迁移人力资源、日常办公

This commit is contained in:
lewis 2025-02-27 17:51:58 +08:00
parent 6b60ac2cf9
commit 764e8f48bf
171 changed files with 16336 additions and 1 deletions

View File

@ -6,6 +6,6 @@ VITE_NOW_TYPE = 'dist'
# VITE_APP_BASE_URL='http://192.168.1.10:8546'
# VITE_APP_BASE_URL='https://test-multi-store.lihaink.cn'
# VITE_APP_BASE_URL='https://multi-store.lihaink.cn'
VITE_APP_BASE_URL='http://192.168.1.22:8544'
VITE_APP_BASE_URL='http://127.0.0.1:8544'
# VITE_APP_BASE_URL='https://ceshi-multi-store.lihaink.cn'

69
src/api/article.ts Normal file
View File

@ -0,0 +1,69 @@
import request from '@/utils/request'
// 文章分类列表
export function articleCateLists(params ?: any) {
return request.get({ url: '/article/articleCate/lists', params }, { urlPrefix: 'oa' })
}
// 文章分类列表
export function articleCateAll(params ?: any) {
return request.get({ url: '/article/articleCate/all', params }, { urlPrefix: 'oa' })
}
// 添加文章分类
export function articleCateAdd(params : any) {
return request.post({ url: '/article/articleCate/add', params }, { urlPrefix: 'oa' })
}
// 编辑文章分类
export function articleCateEdit(params : any) {
return request.post({ url: '/article/articleCate/edit', params }, { urlPrefix: 'oa' })
}
// 删除文章分类
export function articleCateDelete(params : any) {
return request.post({ url: '/article/articleCate/delete', params }, { urlPrefix: 'oa' })
}
// 文章分类详情
export function articleCateDetail(params : any) {
return request.get({ url: '/article/articleCate/detail', params }, { urlPrefix: 'oa' })
}
// 文章分类状态
export function articleCateStatus(params : any) {
return request.post({ url: '/article/articleCate/updateStatus', params }, { urlPrefix: 'oa' })
}
// 文章列表
export function articleLists(params ?: any) {
return request.get({ url: '/article/article/lists', params }, { urlPrefix: 'oa' })
}
// 文章列表
export function articleAll(params ?: any) {
return request.get({ url: '/article/all', params }, { urlPrefix: 'oa' })
}
// 添加文章
export function articleAdd(params : any) {
return request.post({ url: '/article/article/add', params }, { urlPrefix: 'oa' })
}
// 编辑文章
export function articleEdit(params : any) {
return request.post({ url: '/article/article/edit', params }, { urlPrefix: 'oa' })
}
// 删除文章
export function articleDelete(params : any) {
return request.post({ url: '/article/article/delete', params }, { urlPrefix: 'oa' })
}
// 文章详情
export function articleDetail(params : any) {
return request.get({ url: '/article/article/detail', params }, { urlPrefix: 'oa' })
}
// 文章分类状态
export function articleStatus(params : any) {
return request.post({ url: '/article/article/updateStatus', params }, { urlPrefix: 'oa' })
}

View File

@ -0,0 +1,32 @@
import request from "@/utils/request";
// 人事调动部门记录表列表
export function apiOaDepartmentChangeLists(params : any) {
return request.get({ url: "/works/hr/oaDepartmentChange/lists", params }, { urlPrefix: 'oa' });
}
// 添加人事调动部门记录表
export function apiOaDepartmentChangeAdd(params : any) {
return request.post({ url: "/works/hr/oaDepartmentChange/add", params }, { urlPrefix: 'oa' });
}
// 编辑人事调动部门记录表
export function apiOaDepartmentChangeEdit(params : any) {
return request.post({ url: "/works/hr/oaDepartmentChange/edit", params }, { urlPrefix: 'oa' });
}
// 删除人事调动部门记录表
export function apiOaDepartmentChangeDelete(params : any) {
return request.post({
url: "/works/hr/oaDepartmentChange/delete",
params,
}, { urlPrefix: 'oa' });
}
// 人事调动部门记录表详情
export function apiOaDepartmentChangeDetail(params : any) {
return request.get({
url: "/works/hr/oaDepartmentChange/detail",
params,
}, { urlPrefix: 'oa' });
}

View File

@ -0,0 +1,26 @@
import request from "@/utils/request";
// 人事离职记录表列表
export function apiOaPersonalQuitLists(params : any) {
return request.get({ url: "/works/hr/oaPersonalQuit/lists", params }, { urlPrefix: 'oa' });
}
// 添加人事离职记录表
export function apiOaPersonalQuitAdd(params : any) {
return request.post({ url: "/works/hr/oaPersonalQuit/add", params }, { urlPrefix: 'oa' });
}
// 编辑人事离职记录表
export function apiOaPersonalQuitEdit(params : any) {
return request.post({ url: "/works/hr/oaPersonalQuit/edit", params }, { urlPrefix: 'oa' });
}
// 删除人事离职记录表
export function apiOaPersonalQuitDelete(params : any) {
return request.post({ url: "/works/hr/oaPersonalQuit/delete", params }, { urlPrefix: 'oa' });
}
// 人事离职记录表详情
export function apiOaPersonalQuitDetail(params : any) {
return request.get({ url: "/works/hr/oaPersonalQuit/detail", params }, { urlPrefix: 'oa' });
}

26
src/api/oa_plan.ts Normal file
View File

@ -0,0 +1,26 @@
import request from "@/utils/request";
// 日程安排列表
export function apiOaPlanLists(params : any) {
return request.get({ url: "/works/rcbg/oaPlan/lists", params }, { urlPrefix: 'oa' });
}
// 添加日程安排
export function apiOaPlanAdd(params : any) {
return request.post({ url: "/works/rcbg/oaPlan/add", params }, { urlPrefix: 'oa' });
}
// 编辑日程安排
export function apiOaPlanEdit(params : any) {
return request.post({ url: "/works/rcbg/oaPlan/edit", params }, { urlPrefix: 'oa' });
}
// 删除日程安排
export function apiOaPlanDelete(params : any) {
return request.post({ url: "/works/rcbg/oaPlan/delete", params }, { urlPrefix: 'oa' });
}
// 日程安排详情
export function apiOaPlanDetail(params : any) {
return request.get({ url: "/works/rcbg/oaPlan/detail", params }, { urlPrefix: 'oa' });
}

26
src/api/oa_schedule.ts Normal file
View File

@ -0,0 +1,26 @@
import request from "@/utils/request";
// 工作记录列表
export function apiOaScheduleLists(params : any) {
return request.get({ url: "/works/rcbg/oaSchedule/lists", params }, { urlPrefix: 'oa' });
}
// 添加工作记录
export function apiOaScheduleAdd(params : any) {
return request.post({ url: "/works/rcbg/oaSchedule/add", params }, { urlPrefix: 'oa' });
}
// 编辑工作记录
export function apiOaScheduleEdit(params : any) {
return request.post({ url: "/works/rcbg/oaSchedule/edit", params }, { urlPrefix: 'oa' });
}
// 删除工作记录
export function apiOaScheduleDelete(params : any) {
return request.post({ url: "/works/rcbg/oaSchedule/delete", params }, { urlPrefix: 'oa' });
}
// 工作记录详情
export function apiOaScheduleDetail(params : any) {
return request.get({ url: "/works/rcbg/oaSchedule/detail", params }, { urlPrefix: 'oa' });
}

63
src/api/oa_work.ts Normal file
View File

@ -0,0 +1,63 @@
import request from "@/utils/request";
// 汇报工作表列表
export function apiOaWorkLists(params : any) {
return request.get({ url: "/works/rcbg/oaWork/lists", params }, { urlPrefix: 'oa' });
}
// 添加汇报工作表
export function apiOaWorkAdd(params : any) {
return request.post({ url: "/works/rcbg/oaWork/add", params }, { urlPrefix: 'oa' });
}
// 编辑汇报工作表
export function apiOaWorkEdit(params : any) {
return request.post({ url: "/works/rcbg/oaWork/edit", params }, { urlPrefix: 'oa' });
}
// 删除汇报工作表
export function apiOaWorkDelete(params : any) {
return request.post({ url: "/works/rcbg/oaWork/delete", params }, { urlPrefix: 'oa' });
}
// 汇报工作表详情
export function apiOaWorkDetail(params : any) {
return request.get({ url: "/works/rcbg/oaWork/detail", params }, { urlPrefix: 'oa' });
}
// 汇报工作表列表
export function apiOaWorkrecordLists(params : any) {
return request.get({ url: "/works/rcbg/oaWorkRecord/lists", params }, { urlPrefix: 'oa' });
}
// 汇报工作表详情
export function apiOaWorkrecordDetail(params : any) {
return request.get({ url: "/works/rcbg/oaWorkRecord/detail", params }, { urlPrefix: 'oa' });
}
// 删除汇报工作表
export function apiOaWorkrecordDelete(params : any) {
return request.post({ url: "/works/rcbg/oaWorkRecord/delete", params }, { urlPrefix: 'oa' });
}
// 汇报工作表列表
export function apiOaWorkrcommentLists(params : any) {
return request.get({
url: "/works/rcbg/oaWorkComment/lists",
params,
}, { urlPrefix: 'oa' });
}
// 汇报工作表列表
export function apiOaWorkrcommentAdd(params : any) {
return request.post({
url: "/works/rcbg/oaWorkComment/add",
params,
}, { urlPrefix: 'oa' });
}
// 汇报工作表列表
export function apiOaWorkrcommentDelete(params : any) {
return request.post({
url: "/works/rcbg/oaWorkComment/delete",
params,
}, { urlPrefix: 'oa' });
}

View File

@ -0,0 +1,32 @@
import request from '@/utils/request'
// 组织列表
export function orgsLists(params?: any) {
return request.get({ url: '/dept.orgs/lists', params })
}
// 添加组织
export function orgsAdd(params: any) {
return request.post({ url: '/dept.orgs/add', params })
}
// 编辑组织
export function orgsEdit(params: any) {
return request.post({ url: '/dept.orgs/edit', params })
}
// 删除组织
export function orgsDelete(params: any) {
return request.post({ url: '/dept.orgs/delete', params })
}
// 组织详情
export function orgsDetail(params: any) {
return request.get({ url: '/dept.orgs/detail', params })
}
// 所有组织
export function getAll() {
return request.get({ url: '/dept.orgs/getAll'})
}

View File

@ -0,0 +1,16 @@
<template>
<el-link type="primary" v-for="(item, index) in annex" :key="index" :href="item.uri" target="_blank" class="mr-5">{{
item.name
}}</el-link>
<span v-if="!annex.length">暂无附件</span>
</template>
<script lang="ts" setup>
import { defineProps } from 'vue'
defineProps({
annex: Array
})
</script>

View File

