From 28d0785be842022cae7808c23e1f19eaab5fb996 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sat, 5 Aug 2023 14:13:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=83=A8=E9=97=A8=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/department/index.ts | 91 ++++- src/api/department/index.ts | 12 + src/components/Form/src/Form.vue | 18 +- src/components/Form/src/helper/index.ts | 6 +- src/components/Search/src/Search.vue | 21 +- src/locales/en.ts | 10 +- src/locales/zh-CN.ts | 13 +- src/router/index.ts | 10 +- src/utils/is.ts | 4 + .../Authorization/Department/Department.vue | 337 ++++++++++++++++++ .../Department/components/Detail.vue | 20 ++ .../Department/components/Write.vue | 61 ++++ src/views/Authorization/{ => User}/User.vue | 0 .../{ => User}/components/Detail.vue | 0 .../{ => User}/components/Write.vue | 0 src/views/Example/Dialog/ExampleDialog.vue | 42 ++- src/views/Example/Page/ExamplePage.vue | 70 +++- 17 files changed, 655 insertions(+), 60 deletions(-) create mode 100644 src/views/Authorization/Department/Department.vue create mode 100644 src/views/Authorization/Department/components/Detail.vue create mode 100644 src/views/Authorization/Department/components/Write.vue rename src/views/Authorization/{ => User}/User.vue (100%) rename src/views/Authorization/{ => User}/components/Detail.vue (100%) rename src/views/Authorization/{ => User}/components/Write.vue (100%) diff --git a/mock/department/index.ts b/mock/department/index.ts index 8a96b95..34b5341 100644 --- a/mock/department/index.ts +++ b/mock/department/index.ts @@ -14,36 +14,65 @@ for (let i = 0; i < 5; i++) { // 部门名称 departmentName: citys[i], id: toAnyString(), + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + // 备注 + remark: '@cword(10, 15)', children: [ { // 部门名称 departmentName: '研发部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' }, { // 部门名称 departmentName: '产品部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' }, { // 部门名称 departmentName: '运营部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' }, { // 部门名称 departmentName: '市场部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' }, { // 部门名称 departmentName: '销售部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' }, { // 部门名称 departmentName: '客服部', - id: toAnyString() + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' } ] }) @@ -65,6 +94,21 @@ export default [ } } }, + { + url: '/department/table/list', + method: 'get', + response: () => { + return { + data: { + code: code, + data: { + list: departmentList, + total: 5 + } + } + } + } + }, { url: '/department/users', method: 'get', @@ -136,5 +180,40 @@ export default [ } } } + }, + // 保存接口 + { + url: '/department/save', + method: 'post', + timeout: 1000, + response: () => { + return { + data: { + code: code, + data: 'success' + } + } + } + }, + // 删除接口 + { + url: '/department/delete', + method: 'post', + response: ({ body }) => { + const ids = body.ids + if (!ids) { + return { + code: '500', + message: '请选择需要删除的数据' + } + } else { + return { + data: { + code: code, + data: 'success' + } + } + } + } } ] as MockMethod[] diff --git a/src/api/department/index.ts b/src/api/department/index.ts index 6339ad4..b6ece1e 100644 --- a/src/api/department/index.ts +++ b/src/api/department/index.ts @@ -16,3 +16,15 @@ export const deleteUserByIdApi = (ids: string[] | number[]) => { export const saveUserApi = (data: any) => { return request.post({ url: '/department/user/save', data }) } + +export const saveDepartmentApi = (data: any) => { + return request.post({ url: '/department/save', data }) +} + +export const deleteDepartmentApi = (ids: string[] | number[]) => { + return request.post({ url: '/department/delete', data: { ids } }) +} + +export const getDepartmentTableApi = (params: any) => { + return request.get({ url: '/department/table/list', params }) +} diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index fdf9178..347ea4f 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -24,7 +24,7 @@ import { useRenderRadio } from './components/useRenderRadio' import { useRenderCheckbox } from './components/useRenderCheckbox' import { useDesign } from '@/hooks/web/useDesign' import { findIndex } from '@/utils' -import { set } from 'lodash-es' +import { get, set } from 'lodash-es' import { FormProps } from './types' import { FormSchema, @@ -319,18 +319,18 @@ export default defineComponent({ const Comp = () => { // 如果field是多层路径,需要转换成对象 - const fields = item.field.split('.') - // 循环fields,绑定v-model - const vModel = fields.reduce((prev, next, index) => { - if (index === 0) { - return formModel.value[next] + const itemVal = computed({ + get: () => { + return get(formModel.value, item.field) + }, + set: (val) => { + set(formModel.value, item.field, val) } - return prev[next] - }, {}) + }) return ( setComponentRefMap(el, item.field)} {...(autoSetPlaceholder && setTextPlaceholder(item))} {...setComponentProps(item)} diff --git a/src/components/Form/src/helper/index.ts b/src/components/Form/src/helper/index.ts index 74fb284..423993c 100644 --- a/src/components/Form/src/helper/index.ts +++ b/src/components/Form/src/helper/index.ts @@ -150,7 +150,11 @@ export const initModel = (schema: FormSchema[], formModel: Recordable) => { // const hasField = Reflect.has(model, v.field) const hasField = get(model, v.field) // 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值 - set(model, v.field, hasField ? get(model, v.field) : v.value !== void 0 ? v.value : undefined) + set( + model, + v.field, + hasField !== void 0 ? get(model, v.field) : v.value !== void 0 ? v.value : undefined + ) // model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : undefined } }) diff --git a/src/components/Search/src/Search.vue b/src/components/Search/src/Search.vue index 354fefe..2fe42ec 100644 --- a/src/components/Search/src/Search.vue +++ b/src/components/Search/src/Search.vue @@ -9,6 +9,7 @@ import { initModel } from '@/components/Form/src/helper' import ActionButton from './components/ActionButton.vue' import { SearchProps } from './types' import { FormItemProp } from 'element-plus' +import { isObject, isEmptyVal } from '@/utils/is' const props = defineProps({ // 生成Form的布局结构数组 @@ -130,12 +131,22 @@ watch( const filterModel = async () => { const model = await getFormData() - unref(getProps).removeNoValueItem && - Object.keys(model).forEach((key) => { - if (model[key] === void 0 || model[key] === '') { - delete model[key] + if (unref(getProps).removeNoValueItem) { + // 使用reduce过滤空值,并返回一个新对象 + return Object.keys(model).reduce((prev, next) => { + const value = model[next] + if (!isEmptyVal(value)) { + if (isObject(value)) { + if (Object.keys(value).length > 0) { + prev[next] = value + } + } else { + prev[next] = value + } } - }) + return prev + }, {}) + } return model } diff --git a/src/locales/en.ts b/src/locales/en.ts index 2423139..00cf611 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -160,7 +160,8 @@ export default { inputPassword: 'InputPassword', sticky: 'Sticky', treeTable: 'Tree table', - PicturePreview: 'Table Image Preview' + PicturePreview: 'Table Image Preview', + department: 'Department management' }, permission: { hasPermission: 'Please set the operation permission value' @@ -496,7 +497,12 @@ export default { email: 'Email', createTime: 'Create time', // 所属部门 - department: 'Department' + department: 'Department', + departmentName: 'Department name', + status: 'Status', + enable: 'Enable', + disable: 'Disable', + superiorDepartment: 'Superior department' }, inputPasswordDemo: { title: 'InputPassword', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 30fe2c7..8a86b76 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -160,7 +160,8 @@ export default { inputPassword: '密码输入框', sticky: '黏性', treeTable: '树形表格', - PicturePreview: '表格图片预览' + PicturePreview: '表格图片预览', + department: '部门管理' }, permission: { hasPermission: '请设置操作权限值' @@ -488,7 +489,15 @@ export default { email: '邮箱', createTime: '创建时间', // 所属部门 - department: '所属部门' + department: '所属部门', + departmentName: '部门名称', + status: '状态', + // 启用 + enable: '启用', + // 禁用 + disable: '禁用', + // 上级部门 + superiorDepartment: '上级部门' }, inputPasswordDemo: { title: '密码输入框', diff --git a/src/router/index.ts b/src/router/index.ts index ba366e9..9d2e796 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -519,7 +519,7 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ children: [ { path: 'user', - component: () => import('@/views/Authorization/User.vue'), + component: () => import('@/views/Authorization/User/User.vue'), name: 'User', meta: { title: t('router.user') @@ -532,6 +532,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ meta: { title: t('router.role') } + }, + { + path: 'department', + component: () => import('@/views/Authorization/Department/Department.vue'), + name: 'Department', + meta: { + title: t('router.department') + } } ] } diff --git a/src/utils/is.ts b/src/utils/is.ts index 2adaa37..8ac2e50 100644 --- a/src/utils/is.ts +++ b/src/utils/is.ts @@ -108,3 +108,7 @@ export const isDark = (): boolean => { export const isImgPath = (path: string): boolean => { return /(https?:\/\/|data:image\/).*?\.(png|jpg|jpeg|gif|svg|webp|ico)/gi.test(path) } + +export const isEmptyVal = (val: any): boolean => { + return val === '' || val === null || val === undefined +} diff --git a/src/views/Authorization/Department/Department.vue b/src/views/Authorization/Department/Department.vue new file mode 100644 index 0000000..0b45aa5 --- /dev/null +++ b/src/views/Authorization/Department/Department.vue @@ -0,0 +1,337 @@ + + + diff --git a/src/views/Authorization/Department/components/Detail.vue b/src/views/Authorization/Department/components/Detail.vue new file mode 100644 index 0000000..2496e75 --- /dev/null +++ b/src/views/Authorization/Department/components/Detail.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/views/Authorization/Department/components/Write.vue b/src/views/Authorization/Department/components/Write.vue new file mode 100644 index 0000000..4b48234 --- /dev/null +++ b/src/views/Authorization/Department/components/Write.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/views/Authorization/User.vue b/src/views/Authorization/User/User.vue similarity index 100% rename from src/views/Authorization/User.vue rename to src/views/Authorization/User/User.vue diff --git a/src/views/Authorization/components/Detail.vue b/src/views/Authorization/User/components/Detail.vue similarity index 100% rename from src/views/Authorization/components/Detail.vue rename to src/views/Authorization/User/components/Detail.vue diff --git a/src/views/Authorization/components/Write.vue b/src/views/Authorization/User/components/Write.vue similarity index 100% rename from src/views/Authorization/components/Write.vue rename to src/views/Authorization/User/components/Write.vue diff --git a/src/views/Example/Dialog/ExampleDialog.vue b/src/views/Example/Dialog/ExampleDialog.vue index 0fdd926..b544247 100644 --- a/src/views/Example/Dialog/ExampleDialog.vue +++ b/src/views/Example/Dialog/ExampleDialog.vue @@ -4,11 +4,11 @@ import { Search } from '@/components/Search' import { Dialog } from '@/components/Dialog' import { useI18n } from '@/hooks/web/useI18n' import { ElButton, ElTag } from 'element-plus' -import { Table, TableColumn } from '@/components/Table' +import { Table } from '@/components/Table' import { getTableListApi, saveTableApi, delTableListApi } from '@/api/table' import { useTable } from '@/hooks/web/useTable' import { TableData } from '@/api/table/types' -import { h, ref, unref, reactive } from 'vue' +import { ref, unref, reactive } from 'vue' import Write from './components/Write.vue' import Detail from './components/Detail.vue' import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' @@ -47,6 +47,9 @@ const { t } = useI18n() const crudSchemas = reactive([ { field: 'selection', + search: { + hidden: true + }, form: { hidden: true }, @@ -61,6 +64,9 @@ const crudSchemas = reactive([ field: 'index', label: t('tableDemo.index'), type: 'index', + search: { + hidden: true + }, form: { hidden: true }, @@ -86,11 +92,17 @@ const crudSchemas = reactive([ }, { field: 'author', - label: t('tableDemo.author') + label: t('tableDemo.author'), + search: { + hidden: true + } }, { field: 'display_time', label: t('tableDemo.displayTime'), + search: { + hidden: true + }, form: { component: 'DatePicker', componentProps: { @@ -102,19 +114,8 @@ const crudSchemas = reactive([ { field: 'importance', label: t('tableDemo.importance'), - formatter: (_: Recordable, __: TableColumn, cellValue: number) => { - return h( - ElTag, - { - type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger' - }, - () => - cellValue === 1 - ? t('tableDemo.important') - : cellValue === 2 - ? t('tableDemo.good') - : t('tableDemo.commonly') - ) + search: { + hidden: true }, form: { component: 'Select', @@ -161,6 +162,9 @@ const crudSchemas = reactive([ { field: 'pageviews', label: t('tableDemo.pageviews'), + search: { + hidden: true + }, form: { component: 'InputNumber', value: 0 @@ -169,6 +173,9 @@ const crudSchemas = reactive([ { field: 'content', label: t('exampleDemo.content'), + search: { + hidden: true + }, table: { show: false }, @@ -191,6 +198,9 @@ const crudSchemas = reactive([ field: 'action', width: '260px', label: t('tableDemo.action'), + search: { + hidden: true + }, form: { hidden: true }, diff --git a/src/views/Example/Page/ExamplePage.vue b/src/views/Example/Page/ExamplePage.vue index 55f09cd..b5db6c1 100644 --- a/src/views/Example/Page/ExamplePage.vue +++ b/src/views/Example/Page/ExamplePage.vue @@ -3,11 +3,11 @@ import { ContentWrap } from '@/components/ContentWrap' import { Search } from '@/components/Search' import { useI18n } from '@/hooks/web/useI18n' import { ElButton, ElTag } from 'element-plus' -import { Table, TableColumn } from '@/components/Table' +import { Table } from '@/components/Table' import { getTableListApi, delTableListApi } from '@/api/table' import { useTable } from '@/hooks/web/useTable' import { TableData } from '@/api/table/types' -import { h, reactive, ref, unref } from 'vue' +import { reactive, ref, unref } from 'vue' import { useRouter } from 'vue-router' import { useEmitt } from '@/hooks/event/useEmitt' import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' @@ -64,6 +64,9 @@ const { t } = useI18n() const crudSchemas = reactive([ { field: 'selection', + search: { + hidden: true + }, form: { hidden: true }, @@ -78,6 +81,9 @@ const crudSchemas = reactive([ field: 'index', label: t('tableDemo.index'), type: 'index', + search: { + hidden: true + }, form: { hidden: true }, @@ -103,11 +109,17 @@ const crudSchemas = reactive([ }, { field: 'author', - label: t('tableDemo.author') + label: t('tableDemo.author'), + search: { + hidden: true + } }, { field: 'display_time', label: t('tableDemo.displayTime'), + search: { + hidden: true + }, form: { component: 'DatePicker', componentProps: { @@ -119,19 +131,8 @@ const crudSchemas = reactive([ { field: 'importance', label: t('tableDemo.importance'), - formatter: (_: Recordable, __: TableColumn, cellValue: number) => { - return h( - ElTag, - { - type: cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger' - }, - () => - cellValue === 1 - ? t('tableDemo.important') - : cellValue === 2 - ? t('tableDemo.good') - : t('tableDemo.commonly') - ) + search: { + hidden: true }, form: { component: 'Select', @@ -154,11 +155,33 @@ const crudSchemas = reactive([ } ] } + }, + detail: { + slots: { + default: (data: any) => { + return ( + + {data.importance === 1 + ? t('tableDemo.important') + : data.importance === 2 + ? t('tableDemo.good') + : t('tableDemo.commonly')} + + ) + } + } } }, { field: 'pageviews', label: t('tableDemo.pageviews'), + search: { + hidden: true + }, form: { component: 'InputNumber', value: 0 @@ -167,9 +190,12 @@ const crudSchemas = reactive([ { field: 'content', label: t('exampleDemo.content'), - table: { + search: { hidden: true }, + table: { + show: false + }, form: { component: 'Editor', colProps: { @@ -177,13 +203,21 @@ const crudSchemas = reactive([ } }, detail: { - span: 24 + span: 24, + slots: { + default: (data: any) => { + return
+ } + } } }, { field: 'action', width: '260px', label: t('tableDemo.action'), + search: { + hidden: true + }, form: { hidden: true },