@ -0,0 +1,93 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="550px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
<el-form-item label="栏目名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入栏目名称" clearable />
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>
<el-form-item label="状态" prop="is_show">
<el-switch v-model="formData.is_show" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { articleCateEdit, articleCateAdd, articleCateDetail } from '@/api/article'
import Popup from '@/components/popup/index.vue'
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const mode = ref('add')
const popupTitle = computed(() => {
return mode.value == 'edit' ? '编辑栏目' : '新增栏目'
})
const formData = reactive({
id: '',
name: '',
sort: 0,
is_show: 1
})
const formRules = {
name: [
{
required: true,
message: '请输入栏目名称',
trigger: ['blur']
}
]
}
const handleSubmit = async () => {
await formRef.value?.validate()
mode.value == 'edit' ? await articleCateEdit(formData) : await articleCateAdd(formData)
popupRef.value?.close()
emit('success')
}
const open = (type = 'add') => {
mode.value = type
popupRef.value?.open()
}
const setFormData = (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key]
}
}
}
const getDetail = async (row: Record<string, any>) => {
const data = await articleCateDetail({
id: row.id
})
setFormData(data)
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
getDetail
})
</script>

View File

@ -0,0 +1,108 @@
<template>
<div>
<el-card class="!border-none" shadow="never">
<el-alert
type="warning"
title="温馨提示:用于管理网站的分类,只可添加到一级"
:closable="false"
show-icon
/>
</el-card>
<el-card class="!border-none mt-4" shadow="never" v-loading="pager.loading">
<div>
<el-button
class="mb-4"
v-perms="['article.articleCate/add']"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table size="large" :data="pager.lists">
<el-table-column label="栏目名称" prop="name" min-width="120" />
<el-table-column label="文章数" prop="article_count" min-width="120" />
<el-table-column label="状态" min-width="120">
<template #default="{ row }">
<el-switch
v-perms="['article.articleCate/updateStatus']"
v-model="row.is_show"
:active-value="1"
:inactive-value="0"
@change="changeStatus($event, row.id)"
/>
</template>
</el-table-column>
<el-table-column label="排序" prop="sort" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['article.articleCate/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['article.articleCate/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup name="articleColumn">
import { articleCateDelete, articleCateLists, articleCateStatus } from '@/api/article'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const { pager, getLists } = usePaging({
fetchFun: articleCateLists
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.getDetail(data)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await articleCateDelete({ id })
getLists()
}
const changeStatus = async (is_show: any, id: number) => {
try {
await articleCateStatus({ id, is_show })
getLists()
} catch (error) {
getLists()
}
}
getLists()
</script>

View File

@ -0,0 +1,65 @@
<template>
<div class="detail-popup">
<popup ref="popupRef" title="文章详情" :async="true" width="60vw" @confirm="handleSubmit" @close="handleClose">
<h1 style="font-size:32px; margin-bottom: 20px;font-weight:700"> {{ formData.title }} </h1>
<h4 style="margin:20px 0"> {{ formData.desc }} </h4>
<el-image :src="formData.image" />
<div v-html="formData.content"> </div>
<div style="text-align: right;margin-top: 20px">
本文由{{ formData.author }}{{ (formData.create_time) }}发布
</div>
<!-- {{ formData }} -->
</popup>
</div>
</template>
<script lang="ts" setup name="customdetail">
import type { FormInstance } from 'element-plus'
import Popup from '@/components/popup/index.vue'
import { timeFormat } from '@/utils/util'
import type { PropType } from 'vue'
const emit = defineEmits(['success', 'close'])
const popupRef = shallowRef<InstanceType<typeof Popup>>()
//
const formData = ref({
})
//
const handleSubmit = async () => {
popupRef.value?.close()
}
//
const open = (data) => {
popupRef.value?.open()
formData.value = data
}
//
const handleClose = () => {
emit('close')
}
defineExpose({
open,
})
</script>
<style lang="scss" scoped>
.tit {
font-size: 1.2em;
margin-bottom: 10px;
}
:deep(.my-label) {
width: 150px;
}
</style>

View File

@ -0,0 +1,173 @@
<template>
<div class="article-edit">
<el-card class="!border-none" shadow="never">
<el-page-header :content="$route.meta.title" @back="$router.back()" />
</el-card>
<el-card class="mt-4 !border-none" shadow="never">
<el-form
ref="formRef"
class="ls-form"
:model="formData"
label-width="85px"
:rules="rules"
>
<div class="xl:flex">
<div>
<el-form-item label="文章标题" prop="title">
<div class="w-80">
<el-input
v-model="formData.title"
placeholder="请输入文章标题"
type="textarea"
:autosize="{ minRows: 3, maxRows: 3 }"
maxlength="64"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="文章栏目" prop="cid">
<el-select
class="w-80"
v-model="formData.cid"
placeholder="请选择文章栏目"
clearable
>
<el-option
v-for="item in optionsData.article_cate"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="文章简介" prop="desc">
<div class="w-80">
<el-input
v-model="formData.desc"
placeholder="请输入文章简介"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
:maxlength="200"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="摘要" prop="abstract">
<div class="w-80">
<el-input
type="textarea"
:autosize="{ minRows: 6, maxRows: 6 }"
v-model="formData.abstract"
maxlength="200"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="文章封面" prop="image">
<div>
<div>
<material-picker v-model="formData.image" :limit="1" />
</div>
<div class="form-tips">建议尺寸240*180px</div>
</div>
</el-form-item>
<el-form-item label="作者" prop="author">
<div class="w-80">
<el-input v-model="formData.author" placeholder="请输入作者名称" />
</div>
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>
<el-form-item label="初始浏览量" prop="click_virtual">
<div>
<el-input-number v-model="formData.click_virtual" :min="0" />
</div>
</el-form-item>
<el-form-item label="文章状态" required prop="is_show">
<el-radio-group v-model="formData.is_show">
<el-radio :label="1">显示</el-radio>
<el-radio :label="0">隐藏</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="xl:ml-20">
<el-form-item label="文章内容" prop="content">
<editor v-model="formData.content" :height="667" :width="375" />
</el-form-item>
</div>
</div>
</el-form>
</el-card>
<footer-btns>
<el-button type="primary" @click="handleSave">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="articleListsEdit">
import type { FormInstance } from 'element-plus'
import { useDictOptions } from '@/hooks/useDictOptions'
import { articleDetail, articleEdit, articleAdd, articleCateAll } from '@/api/article'
import useMultipleTabs from '@/hooks/useMultipleTabs'
const route = useRoute()
const router = useRouter()
const formData = reactive({
id: '',
title: '',
image: '',
cid: '',
desc: '',
author: '',
content: '',
click_virtual: 0,
sort: 0,
is_show: 1,
abstract: ''
})
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const rules = reactive({
title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
cid: [{ required: true, message: '请选择文章栏目', trigger: 'blur' }]
})
const getDetails = async () => {
const data = await articleDetail({
id: route.query.id
})
Object.keys(formData).forEach((key) => {
//@ts-ignore
formData[key] = data[key]
})
}
const { optionsData } = useDictOptions<{
article_cate: any[]
}>({
article_cate: {
api: articleCateAll
}
})
const handleSave = async () => {
await formRef.value?.validate()
if (route.query.id) {
await articleEdit(formData)
} else {
await articleAdd(formData)
}
removeTab()
router.back()
}
route.query.id && getDetails()
</script>

View File

@ -0,0 +1,154 @@
<template>
<div class="article-lists">
<el-card class="!border-none" shadow="never">
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="文章标题">
<el-input class="w-[280px]" v-model="queryParams.title" clearable @keyup.enter="resetPage" />
</el-form-item>
<el-form-item label="栏目名称">
<el-select class="w-[280px]" v-model="queryParams.cid">
<el-option label="全部" value />
<el-option v-for="item in optionsData.article_cate" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="文章状态">
<el-select class="w-[280px]" v-model="queryParams.is_show">
<el-option label="全部" value />
<el-option label="显示" :value="1" />
<el-option label="隐藏" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div>
<router-link v-perms="['article.article/add', 'article.article/add:edit']" :to="{
path: getRoutePath('article.article/add:edit')
}">
<el-button type="primary" class="mb-4">
<template #icon>
<icon name="el-icon-Plus" />
</template>
发布文章
</el-button>
</router-link>
</div>
<el-table size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="ID" prop="id" min-width="80" />
<el-table-column label="封面" min-width="100">
<template #default="{ row }">
<image-contain v-if="row.image" :src="row.image" :width="60" :height="45"
:preview-src-list="[row.image]" preview-teleported fit="contain" />
</template>
</el-table-column>
<el-table-column label="标题" prop="title" min-width="160" show-tooltip-when-overflow />
<el-table-column label="栏目" prop="cate_name" min-width="100" />
<el-table-column label="作者" prop="author" min-width="120" />
<el-table-column label="浏览量" prop="click" min-width="100" />
<el-table-column label="状态" min-width="100">
<template #default="{ row }">
<el-switch v-perms="['article.article/updateStatus']" v-model="row.is_show" :active-value="1"
:inactive-value="0" @change="changeStatus($event, row.id)" />
</template>
</el-table-column>
<el-table-column label="排序" prop="sort" min-width="100" />
<el-table-column label="发布时间" prop="create_time" min-width="120" />
<el-table-column label="操作" width="170" fixed="right">
<template #default="{ row }">
<el-button v-perms="['article.article/edit', 'article.article/add:edit']" type="primary" link>
<router-link :to="{
path: getRoutePath('article.article/add:edit'),
query: {
id: row.id
}
}">
编辑
</router-link>
</el-button>
<el-button v-perms="['article.article/delete']" type="danger" link @click="handleDelete(row.id)">
删除
</el-button>
<el-button v-perms="['article.article/detail']" link @click="handleDetail(row.id)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<detail-popup v-if="showDtail" ref="detailRef" @close="showDtail = false" />
</div>
</template>
<script lang="ts" setup name="articleLists">
import { articleLists, articleDelete, articleStatus, articleCateAll, articleDetail } from '@/api/article'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import feedback from '@/utils/feedback'
import DetailPopup from './detail.vue'
const queryParams = reactive({
title: '',
cid: '',
is_show: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: articleLists,
params: queryParams
})
const { optionsData } = useDictOptions<{
article_cate: any[]
}>({
article_cate: {
api: articleCateAll
}
})
const changeStatus = async (is_show: any, id: number) => {
try {
await articleStatus({ id, is_show })
getLists()
} catch (error) {
getLists()
}
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await articleDelete({ id })
getLists()
}
const detailRef = shallowRef<InstanceType<typeof DetailPopup>>()
const showDtail = ref(false)
const handleDetail = async (id: number) => {
let res = await articleDetail({ id })
showDtail.value = true
await nextTick()
detailRef.value?.open(res)
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@ -0,0 +1,88 @@
<template>
<div>
<div>
<draggable class="draggable" v-model="navLists" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap class="max-w-[400px]" :key="index" @close="handleDelete(index)">
<div class="bg-fill-light flex items-center w-full p-4 mb-4 cursor-move">
<material-picker
v-model="item.image"
upload-class="bg-body"
size="60px"
exclude-domain
>
<template #upload>
<div class="upload-btn w-[60px] h-[60px]">
<icon name="el-icon-Plus" :size="20" />
</div>
</template>
</material-picker>
<div class="ml-3 flex-1">
<div class="flex">
<span class="text-tx-regular flex-none mr-3">名称</span>
<el-input v-model="item.name" placeholder="请输入名称" />
</div>
<div class="flex mt-[18px]">
<span class="text-tx-regular flex-none mr-3">链接</span>
<link-picker v-model="item.link" />
</div>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
<div>
<el-button type="primary" @click="handleAdd">添加</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import Draggable from 'vuedraggable'
const props = defineProps({
modelValue: {
type: Array as PropType<any[]>,
default: () => []
},
max: {
type: Number,
default: 10
},
min: {
type: Number,
default: 1
}
})
const emit = defineEmits(['update:modelValue'])
const navLists = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
const handleAdd = () => {
if (props.modelValue?.length < props.max) {
navLists.value.push({
image: '',
name: '导航名称',
link: {}
})
} else {
feedback.msgError(`最多添加${props.max}`)
}
}
const handleDelete = (index: number) => {
if (props.modelValue?.length <= props.min) {
return feedback.msgError(`最少保留${props.min}`)
}
navLists.value.splice(index, 1)
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,59 @@
<template>
<el-image :style="styles" v-bind="props" :src="getImageUrl(src)">
<template #placeholder>
<div class="image-slot"></div>
</template>
<template #error>
<div class="image-slot">
<icon name="el-icon-Picture" :size="30" />
</div>
</template>
</el-image>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import type { CSSProperties } from 'vue'
import { addUnit } from '@/utils/util'
import { imageProps } from 'element-plus'
import useAppStore from '@/stores/modules/app'
const props = defineProps({
width: {
type: [String, Number],
default: 'auto'
},
height: {
type: [String, Number],
default: 'auto'
},
radius: {
type: [String, Number],
default: 0
},
...imageProps
})
const { getImageUrl } = useAppStore()
const styles = computed<CSSProperties>(() => {
return {
width: addUnit(props.width),
height: addUnit(props.height),
borderRadius: addUnit(props.radius)
}
})
</script>
<style lang="scss" scoped>
.el-image {
display: block;
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #fafafa;
color: #909399;
}
}
</style>

View File

@ -0,0 +1,33 @@
<template>
<div class="pages-setting">
<div
class="title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"
>
{{ widget?.title }}
</div>
<keep-alive>
<component
class="pt-5 pr-4"
:is="widgets[widget?.name]?.attr"
:content="widget?.content"
:styles="widget?.styles"
:type="type"
/>
</keep-alive>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import widgets from '../widgets'
const props = defineProps({
widget: {
type: Object as PropType<Record<string, any>>,
default: () => ({})
},
type: {
type: String as PropType<'mobile' | 'pc'>,
default: 'mobile'
}
})
</script>

View File

@ -0,0 +1,44 @@
<template>
<el-menu
:default-active="modelValue"
class="w-[160px] min-h-[668px] pages-menu"
@select="handleSelect"
>
<el-menu-item v-for="(item, key) in menus" :index="key" :key="item.id">
<span>{{ item.name }}</span>
</el-menu-item>
</el-menu>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
defineProps({
menus: {
type: Object as PropType<Record<string, any>>,
default: () => ({})
},
modelValue: {
type: String,
default: '1'
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: string): void
}>()
const handleSelect = (index: string) => {
emit('update:modelValue', index)
}
</script>
<style lang="scss" scoped>
.pages-menu {
:deep(.el-menu-item) {
border-color: transparent;
&.is-active {
border-right-width: 2px;
border-color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9);
}
}
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div class="pages-preview">
<div
v-for="(widget, index) in pageData"
:key="widget.id"
class="relative"
:class="{
'cursor-pointer': !widget?.disabled
}"
@click="handleClick(widget, index)"
>
<div
class="absolute w-full h-full z-[100] border-dashed"
:class="{
select: index == modelValue,
'border-[#dcdfe6] border-2': !widget?.disabled
}"
:style="widget.styles"
></div>
<slot>
<component
:is="widgets[widget?.name]?.content"
:content="widget.content"
:styles="widget.styles"
:key="widget.id"
/>
</slot>
</div>
</div>
</template>
<script lang="ts" setup>
import widgets from '../widgets'
import type { PropType } from 'vue'
defineProps({
pageData: {
type: Array as PropType<any[]>,
default: () => []
},
modelValue: {
type: Number,
default: 0
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: number): void
}>()
const handleClick = (widget: any, index: number) => {
if (widget.disabled) return
emit('update:modelValue', index)
}
</script>
<style lang="scss" scoped>
.pages-preview {
width: 460px;
height: 360px;
background: url(../../image/pc_index.png);
background-size: 100% 100%;
background-repeat: no-repeat;
.select {
@apply border-primary border-solid;
}
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div class="shadow mx-[30px] pages-preview">
<el-scrollbar>
<div
v-for="(widget, index) in pageData"
:key="widget.id"
class="relative"
:class="{
'cursor-pointer': !widget?.disabled
}"
@click="handleClick(widget, index)"
>
<div
class="absolute w-full h-full z-[100] border-dashed"
:class="{
select: index == modelValue,
'border-[#dcdfe6] border-2': !widget?.disabled
}"
></div>
<slot>
<component
:is="widgets[widget?.name]?.content"
:content="widget.content"
:styles="widget.styles"
:key="widget.id"
/>
</slot>
</div>
</el-scrollbar>
</div>
</template>
<script lang="ts" setup>
import widgets from '../widgets'
import type { PropType } from 'vue'
defineProps({
pageData: {
type: Array as PropType<any[]>,
default: () => []
},
modelValue: {
type: Number,
default: 0
}
})
const emit = defineEmits<{
(event: 'update:modelValue', value: number): void
}>()
const handleClick = (widget: any, index: number) => {
if (widget.disabled) return
emit('update:modelValue', index)
}
</script>
<style lang="scss" scoped>
.pages-preview {
background-color: #f8f8f8;
width: 360px;
height: 615px;
color: #333;
.select {
@apply border-primary border-solid;
}
}
</style>

View File

@ -0,0 +1,100 @@
<template>
<div>
<el-form label-width="70px">
<el-form-item label="是否启用" v-if="type == 'mobile'">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*340px</div>
<draggable class="draggable" v-model="content.data" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div
class="bg-fill-light flex items-center w-full p-4 mt-4 cursor-move"
>
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input
v-model="item.name"
placeholder="请输入名称"
/>
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker
v-if="type == 'mobile'"
v-model="item.link"
/>
<el-input
v-if="type == 'pc'"
placeholder="请输入链接"
v-model="item.link.path"
/>
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
<el-button type="primary" @click="handleAdd">添加图片</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import type options from './options'
import Draggable from 'vuedraggable'
const limit = 5
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
},
type: {
type: String as PropType<'mobile' | 'pc'>,
default: 'mobile'
}
})
const handleAdd = () => {
if (props.content.data?.length < limit) {
props.content.data.push({
image: '',
name: '',
link: {}
})
} else {
feedback.msgError(`最多添加${limit}张图片`)
}
}
const handleDelete = (index: number) => {
if (props.content.data?.length <= 1) {
return feedback.msgError('最少保留一张图片')
}
props.content.data.splice(index, 1)
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,42 @@
<template>
<div class="banner" :style="styles">
<div class="banner-image w-full h-full">
<decoration-img
width="100%"
:height="styles.height || height"
:src="getImage"
fit="contain"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import DecorationImg from '../../decoration-img.vue'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
},
height: {
type: String,
default: '170px'
}
})
const getImage = computed(() => {
const { data } = props.content
if (Array.isArray(data)) {
return data[0] ? data[0].image : ''
}
return ''
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,15 @@
export default () => ({
title: '首页轮播图',
name: 'banner',
content: {
enabled: 1,
data: [
{
image: '',
name: '',
link: {}
}
]
},
styles: {}
})

View File

@ -0,0 +1,38 @@
<template>
<div>
<el-form label-width="90px">
<el-form-item label="客服标题">
<el-input class="w-[400px]" v-model="content.title" />
</el-form-item>
<el-form-item label="服务时间">
<el-input class="w-[400px]" v-model="content.time" />
</el-form-item>
<el-form-item label="联系电话">
<el-input class="w-[400px]" v-model="content.mobile" />
</el-form-item>
<el-form-item label="客服二维码">
<div>
<material-picker v-model="content.qrcode" exclude-domain />
<div class="form-tips">建议图片尺寸200*200像素图片格式jpgpngjpeg</div>
</div>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,39 @@
<template>
<div class="customer-service">
<decoration-img width="140px" height="140px" :src="content.qrcode" alt="" />
<div class="text-[15px] mt-[7px] font-medium">{{ content.title }}</div>
<div class="text-[#666] mt-[20px]">服务时间{{ content.time }}</div>
<div class="text-[#666] mt-[7px]">客服电话{{ content.mobile }}</div>
<div
class="text-white text-[16px] rounded-[42px] bg-[#4173FF] w-full h-[42px] flex justify-center items-center mt-[50px]"
>
保存二维码图片
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import DecorationImg from '../../decoration-img.vue'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped>
.customer-service {
margin: 10px 18px;
border-radius: 10px;
padding: 50px 55px 80px;
background: #fff;
@apply flex flex-col justify-center items-center;
}
</style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,11 @@
export default () => ({
title: '客服设置',
name: 'customer-service',
content: {
title: '添加客服二维码',
time: '',
mobile: '',
qrcode: ''
},
styles: {}
})

View File

@ -0,0 +1,13 @@
const widgets: Record<string, any> = import.meta.glob('./**/index.ts', { eager: true })
interface Widget {
attr: any
content: any
options: any
}
const exportWidgets: Record<string, Widget> = {}
Object.keys(widgets).forEach((key) => {
const widgetName = key.replace(/^\.\/([\w-]+).*/gi, '$1')
exportWidgets[widgetName] = widgets[key]?.default
})
export default exportWidgets

View File

@ -0,0 +1,38 @@
<template>
<div>
<el-form label-width="70px">
<el-form-item label="排版样式">
<el-radio-group v-model="content.style">
<el-radio :label="1">横排</el-radio>
<el-radio :label="2">竖排</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="标题名称">
<el-input class="w-[400px]" v-model="content.title" />
</el-form-item>
<el-form-item label="菜单设置">
<div class="flex-1">
<AddNav v-model="content.data" />
</div>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import AddNav from '../../add-nav.vue'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,59 @@
<template>
<div class="my-service">
<div v-if="content.title" class="title px-[15px] py-[10px]">
<div>{{ content.title }}</div>
</div>
<div v-if="content.style == 1" class="flex flex-wrap pt-[20px] pb-[10px]">
<div
v-for="(item, index) in content.data"
:key="index"
class="flex flex-col items-center w-1/4 mb-[15px]"
>
<decoration-img width="26px" height="26px" :src="item.image" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
</div>
</div>
<div v-if="content.style == 2">
<div
v-for="(item, index) in content.data"
:key="index"
class="flex items-center border-b border-[#e5e5e5] h-[50px] px-[12px]"
>
<decoration-img width="24px" height="24px" :src="item.image" alt="" />
<div class="ml-[10px] flex-1">{{ item.name }}</div>
<div>
<icon name="el-icon-ArrowRight" />
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import DecorationImg from '../../decoration-img.vue'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped>
.my-service {
margin: 10px 10px 0;
background-color: #fff;
border-radius: 7px;
.title {
border-bottom: 1px solid #e5e5e5;
font-size: 16px;
font-weight: 500;
}
}
</style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,16 @@
export default () => ({
title: '我的服务',
name: 'my-service',
content: {
style: 1,
title: '我的服务',
data: [
{
image: '',
name: '导航名称',
link: {}
}
]
},
styles: {}
})

View File

@ -0,0 +1,36 @@
<template>
<div>
<el-form label-width="70px">
<el-form-item label="是否启用">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单设置">
<div class="flex-1">
<div class="form-tips mb-4">最多可添加10个建议图片尺寸100px*100px</div>
<AddNav v-model="content.data" />
</div>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import AddNav from '../../add-nav.vue'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,32 @@
<template>
<div class="nav bg-white pt-[15px] pb-[8px]">
<div class="flex flex-wrap">
<div
v-for="(item, index) in content.data"
:key="index"
class="flex flex-col items-center w-1/5 mb-[15px]"
>
<decoration-img width="41px" height="41px" :src="item.image" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import DecorationImg from '../../decoration-img.vue'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,15 @@
export default () => ({
title: '导航菜单',
name: 'nav',
content: {
enabled: 1,
data: [
{
image: '',
name: '导航名称',
link: {}
}
]
},
styles: {}
})

View File

@ -0,0 +1,20 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,70 @@
<template>
<div class="news">
<div class="flex items-center news-title mx-[10px] my-[15px] text-[17px] font-medium">
最新资讯
</div>
<div
v-for="item in newsList"
:key="item.id"
class="news-card flex bg-white px-[10px] py-[16px] text-[#333] border-[#f2f2f2] border-b"
>
<div class="mr-[10px]" v-if="item.image">
<img :src="item.image" class="w-[120px] h-[90px] object-contain" />
</div>
<div class="flex flex-col justify-between flex-1">
<div class="text-[15px] font-medium line-clamp-2">{{ item.title }}</div>
<div class="line-clamp-1 text-sm mt-[8px]">
{{ item.desc }}
</div>
<div class="text-[#999] text-xs w-full flex justify-between mt-[8px]">
<div>{{ item.create_time }}</div>
<div class="flex items-center">
<icon name="el-icon-View" />
<div class="ml-[5px]">{{ item.click }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import { getDecorateArticle } from '@/api/decoration'
import type options from './options'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
const newsList = ref<any[]>([])
const getData = async () => {
const data = await getDecorateArticle({
limit: 10
})
newsList.value = data
}
getData()
</script>
<style lang="scss" scoped>
.news {
.news-title {
&::before {
content: '';
width: 4px;
height: 17px;
display: block;
margin-right: 5px;
background: #4173ff;
}
}
}
</style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,7 @@
export default () => ({
title: '资讯',
name: 'news',
disabled: 1,
content: {},
styles: {}
})

View File

@ -0,0 +1,20 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,23 @@
<template>
<div class="search">
<div class="search-con flex items-center px-[15px]">
<icon name="el-icon-Search" :size="17" />
<span class="ml-[5px]">请输入关键词搜索</span>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.search {
background-color: #fff;
padding: 7px 12px;
.search-con {
height: 100%;
height: 36px;
border-radius: 36px;
background: #f4f4f4;
color: #999999;
}
}
</style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,7 @@
export default () => ({
title: '搜索',
name: 'search',
disabled: 1,
content: {},
styles: {}
})

View File

@ -0,0 +1,88 @@
<template>
<div>
<el-form label-width="70px">
<el-form-item label="是否启用">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*200px</div>
<draggable class="draggable" v-model="content.data" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div
class="bg-fill-light flex items-center w-full p-4 mt-4 cursor-move"
>
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input
v-model="item.name"
placeholder="请输入名称"
/>
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
<el-button type="primary" @click="handleAdd">添加图片</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import type options from './options'
import Draggable from 'vuedraggable'
const limit = 5
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
const handleAdd = () => {
if (props.content.data?.length < limit) {
props.content.data.push({
image: '',
name: '',
link: {}
})
} else {
feedback.msgError(`最多添加${limit}张图片`)
}
}
const handleDelete = (index: number) => {
if (props.content.data?.length <= 1) {
return feedback.msgError('最少保留一张图片')
}
props.content.data.splice(index, 1)
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,32 @@
<template>
<div class="banner mx-[10px] mt-[10px]">
<div class="banner-image">
<decoration-img width="100%" height="100px" :src="getImage" fit="contain" />
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
import DecorationImg from '../../decoration-img.vue'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
const getImage = computed(() => {
const { data } = props.content
if (Array.isArray(data)) {
return data[0] ? data[0].image : ''
}
return ''
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,15 @@
export default () => ({
title: '个人中心广告图',
name: 'user-banner',
content: {
enabled: 1,
data: [
{
image: '',
name: '',
link: {}
}
]
},
styles: {}
})

View File

@ -0,0 +1,20 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({})
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({})
}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,16 @@
<template>
<div class="user-info flex items-center px-[25px]">
<img src="./images/default_avatar.png" class="w-[60px] h-[60px]" alt="" />
<div class="text-white text-[18px] ml-[10px]">未登录</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.user-info {
background: url(./images/my_topbg.png);
height: 115px;
background-position: bottom;
background-size: 100% auto;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View File

@ -0,0 +1,8 @@
import attr from './attr.vue'
import content from './content.vue'
import options from './options'
export default {
attr,
content,
options
}

View File

@ -0,0 +1,7 @@
export default () => ({
title: '用户信息',
name: 'user-info',
disabled: 1,
content: {},
styles: {}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 KiB

View File

@ -0,0 +1,103 @@
<template>
<div class="decoration-pages min-w-[1100px]">
<el-card shadow="never" class="!border-none flex-1 flex" :body-style="{ flex: 1 }">
<div class="flex h-full items-start">
<Menu v-model="activeMenu" :menus="menus" />
<preview v-model="selectWidgetIndex" :pageData="getPageData" />
<attr-setting class="flex-1" :widget="getSelectWidget" />
</div>
</el-card>
<footer-btns class="mt-4" :fixed="false" v-perms="['decorate:pages:save']">
<el-button type="primary" @click="setData">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="decorationPages">
import Menu from '../component/pages/menu.vue'
import Preview from '../component/pages/preview.vue'
import AttrSetting from '../component/pages/attr-setting.vue'
import widgets from '../component/widgets'
import { getDecoratePages, setDecoratePages } from '@/api/decoration'
import { getNonDuplicateID } from '@/utils/util'
enum pagesTypeEnum {
HOME = '1',
USER = '2',
SERVICE = '3'
}
const generatePageData = (widgetNames: string[]) => {
return widgetNames.map((widgetName) => {
const options = {
id: getNonDuplicateID(),
...(widgets[widgetName]?.options() || {})
}
return options
})
}
const menus: Record<
string,
{
id: number
name: string
pageData: any[]
}
> = reactive({
[pagesTypeEnum.HOME]: {
id: 1,
type: 1,
name: '首页装修',
pageData: generatePageData(['search', 'banner', 'nav', 'news'])
},
[pagesTypeEnum.USER]: {
id: 2,
type: 2,
name: '个人中心',
pageData: generatePageData(['user-info', 'my-service', 'user-banner'])
},
[pagesTypeEnum.SERVICE]: {
id: 3,
type: 3,
name: '客服设置',
pageData: generatePageData(['customer-service'])
}
})
const activeMenu = ref('1')
const selectWidgetIndex = ref(-1)
const getPageData = computed(() => {
return menus[activeMenu.value]?.pageData ?? []
})
const getSelectWidget = computed(() => {
return menus[activeMenu.value]?.pageData[selectWidgetIndex.value] ?? ''
})
const getData = async () => {
const data = await getDecoratePages({ id: activeMenu.value })
menus[String(data.id)].pageData = JSON.parse(data.data)
}
const setData = async () => {
await setDecoratePages({
...menus[activeMenu.value],
data: JSON.stringify(menus[activeMenu.value].pageData)
})
getData()
}
watch(
activeMenu,
() => {
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled)
getData()
},
{
immediate: true
}
)
</script>
<style lang="scss" scoped>
.decoration-pages {
min-height: calc(100vh - var(--navbar-height) - 80px);
@apply flex flex-col;
}
</style>

View File

@ -0,0 +1,90 @@
<template>
<div class="decoration-pages min-w-[1100px]">
<el-card shadow="never" class="!border-none flex-1 flex" :body-style="{ flex: 1 }">
<div class="flex h-full items-start">
<Menu v-model="activeMenu" :menus="menus" />
<preview-pc class="mx-4" v-model="selectWidgetIndex" :pageData="getPageData" />
<attr-setting class="flex-1" :widget="getSelectWidget" type="pc" />
</div>
</el-card>
<footer-btns class="mt-4" :fixed="false" v-perms="['decorate:pages:save']">
<el-button type="primary" @click="setData">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="decorationPc">
import Menu from './component/pages/menu.vue'
import PreviewPc from './component/pages/preview-pc.vue'
import AttrSetting from './component/pages/attr-setting.vue'
import widgets from './component/widgets'
import { getDecoratePages, setDecoratePages } from '@/api/decoration'
import { getNonDuplicateID } from '@/utils/util'
enum pagesTypeEnum {
HOME = '4'
}
const generatePageData = (widgetNames: string[]) => {
return widgetNames.map((widgetName) => {
const options = {
id: getNonDuplicateID(),
...(widgets[widgetName]?.options() || {})
}
return options
})
}
const menus: Record<
string,
{
id: number
name: string
pageData: any[]
}
> = reactive({
[pagesTypeEnum.HOME]: {
id: 4,
type: 4,
name: '首页装修',
pageData: []
}
})
const activeMenu = ref('4')
const selectWidgetIndex = ref(0)
const getPageData = computed(() => {
return menus[activeMenu.value]?.pageData ?? []
})
const getSelectWidget = computed(() => {
return menus[activeMenu.value]?.pageData[selectWidgetIndex.value] ?? ''
})
const getData = async () => {
const data = await getDecoratePages({ id: activeMenu.value })
menus[String(data.id)].pageData = JSON.parse(data.data)
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled)
}
const setData = async () => {
await setDecoratePages({
...menus[activeMenu.value],
data: JSON.stringify(menus[activeMenu.value].pageData)
})
getData()
}
watch(
activeMenu,
() => {
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled)
getData()
},
{
immediate: true
}
)
</script>
<style lang="scss" scoped>
.decoration-pages {
min-height: calc(100vh - var(--navbar-height) - 80px);
@apply flex flex-col;
}
</style>

View File

@ -0,0 +1,217 @@
<template>
<div class="decoration-tabbar min-w-[800px]">
<el-card shadow="never" class="!border-none flex-1" :body-style="{ height: '100%' }">
<div class="flex h-full items-start">
<div class="pages-preview mx-[30px]">
<div class="tabbar flex">
<div
class="tabbar-item flex flex-col justify-center items-center flex-1"
v-for="(item, index) in tabbar.list"
:key="index"
:style="{ color: tabbar.style.default_color }"
>
<img class="w-[22px] h-[22px]" :src="item.unselected" alt="" />
<div class="leading-3 text-[12px] mt-[4px]">{{ item.name }}</div>
</div>
</div>
</div>
<div class="flex-1">
<div
class="title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"
>
底部导航设置
<span class="form-tips ml-[10px] !mt-0">
至少添加2个导航最多添加5个导航
</span>
</div>
<el-form class="mt-4" label-width="70px">
<el-tabs model-value="content">
<el-tab-pane label="导航图片" name="content">
<div class="mb-[18px]">
<draggable
class="draggable"
v-model="tabbar.list"
animation="300"
draggable=".draggable"
:move="onMove"
>
<template v-slot:item="{ element, index }">
<del-wrap
@close="handleDelete(index)"
class="max-w-[400px]"
:class="{ draggable: index != 0 }"
>
<div class="bg-fill-light w-full p-4 mt-4">
<el-form-item label="导航图标">
<material-picker
v-model="element.unselected"
upload-class="bg-body"
size="60px"
>
<template #upload>
<div
class="upload-btn w-[60px] h-[60px]"
>
<icon
name="el-icon-Plus"
:size="16"
/>
<span class="text-xs leading-5">
未选中
</span>
</div>
</template>
</material-picker>
<material-picker
v-model="element.selected"
upload-class="bg-body"
size="60px"
>
<template #upload>
<div
class="upload-btn w-[60px] h-[60px]"
>
<icon
name="el-icon-Plus"
:size="16"
/>
<span class="text-xs leading-5">
选中
</span>
</div>
</template>
</material-picker>
</el-form-item>
<el-form-item label="导航名称">
<el-input
v-model="element.name"
placeholder="请输入名称"
/>
</el-form-item>
<el-form-item label="链接地址">
<link-picker v-model="element.link" />
</el-form-item>
</div>
</del-wrap>
</template>
</draggable>
</div>
<el-form-item v-if="tabbar.list?.length < max" label-width="0">
<el-button type="primary" @click="handleAdd">
添加导航
</el-button>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="样式设置" name="styles">
<el-form-item label="默认颜色">
<color-picker
class="max-w-[400px]"
v-model="tabbar.style.default_color"
default-color="#999999"
/>
</el-form-item>
<el-form-item label="选中颜色">
<color-picker
class="max-w-[400px]"
v-model="tabbar.style.selected_color"
default-color="#4173ff"
/>
</el-form-item>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
</div>
</el-card>
<footer-btns class="mt-4" :fixed="false" v-perms="['decorate:tabbar:save']">
<el-button type="primary" @click="setData">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="decorationTabbar">
import { getDecorateTabbar, setDecorateTabbar } from '@/api/decoration'
import feedback from '@/utils/feedback'
import Draggable from 'vuedraggable'
const max = 5
const min = 2
const tabbar = reactive({
style: {
default_color: '',
selected_color: ''
},
list: [
{
name: '',
selected: '',
unselected: '',
link: {}
},
{
name: '',
selected: '',
unselected: '',
link: {}
}
]
})
const handleAdd = () => {
if (tabbar.list?.length < max) {
tabbar.list.push({
name: '',
selected: '',
unselected: '',
link: {}
})
} else {
feedback.msgError(`最多添加${max}`)
}
}
const handleDelete = (index: number) => {
if (tabbar.list?.length <= min) {
return feedback.msgError(`最少保留${min}`)
}
tabbar.list.splice(index, 1)
}
const onMove = (e: any) => {
if (e.relatedContext.index == 0) {
return false
}
return true
}
const getData = async () => {
const data = await getDecorateTabbar()
tabbar.list = data.list
tabbar.style = data.style
}
const setData = async () => {
await setDecorateTabbar(toRaw(tabbar))
getData()
}
getData()
</script>
<style lang="scss" scoped>
.decoration-tabbar {
min-height: calc(100vh - var(--navbar-height) - 80px);
@apply flex flex-col;
.pages-preview {
background-color: #f7f7f7;
width: 360px;
height: 615px;
color: #333;
position: relative;
.tabbar {
position: absolute;
height: 50px;
background-color: #fff;
bottom: 0;
width: 100%;
border: 2px solid var(--el-color-primary);
}
}
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<div>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="id" prop="id" show-overflow-tooltip />
<el-table-column label="申请人" prop="user_name" show-overflow-tooltip />
<el-table-column label="申请时间" prop="create_time" show-overflow-tooltip />
<el-table-column label="审批类型" prop="type_name" show-overflow-tooltip />
<el-table-column label="所属部门" prop="dept_name" show-overflow-tooltip />
<el-table-column label="当前审批人" prop="check_admin_users" show-overflow-tooltip />
<el-table-column label="审批状态" prop="check_status_text" show-overflow-tooltip />
<el-table-column label="备注" prop="remarks" show-overflow-tooltip />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handDetail(row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex mt-4 justify-end">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<detailPopup v-if="showDetail" ref="detailRef" @success="showDetail = false, getLists()"
@close="showDetail = false, getLists()" :typeName="typeName" />
</div>
</template>
<script lang="ts" setup name="oaSealCateLists">
import { usePaging } from '@/hooks/usePaging'
import { useDictData } from '@/hooks/useDictOptions'
import { apiOaoaApproveCopy } from '@/api/oa_Initiate'
import detailPopup from '@/views/oa_Initiate/detail.vue'
import { apiOaoaApproveDetail } from "@/api/oa_Initiate"
const detailRef = ref(null)
//
const showDetail = ref(false)
//
const queryParams = reactive({
title: '',
status: ''
})
const typeName = ref('')
//
const selectData = ref<any[]>([])
//
const handleSelectionChange = (val: any[]) => {
selectData.value = val.map(({ id }) => id)
}
//
const { dictData } = useDictData('')
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: apiOaoaApproveCopy,
params: queryParams
})
const handDetail = async (row: any) => {
typeName.value = row.type_name
let res = await apiOaoaApproveDetail({ id: row.id })
showDetail.value = true
await nextTick()
detailRef.value?.open()
detailRef.value?.setFormData(res)
}
getLists()
</script>

View File

@ -0,0 +1,95 @@
<template>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!flex-1">
<el-option label="全部" :value="0" />
<el-option label="带我审批" :value="1" />
<el-option label="我已审批" :value="2" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="申请人" prop="user_name" show-overflow-tooltip />
<el-table-column label="申请时间" prop="create_time" show-overflow-tooltip />
<el-table-column label="审批类型" prop="type_name" show-overflow-tooltip />
<el-table-column label="所属部门" prop="dept_name" show-overflow-tooltip />
<el-table-column label="当前审批人" prop="check_admin_users" show-overflow-tooltip />
<el-table-column label="审批状态" prop="check_status_text" show-overflow-tooltip />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handDetail(row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex mt-4 justify-end">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<detailPopup v-if="showDetail" ref="detailRef" @success="showDetail = false, getLists()"
@close="showDetail = false, getLists()" :typeName="typeName" />
</div>
</template>
<script lang="ts" setup name="oaSealCateLists">
import { usePaging } from '@/hooks/usePaging'
import { useDictData } from '@/hooks/useDictOptions'
import { apiOaoaApprovelst } from '@/api/oa_Initiate'
import detailPopup from '@/views/oa_Initiate/detail.vue'
import { apiOaoaApproveDetail } from "@/api/oa_Initiate"
const detailRef = ref(null)
//
const showDetail = ref(false)
const typeName = ref('')
//
const queryParams = reactive({
title: '',
status: ''
})
//
const selectData = ref<any[]>([])
//
const handleSelectionChange = (val: any[]) => {
selectData.value = val.map(({ id }) => id)
}
//
const { dictData } = useDictData('')
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: apiOaoaApprovelst,
params: queryParams
})
const handDetail = async (row: any) => {
typeName.value = row.type_name
let res = await apiOaoaApproveDetail({ id: row.id })
showDetail.value = true
await nextTick()
detailRef.value?.open()
detailRef.value?.setFormData(res)
}
getLists()
</script>

View File

@ -0,0 +1,318 @@
<template>
<div class="detail-popup">
<popup ref="popupRef" :showFootBtn="false" title="审批详情" :async="true" width="60vw" @close='hdClose'>
<el-card v-if="isGenerateForm">
<template #header>审批内容</template>
<el-descriptions :column="3" border>
<el-descriptions-item v-for="(item, value) in fromValue" :label="item.label" label-align="left"
align="left">
{{ item.text || item.value }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border v-if='formData.extends?.annex'>
<el-descriptions-item label="附件" label-align="left" align="left">
<annexLink :annex='formData.extends.annex'></annexLink>
</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card v-else>
<template #header>审批内容</template>
<el-descriptions :column="3" border>
<el-descriptions-item v-for="(item, value) in fromValue" :label="item" label-align="left" align="left">
{{ formData.extends[value] }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border v-if='formData.extends?.annex'>
<el-descriptions-item label="附件" label-align="left" align="left">
<annexLink :annex='formData.extends.annex'></annexLink>
</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card>
<template #header>审批流程</template>
<el-descriptions :column="3" border>
<el-descriptions-item label="审批状态" label-align="left" align="left">
{{ formData.check_status_text }}
</el-descriptions-item>
<el-descriptions-item label="当前审核人" label-align="left" align="left">
{{ formData.check_admin_users || "审批结束" }}
</el-descriptions-item>
<el-descriptions-item label="抄送人" label-align="left" align="left">
{{ formData.copy_users }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="审批流程" label-align="left" align="left">
<el-steps class="mb-4" style="max-width: 50vw" :space="200" :active="findActive() + 2" simple>
<el-step :icon="Clock"
:title="formData.record[formData.record.length - 1].check_user_name + '创建'" />
<el-step :icon="Clock" :title="flowTypeToText(item.flow_type, item)"
v-for="item in formData.steps" />
</el-steps>
</el-descriptions-item>
<el-descriptions-item label="审批记录" label-align="left" align="left">
<p v-for="item in formData.record">
<span>{{ item.check_user_name + item.status_text }} </span>了申请
{{ item.check_time }}
<span>
操作意见
{{ item.content }}
</span>
</p>
</el-descriptions-item>
<el-descriptions-item label="审批节点" label-align="left" align="left"
v-if="formData.flow_info.check_type == 2 && formData.check_status != 3 && formData.check_status != 2 && formData.admin_id != userStore.id && showTextarea()">
<div class="flex" style="position: relative;">
<el-radio-group v-model="form.check_node">
<el-radio :label="1">审批结束</el-radio>
<el-radio :label="2">下一审批人</el-radio>
</el-radio-group>
<div class="w-280[px]" style="position: absolute;left:250px">
<el-input v-show="form.check_node == 2" v-model="form.check_admin_names"
placeholder="点击选择下一审批人" clearable readonly @click="userclick" />
</div>
</div>
</el-descriptions-item>
<el-descriptions-item label="审批意见" label-align="left" align="left"
v-if="showTextarea() && formData.admin_id != userStore.id">
<el-input type="textarea" v-model="form.content"></el-input>
</el-descriptions-item>
<el-descriptions-item label="操作" label-align="left" align="left" v-if="showTextarea()">
<el-button type="primary" @click="form.check = 1, handCheck()"
v-if="formData.admin_id != userStore.id">
通过
</el-button>
<el-button @click="form.check = 2, handCheck()"
v-if="formData.admin_id != userStore.id && formData.flow_info.check_type != 3">
拒绝
</el-button>
<el-button @click="form.check = 2, handCheck()"
v-if="formData.admin_id != userStore.id && formData.flow_info.check_type == 3">
回退
</el-button>
<el-button type="info" @click="showBackDialog = true" v-if="formData.admin_id == userStore.id">
撤回
</el-button>
</el-descriptions-item>
<el-descriptions-item label="操作" label-align="left" align="left"
v-if="formData.check_status == 3 && formData.record[formData.record.length - 1].check_user_id == userStore.id">
<el-button type="info" @click="reEdit">
重新编辑
</el-button>
</el-descriptions-item>
</el-descriptions>
</el-card>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
<el-dialog v-model="showBackDialog" title="撤回审批" width="550px">
<el-form-item label="撤回原因">
<el-input v-model="form.content" type="textarea"> </el-input>
</el-form-item>
<el-form-item label="">
<el-button type="primary" @click="backFn">撤回</el-button>
<el-button @click="showBackDialog = false">取消</el-button>
</el-form-item>
</el-dialog>
</popup>
</div>
</template>
<script lang="ts" setup name="customdetail">
import annexLink from './../../components/annexLink/index.vue'
import Popup from '@/components/popup/index.vue'
import { apiOaoaApproveCheck } from "@/api/oa_initiate"
import useUserStore from "@/stores/modules/user";
import { Clock } from '@element-plus/icons-vue'
import feedback from './../../utils/feedback'
import { ref, reactive } from "vue"
import qja from './form/jq/qja.js'
import cca from './form/jq/cca.js'
import wca from './form/jq/wca.js'
import jba from './form/jq/jba.js'
import hysyda from './form/xz/hysyda.js'
import gwlza from './form/xz/gwlza.js'
import wpwxa from './form/xz/wpwxa.js'
import zzjya from './form/xz/zzjya.js'
import yza from './form/xz/yza.js'
import yca from './form/xz/yca.js'
import ycgha from './form/xz/ycgha.js'
import jka from './form/cw/jka.js'
import fka from './form/cw/fka.js'
import jla from './form/cw/jla.js'
import cga from './form/cw/cga.js'
import hdjfa from './form/cw/hdjfa.js'
import rza from './form/rs/rza.js'
import zza from './form/rs/zza.js'
import lza from './form/rs/lza.js'
import zga from './form/rs/zga.js'
import zpxqa from './form/rs/zpxqa.js'
import tyspa from './form/qt/tyspa.js'
let props = defineProps({
typeName: {
type: String,
}
})
const emit = defineEmits(['close', 'reEdit'])
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const showPerDialog = ref(false);
const personnel = ref(null);
const userStore = useUserStore().userInfo;
const showBackDialog = ref(false)
const isGenerateForm = ref(false)
let fromValue = ref({})
const getFormValue = () => {
if (props.typeName == '请假') fromValue.value = qja;
else if (props.typeName == '出差') fromValue.value = cca;
else if (props.typeName == '外出') fromValue.value = wca;
else if (props.typeName == '加班') fromValue.value = jba;
else if (props.typeName == '会议室预定') fromValue.value = hysyda;
else if (props.typeName == '公文流转') fromValue.value = gwlza;
else if (props.typeName == '物品维修') fromValue.value = wpwxa;
else if (props.typeName == '资质借用') fromValue.value = zzjya;
else if (props.typeName == '用章') fromValue.value = yza;
else if (props.typeName == '用车') fromValue.value = yca;
else if (props.typeName == '用车归还') fromValue.value = ycgha;
else if (props.typeName == '借款') fromValue.value = jka;
else if (props.typeName == '付款') fromValue.value = fka;
else if (props.typeName == '奖励') fromValue.value = jla;
else if (props.typeName == '采购') fromValue.value = cga;
else if (props.typeName == '活动经费') fromValue.value = hdjfa;
else if (props.typeName == '入职') fromValue.value = rza;
else if (props.typeName == '转正') fromValue.value = zza;
else if (props.typeName == '离职') fromValue.value = lza;
else if (props.typeName == '转岗') fromValue.value = zga;
else if (props.typeName == '招聘需求') fromValue.value = zpxqa;
else if (props.typeName == '通用审批') fromValue.value = tyspa;
else {
fromValue.value = formData.extends
isGenerateForm.value = true
}
console.log(fromValue.value)
}
//
const formData = reactive({
id: 0,
extends: {}
})
//
const setFormData = async (data: Record<any, any>) => {
for (const key in data) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key]
}
}
getFormValue()
}
const form = reactive({
"id": formData.id,
"check": '',
"content": "",
"check_node": 1,
"check_admin_ids": '',
check_admin_names: ""
})
const backFn = () => {
if (!form.content) return feedback.msgError("请填写撤回原因");
form.check = 3
handCheck()
}
const userclick = async () => {
showPerDialog.value = true;
await nextTick();
personnel.value.open();
};
const submituser = (e) => {
form.check_admin_names = e.name;
form.check_admin_ids = e.id;
showPerDialog.value = false;
};
//
const open = () => {
popupRef.value?.open()
}
const flowTypeToText = (type, item) => {
if (type == 0) return item.user_id_info[0].name;
if (type == 1) return "部门负责人";
if (type == 2) return "或签";
if (type == 3) return "会签";
if (type == 4) return item.user_id_info[0].name;
}
const findActive = () => {
let index = formData.steps.findIndex(item => { return item.sort == formData.check_step_sort })
return index
}
//
const handleClose = () => {
emit('close')
}
const hdClose = () => {
emit('close')
}
//
const handCheck = async () => {
if (form.check == 2 && !form.content) return feedback.msgError("请填写审批意见")
if (formData.check_admin_ids && formData.record[formData.record.length - 1].check_user_id == form.check_admin_ids) {
return feedback.msgError("下一级审批人不能是发起审批人")
}
if (formData.flow_info.check_type != 2) delete form.check_node;
form.id = formData.id
const res = await apiOaoaApproveCheck({ ...form })
handleClose()
}
//
const showActionList = reactive([4, 3, 2])
const showTextarea = () => {
if (showActionList.includes(formData.check_status)) return false;
if (formData.admin_id == userStore.id) return true;
if (formData?.check_admin_ids.length > 1) {
if (formData.steps[findActive()].check_list.map(item => item.check_user_id).includes(userStore.id)) return false;
else return (formData?.check_admin_ids.split(',').map(Number).includes(userStore.id)); //
} else {
return (formData?.check_admin_ids == userStore.id)
}
}
//
const reEdit = () => {
emit('reEdit', { extends: formData.extends, typeName: props.typeName, cate: formData.flow_info.flow_cate })
}
defineExpose({
open,
setFormData,
})
</script>
<style lang="scss" scoped>
:deep(.el-step__icon) {
margin-top: 10px !important;
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<div class="edit-popup">
<popup ref="popupRef" :title="popupTitle" :async="true" width="60vw" @confirm="handleSubmit" @close="handleClose">
<el-card>
<template #header>
审批内容
</template>
<qj :formData=formData.extends ref="forms" v-if="type == '请假'"></qj>
<cc ref="forms" :formData=formData.extends v-else-if="type == '出差'"></cc>
<wc ref="forms" :formData=formData.extends v-else-if="type == '外出'"></wc>
<jb ref="forms" :formData=formData.extends v-else-if="type == '加班'"></jb>
<hysyd ref="forms" :formData=formData.extends v-else-if="type == '会议室预定'"></hysyd>
<gwlz ref="forms" :formData=formData.extends v-else-if="type == '公文流转'"></gwlz>
<wpwx ref="forms" :formData=formData.extends v-else-if="type == '物品维修'"></wpwx>
<zzjy ref="forms" :formData=formData.extends v-else-if="type == '资质借用'"></zzjy>
<yz ref="forms" :formData=formData.extends v-else-if="type == '用章'"></yz>
<yc ref="forms" :formData=formData.extends v-else-if="type == '用车'"></yc>
<ycgh ref="forms" :formData=formData.extends v-else-if="type == '用车归还'"></ycgh>
<jk ref="forms" :formData=formData.extends v-else-if="type == '借款'"></jk>
<fk ref="forms" :formData=formData.extends v-else-if="type == '付款'"></fk>
<jl ref="forms" :formData=formData.extends v-else-if="type == '奖励'"></jl>
<cg ref="forms" :formData=formData.extends v-else-if="type == '采购'"></cg>
<hdjf ref="forms" :formData=formData.extends v-else-if="type == '活动经费'"></hdjf>
<rz ref="forms" :formData=formData.extends v-else-if="type == '入职'"></rz>
<zz ref="forms" :formData=formData.extends v-else-if="type == '转正'"></zz>
<lz ref="forms" :formData=formData.extends v-else-if="type == '离职'"></lz>
<zg ref="forms" :formData=formData.extends v-else-if="type == '转岗'"></zg>
<zpxq ref="forms" :formData=formData.extends v-else-if="type == '招聘需求'"></zpxq>
<tysp ref="forms" :formData=formData.extends v-else-if="type == '通用审批'"></tysp>
<generateForm :config="formData.data" :formData="formData.extends" v-else></generateForm>
</el-card>
<oaFlow :form-data="formData" :flow_cate="formData.id"></oaFlow>
</popup>
</div>
</template>
<script lang="ts" setup name="oaFlowTypeEdit">
import generateForm from './../../components/generateForm/index.vue'
import Popup from "@/components/popup/index.vue";
import { apiOaoaApproveAdd } from "@/api/oa_Initiate"
import qj from './form/jq/qj.vue'
import cc from './form/jq/cc.vue'
import wc from './form/jq/wc.vue'
import jb from './form/jq/jb.vue'
import hysyd from './form/xz/hysyd.vue'
import gwlz from './form/xz/gwlz.vue'
import wpwx from './form/xz/wpwx.vue'
import zzjy from './form/xz/zzjy.vue'
import yz from './form/xz/yz.vue'
import yc from './form/xz/yc.vue'
import ycgh from './form/xz/ycgh.vue'
import jk from './form/cw/jk.vue'
import fk from './form/cw/fk.vue'
import jl from './form/cw/jl.vue'
import cg from './form/cw/cg.vue'
import hdjf from './form/cw/hdjf.vue'
import rz from './form/rs/rz.vue'
import zz from './form/rs/zz.vue'
import lz from './form/rs/lz.vue'
import zg from './form/rs/zg.vue'
import zpxq from './form/rs/zpxq.vue'
import tysp from './form/qt/tysp.vue'
defineProps({
type: {
type: String,
}
})
const forms = ref('')
const emit = defineEmits(["success", "close"]);
const popupRef = shallowRef<InstanceType<typeof Popup>>();
const mode = ref("add");
//
const popupTitle = computed(() => {
return "新增审批"
});
//
const formData = reactive({
id: 0,
data: [],
extends: {}
});
//
const setFormData = async (data: Record<any, any>) => {
formData.data = data.data;
formData.id = data.id;
};
//
const setExtend = async (data: Record<any, any>) => {
formData.extends = data
};
//
const handleSubmit = async () => {
if (forms.value) {
await forms.value?.check();
}
const data = { ...formData };
await apiOaoaApproveAdd(data)
popupRef.value?.close();
emit("success");
};
//
const open = (type = "add") => {
mode.value = type;
popupRef.value?.open();
};
//
const handleClose = () => {
emit("close");
};
defineExpose({
open,
setFormData,
setExtend
});
</script>

View File

@ -0,0 +1,111 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="物品名称" prop="wpmc">
<el-input v-model="formData.wpmc" clearable placeholder="请输入物品名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="期望交互日期" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择期望交互日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购数量" prop="chsl">
<el-input v-model="formData.chsl" clearable placeholder="请输入采购数量" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购金额" prop="chje">
<el-input v-model="formData.chje" clearable placeholder="请输入采购金额" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="采购事由" prop="jlsy">
<el-input v-model="formData.jlsy" clearable placeholder="请输入采购事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
const qjlxList = reactive(['会议室一', '会议室二', '会议室三'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
wpmc: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
chsl: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jlsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
chje: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,9 @@
const cga = {
wpmc: "物品名称",
kssj: "期望交互日期",
chsl: "采购数量",
chje: "采购金额",
jlsy: "采购事由",
bz: "备注",
}
export default cga

View File

@ -0,0 +1,100 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="付款金额" prop="jkje">
<el-input v-model="formData.wjmc" clearable placeholder="请输入付款金额" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="付款方式" prop="jjlx">
<el-select v-model="formData.jjlx" placeholder="请选择付款方式" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="付款日期" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择付款日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收款人全称" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入收款人全称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="银行账号" prop="yhzh">
<el-input v-model="formData.yhzh" clearable placeholder="请输入银行账号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开户行" prop="khh">
<el-input v-model="formData.yhzh" clearable placeholder="请输入开户行" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="付款事由" prop="bz">
<el-input v-model="formData.bz" clearable placeholder="请输入付款事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz1" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
let list = ['jkje', 'jjlx', 'jyr', 'yhzh', 'khh', "bz", 'lwrq']
const qjlxList = reactive(['银行卡', '现金', '汇票', '电汇', '贷记', '支票', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,11 @@
const fka = {
wjmc: "付款金额",
jjlx: "付款方式",
lwrq: "付款日期",
jyr: "收款人全称",
yhzh: "银行账号",
yhzh: "开户行",
bz: "付款事由",
bz1: "备注",
}
export default fka

View File

@ -0,0 +1,118 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="活动名称" prop="jlje">
<el-input v-model="formData.jlje" clearable placeholder="请输入活动名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="活动预算" prop="jlje1">
<el-input v-model="formData.jlje" clearable placeholder="请输入活动预算" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="活动说明" prop="hdsm">
<el-input v-model="formData.hdsm" clearable placeholder="请输入活动说明" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['会议室一', '会议室二', '会议室三'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
jlje: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jlje1: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
hdsm: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,10 @@
const hdjfa = {
jlje: "活动名称",
jlje: "活动预算",
hdsm: "活动说明",
kssj: "开始时间",
jssj: "结束时间",
bz: "备注",
}
export default hdjfa

View File

@ -0,0 +1,112 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="借款金额" prop="wjmc">
<el-input v-model="formData.wjmc" clearable placeholder="请输入借款金额" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="借款类型" prop="jjlx">
<el-select v-model="formData.jjlx" placeholder="请选择借款类型" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请日期" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择申请日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="借款人" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入借用人" @click="userclick('jyr')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="银行账号" prop="yhzh">
<el-input v-model="formData.yhzh" clearable placeholder="请输入银行账号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开户行" prop="khh">
<el-input v-model="formData.khh" clearable placeholder="请输入开户行" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="借款事由" prop="bz">
<el-input v-model="formData.bz" clearable placeholder="请输入借款事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz1" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
let list = ['wjmc', 'jkje', 'jjlx', 'jyr', 'yhzh', 'khh', "bz", 'lwrq']
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
let value
const userclick = async (val) => {
showPerDialog.value = true
value = val
await nextTick()
personnel.value.open()
}
const submituser = (e) => {
props.formData[value] = e.name
props.formData[value + "_id"] = e.id
showPerDialog.value = false
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,12 @@
const jka = {
wjmc: "借款金额",
jjlx: "借款类型",
lwrq: "申请日期",
jyr: "借款人",
yhzh: "银行账号",
khh: "开户行",
bz: "借款事由",
bz1: "备注",
}
export default jka

View File

@ -0,0 +1,86 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="奖励金额" prop="jlje">
<el-input v-model="formData.jlje" clearable placeholder="请输入奖励金额" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="奖励日期" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择奖励日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="奖励事由" prop="jlsy">
<el-input v-model="formData.jlsy" clearable placeholder="请输入奖励事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
let props = defineProps({
formData: Object,
})
const qjlxList = reactive(['会议室一', '会议室二', '会议室三'])
const formRef = ref(null)
//
const formRules = reactive({
jlje: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jlsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,7 @@
const jla = {
jlje: "奖励金额",
kssj: "奖励日期",
jlsy: "奖励事由",
bz: "备注",
}
export default jla

View File

@ -0,0 +1,103 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出差天数">
<el-input v-model="formData.qjts" clearable readonly placeholder="系统自动计算" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出差事由" prop="ccsy">
<el-input v-model="formData.ccsy" clearable placeholder="请输入出差事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['事假', '年假', '调休假', '病假', '婚假', '产假', '陪产假', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
qjlx: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
ccsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const calcDay = () => {
const date1 = props.formData.kssj;
const date2 = props.formData?.jssj;
if (date1 && date2) {
const timeDiff = new Date(date2).getTime() - new Date(date1).getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
props.formData.qjts = daysDiff || 0
}
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,7 @@
const cca = {
kssj: "开始时间",
jssj: "结束时间",
qjts: "出差天数",
ccsy: "出差事由",
}
export default cca

View File

@ -0,0 +1,105 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="加班天数">
<el-input v-model="formData.qjts" clearable placeholder="系统自动计算" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="加班事由" prop="jbsy">
<el-input v-model="formData.jbsy" clearable placeholder="请输入加班事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['事假', '年假', '调休假', '病假', '婚假', '产假', '陪产假', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
qjlx: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const calcDay = () => {
const date1 = props.formData.kssj;
const date2 = props.formData?.jssj;
if (date1 && date2) {
const timeDiff = new Date(date2).getTime() - new Date(date1).getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
props.formData.qjts = daysDiff || 0
}
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,7 @@
const jba = {
kssj: "开始时间",
jssj: "结束时间",
qjts: "加班天数",
jbsy: "加班事由",
}
export default jba

View File

@ -0,0 +1,115 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="请假类型" prop="qjlx">
<el-select v-model="formData.qjlx" placeholder="请选择请假类型" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="请假天数">
<el-input v-model="formData.qjts" clearable placeholder="系统自动计算" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="请假事由" prop="qjsy">
<el-input v-model="formData.qjsy" clearable placeholder="请输入请假事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
let props = defineProps({
formData: Object,
})
const qjlxList = reactive(['事假', '年假', '调休假', '病假', '婚假', '产假', '陪产假', '其他'])
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
qjlx: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
qjsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const calcDay = () => {
const date1 = props.formData.kssj;
const date2 = props.formData?.jssj;
if (date1 && date2) {
const timeDiff = new Date(date2).getTime() - new Date(date1).getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
props.formData.qjts = daysDiff || 0
}
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,8 @@
const qja = {
qjlx: "请假类型",
kssj: "开始时间",
jssj: "结束时间",
qjts: "请假天数",
qjsy: "请假事由",
}
export default qja

View File

@ -0,0 +1,115 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="外出地点" prop="wcdd">
<el-input v-model="formData.wcdd" clearable placeholder="请输入外出地点" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="外出天数">
<el-input v-model="formData.qjts" clearable readonly placeholder="系统自动计算" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="外出事由" prop="wcsy">
<el-input v-model="formData.wcsy" clearable placeholder="请输入外出事由" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['事假', '年假', '调休假', '病假', '婚假', '产假', '陪产假', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
qjlx: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
wcsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
wcdd: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const calcDay = () => {
const date1 = props.formData.kssj;
const date2 = props.formData?.jssj;
if (date1 && date2) {
const timeDiff = new Date(date2).getTime() - new Date(date1).getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
props.formData.qjts = daysDiff || 0
}
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,8 @@
const wca = {
wcdd: "外出地点",
kssj: "开始时间",
jssj: "结束时间",
qjts: "外出天数",
wcsy: "外出事由",
}
export default wca

View File

@ -0,0 +1,76 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="审批内容" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入审批内容" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="紧急程度" prop="jjlx">
<el-select v-model="formData.jjlx" placeholder="请选择紧急程度" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="详细描述" prop="bz1">
<el-input v-model="formData.bz1" clearable placeholder="请输入详细描述" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw", 'lwrq1', 'jjlx', 'bz1']
const qjlxList = reactive(['普通', '紧急', '特急'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,7 @@
const tyspa = {
jyr: "审批内容",
jjlx: "紧急程度",
bz1: "详细描述",
}
export default tyspa

View File

@ -0,0 +1,140 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="员工姓名" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入员工姓名" @click="userclick('jyr')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入职时间" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择入职时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所在部门" prop="rzbm">
<el-select v-model="formData.rzbm" placeholder="请选择所在部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="担任职务" prop="drzw">
<el-select v-model="formData.drzw" placeholder="请选择担任职务" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请离职日期" prop="lwrq1">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq1" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择申请离职日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计离职日期" prop="lwrq2">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq2" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择预计离职日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="离职原因" prop="bz1">
<el-input v-model="formData.bz1" clearable placeholder="请输入离职原因" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
import { deptLists } from "@/api/org/department";
import { jobsLists } from '@/api/org/post'
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw", 'lwrq1', 'lwrq2', 'bz1']
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const deptList = ref([])
const getDeptList = async () => {
const res = await deptLists()
deptList.value = res.lists
}
getDeptList()
const zwlist = ref([])
const getzwlist = async () => {
const res = await jobsLists()
zwlist.value = res.lists
}
getzwlist()
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
let value
const userclick = async (val) => {
showPerDialog.value = true
value = val
await nextTick()
personnel.value.open()
}
const submituser = (e) => {
formData[value] = e.name
formData[value + "_id"] = e.id
showPerDialog.value = false
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,11 @@
const lza = {
jyr: "员工姓名",
lwrq: "入职时间",
rzbm: "所在部门",
drzw: "担任职务",
lwrq1: "申请离职日期",
lwrq2: "预计离职日期",
bz1: "离职原因",
}
export default lza

View File

@ -0,0 +1,133 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="员工姓名" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入员工姓名" @click="userclick('jyr')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入职时间" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择入职时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="手机号码" prop="wjmc">
<el-input v-model="formData.wjmc" clearable placeholder="请输入手机号码" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择性别" class="flex-1">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入职部门" prop="rzbm">
<el-select v-model="formData.rzbm" placeholder="请选择入职部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="担任职务" prop="drzw">
<el-select v-model="formData.drzw" placeholder="请选择担任职务" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz1" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
import { deptLists } from "@/api/org/department";
import { jobsLists } from '@/api/org/post'
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw"]
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const deptList = ref([])
const getDeptList = async () => {
const res = await deptLists()
deptList.value = res.lists
}
getDeptList()
const zwlist = ref([])
const getzwlist = async () => {
const res = await jobsLists()
zwlist.value = res.lists
}
getzwlist()
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
let value
const userclick = async (val) => {
showPerDialog.value = true
value = val
await nextTick()
personnel.value.open()
}
const submituser = (e) => {
formData[value] = e.name
formData[value + "_id"] = e.id
showPerDialog.value = false
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,11 @@
const rza = {
jyr: "员工姓名",
lwrq: "入职时间",
wjmc: "手机号码",
sex: "性别",
rzbm: "入职部门",
drzw: "担任职务",
bz1: "备注",
}
export default rza

View File

@ -0,0 +1,156 @@
<template>
<el-form ref="formRef" :model="formData" label-width="120px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="员工姓名" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入员工姓名" @click="userclick('jyr')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="入职时间" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择入职时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="当前所在部门" prop="rzbm">
<el-select v-model="formData.rzbm" placeholder="请选择当前所在部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="担任职务" prop="drzw">
<el-select v-model="formData.drzw" placeholder="请选择担任职务" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="转岗后所在部门" prop="rzbm">
<el-select v-model="formData.rzbm1" placeholder="请选择转岗后所在部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="转刚后职务" prop="drzw">
<el-select v-model="formData.drzw1" placeholder="请选择转刚后职务" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请转岗日期" prop="lwrq1">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq1" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择申请转岗日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计转刚日期" prop="lwrq2">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq2" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择预计转刚日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="转岗原因" prop="bz1">
<el-input v-model="formData.bz1" clearable placeholder="请输入转岗原因" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
import { deptLists } from "@/api/org/department";
import { jobsLists } from '@/api/org/post'
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw", 'lwrq1', 'lwrq2', 'bz1', 'rzbm1', 'drzw1']
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const deptList = ref([])
const getDeptList = async () => {
const res = await deptLists()
deptList.value = res.lists
}
getDeptList()
const zwlist = ref([])
const getzwlist = async () => {
const res = await jobsLists()
zwlist.value = res.lists
}
getzwlist()
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
let value
const userclick = async (val) => {
showPerDialog.value = true
value = val
await nextTick()
personnel.value.open()
}
const submituser = (e) => {
props.formData[value] = e.name
props.formData[value + "_id"] = e.id
showPerDialog.value = false
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,13 @@
const zga = {
jyr: "员工姓名",
lwrq: "入职时间",
rzbm: "当前所在部门",
drzw: "担任职务",
rzbm1: "转岗后所在部门",
drzw1: "转刚后职务",
lwrq1: "申请转岗日期",
lwrq2: "预计转刚日期",
bz1: "转岗原因",
}
export default zga

View File

@ -0,0 +1,113 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="招聘部门" prop="rzbm">
<el-select v-model="formData.rzbm" placeholder="请选择招聘部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="期望到岗日期" prop="lwrq1">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq1" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择期望到岗日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="招聘岗位" prop="drzw">
<el-select v-model="formData.drzw" placeholder="请选择招聘岗位" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="招聘人数" prop="bz1">
<el-input v-model="formData.bz1" clearable placeholder="请输入招聘人数" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="岗位职责" prop="gwzz">
<el-input v-model="formData.gwzz" clearable placeholder="请输入岗位职责" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="任职要求" prop="rzyq">
<el-input v-model="formData.rzyq" clearable placeholder="请输入任职要求" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
import { deptLists } from "@/api/org/department";
import { jobsLists } from '@/api/org/post'
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw", 'lwrq1', 'lwrq2', 'bz1', 'gwzz', 'rzyq']
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const deptList = ref([])
const getDeptList = async () => {
const res = await deptLists()
deptList.value = res.lists
}
getDeptList()
const zwlist = ref([])
const getzwlist = async () => {
const res = await jobsLists()
zwlist.value = res.lists
}
getzwlist()
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,10 @@
const zpxqa = {
rzbm: "招聘部门",
lwrq1: "期望到岗日期",
drzw: "招聘岗位",
bz1: "招聘人数",
gwzz: "岗位职责",
rzyq: "任职要求",
}
export default zpxqa

View File

@ -0,0 +1,124 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="员工姓名" prop="jyr">
<el-input v-model="formData.jyr" clearable placeholder="请输入员工姓名" @click="userclick('jyr')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="转正日期" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择转正日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所在部门" prop="rzbm">
<el-select v-model="formData.rzbm" placeholder="请选择入职部门" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in deptList">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="担任职务" prop="drzw">
<el-select v-model="formData.drzw" placeholder="请选择担任职务" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="item in zwlist">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="试用期评价" prop="bz1">
<el-input v-model="formData.bz1" clearable placeholder="请输入试用期评价" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
<div v-if="showPerDialog">
<personnelselector ref="personnel" @confirm="submituser" type="1">
</personnelselector>
</div>
</el-form>
</template>
<script setup>
import { deptLists } from "@/api/org/department";
import { jobsLists } from '@/api/org/post'
let list = ['jyr', 'lwrq', 'wjmc', 'sex', 'rzbm', "drzw", 'bz1']
const qjlxList = reactive(['差旅费', '办公费', '招待费', '交通费', '通讯费', '采购付款', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const deptList = ref([])
const getDeptList = async () => {
const res = await deptLists()
deptList.value = res.lists
}
getDeptList()
const zwlist = ref([])
const getzwlist = async () => {
const res = await jobsLists()
zwlist.value = res.lists
}
getzwlist()
//
const formRules = reactive({
})
const setRules = () => {
list.forEach(item => {
formRules[item] = [{
required: true,
message: '不可为空',
trigger: ['blur']
}]
})
}
setRules()
const showPerDialog = ref(false)
const personnel = ref(null)
let value
const userclick = async (val) => {
showPerDialog.value = true
value = val
await nextTick()
personnel.value.open()
}
const submituser = (e) => {
props.formData[value] = e.name
props.formData[value + "_id"] = e.id
showPerDialog.value = false
}
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,8 @@
const zza = {
jyr: "员工姓名",
lwrq: "转正日期",
rzbm: "所在部门",
drzw: "担任职务",
bz1: "试用期评价",
}
export default zza

View File

@ -0,0 +1,104 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="文件名称" prop="wjmc">
<el-input v-model="formData.wjmc" clearable placeholder="请输入文件名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="紧急程度" prop="jjcd">
<el-select v-model="formData.jjcd" placeholder="请选择紧急程度" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="来文单位" prop="lwdw">
<el-input v-model="formData.lwdw" clearable placeholder="请输入来文单位" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="来文日期" prop="lwrq">
<el-date-picker class="flex-1 !flex" v-model="formData.lwrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择来文日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="文件摘要" prop="wjzy">
<el-input v-model="formData.wjzy" clearable placeholder="请输入文件摘要" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
const qjlxList = reactive(['普通', '紧急', '特急'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
wjmc: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
lwdw: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
lwrq: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
wjzy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jjcd: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
lwdw: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,9 @@
const gwlza = {
wjmc: "文件名称",
jjcd: "紧急程度",
lwdw: "来文单位",
lwrq: "来文日期",
wjzy: "文件摘要",
bz: "备注",
}
export default gwlza

View File

@ -0,0 +1,99 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="会议室选择" prop="hysxz">
<el-select v-model="formData.hysxz" placeholder="请选择会议室" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="formData.bz" clearable placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['会议室一', '会议室二', '会议室三'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
hysxz: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,7 @@
const hysyda = {
item: "会议室选择",
kssj: "开始时间",
jssj: "结束时间",
bz: "备注",
}
export default hysyda

View File

@ -0,0 +1,124 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="故障设备名称" prop="gzsbmc">
<el-input v-model="formData.gzsbmc" clearable placeholder="请输入故障设备名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="紧急程度" prop="jjcd">
<el-select v-model="formData.jjcd" placeholder="请选择紧急程度" class="flex-1">
<el-option :label="item" :value="item" v-for="(item, index) in qjlxList" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计维修费用" prop="yjwxfy">
<el-input v-model="formData.yjwxfy" clearable placeholder="请输入预计维修费用" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="报修日期" prop="bxrq">
<el-date-picker class="flex-1 !flex" v-model="formData.bxrq" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择报修日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="故障描述" prop="gzms">
<el-input v-model="formData.gzms" clearable placeholder="请输入故障描述" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件">
<uploadAnnex :form-data="formData"></uploadAnnex>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
const qjlxList = reactive(['普通', '紧急', '特急'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
//
const formRules = reactive({
gzsbmc: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
yjwxfy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
bxrq: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
gzms: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jjcd: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
lwrq: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
wjzy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jbsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

View File

@ -0,0 +1,8 @@
const wpwxa = {
gzsbmc: "故障设备名称",
jjcd: "紧急程度",
yjwxfy: "预计维修费用",
bxrq: "报修日期",
gzms: "故障描述",
}
export default wpwxa

View File

@ -0,0 +1,129 @@
<template>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-row>
<el-col :span="8">
<el-form-item label="开始时间" prop="kssj">
<el-date-picker class="flex-1 !flex" v-model="formData.kssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间" prop="jssj">
<el-date-picker class="flex-1 !flex" v-model="formData.jssj" clearable type="datetime"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" @change="calcDay">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="用车天数">
<el-input v-model="formData.qjts" clearable placeholder="系统自动计算" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="用车目的地" prop="mdd">
<el-input v-model="formData.mdd" clearable placeholder="请输入用车目的地" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="车辆选择" prop="clxz">
<el-select v-model="formData.clxz" placeholder="请选择车辆选择" class="flex-1">
<el-option :label="item.name" :value="item.name" v-for="(item, index) in carLists" :key="index">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="用车事由" prop="ccsy">
<el-input v-model="formData.ccsy" clearable placeholder="请输入用车事由" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
const qjlxList = reactive(['事假', '年假', '调休假', '病假', '婚假', '产假', '陪产假', '其他'])
let props = defineProps({
formData: Object,
})
const formRef = ref(null)
import { apiOaCarCateLists } from '@/api/oa_car_cate'
let carLists = ref([])
apiOaCarCateLists().then(res => {
carLists.value = res.lists
})
const calcDay = () => {
const date1 = props.formData.kssj;
const date2 = props.formData?.jssj;
if (date1 && date2) {
const timeDiff = new Date(date2).getTime() - new Date(date1).getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
props.formData.qjts = daysDiff || 0
}
}
const checkDate = (rule: any, value: any, callback: any) => {
if (new Date(props.formData.jssj) < new Date(props.formData.kssj)) {
callback(new Error('结束时间不能早于开始时间'))
} else {
callback()
}
}
//
const formRules = reactive({
qjlx: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
kssj: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
jssj: [
{
required: true,
message: '不可为空',
trigger: ['blur']
},
{
validator: checkDate,
trigger: ['blur']
}
],
ccsy: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
mdd: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
clxz: [{
required: true,
message: '不可为空',
trigger: ['blur']
}],
})
const check = async () => {
await formRef.value?.validate();
}
defineExpose({
check
});
</script>

Some files were not shown because too many files have changed in this diff Show More