From d685280269881b5dddec3a1f2fa41d11e06b5e25 Mon Sep 17 00:00:00 2001 From: dataeaseShu Date: Mon, 14 Jul 2025 18:26:33 +0800 Subject: [PATCH] feat(user): user manage --- frontend/package.json | 1 + frontend/src/api/user.ts | 16 + frontend/src/api/workspace.ts | 9 + .../src/assets/svg/icon_assigned_outlined.svg | 5 + .../src/assets/svg/icon_close_outlined.svg | 3 + frontend/src/assets/svg/icon_member.svg | 4 + .../src/assets/svg/icon_rename_outlined.svg | 4 + .../workspace/icon_custom-tools_colorful.png | Bin 0 -> 1584 bytes .../src/components/drawer-filter/index.ts | 3 + .../drawer-filter/src/DrawerEnumFilter.vue | 115 +++++ .../drawer-filter/src/DrawerFilter.vue | 91 ++++ frontend/src/components/drawer-main/index.ts | 3 + .../components/drawer-main/src/DrawerMain.vue | 163 ++++++ frontend/src/components/filter-text/index.ts | 91 ++++ .../components/filter-text/src/FilterText.vue | 206 ++++++++ frontend/src/components/layout/MenuItem.vue | 16 +- frontend/src/i18n/en.json | 51 +- frontend/src/i18n/zh-CN.json | 51 +- frontend/src/router/index.ts | 19 +- frontend/src/style.less | 22 + frontend/src/utils/propTypes.ts | 27 + frontend/src/views/ds/Card.vue | 7 +- frontend/src/views/ds/Datasource.vue | 2 +- frontend/src/views/system/user/User.vue | 368 +++++++++++--- frontend/src/views/system/user/UserImport.vue | 475 ++++++++++++++++++ .../src/views/system/workspace/ParamsForm.vue | 108 ++++ frontend/src/views/system/workspace/index.vue | 444 ++++++++++++++++ 27 files changed, 2221 insertions(+), 83 deletions(-) create mode 100644 frontend/src/api/user.ts create mode 100644 frontend/src/api/workspace.ts create mode 100644 frontend/src/assets/svg/icon_assigned_outlined.svg create mode 100644 frontend/src/assets/svg/icon_close_outlined.svg create mode 100644 frontend/src/assets/svg/icon_member.svg create mode 100644 frontend/src/assets/svg/icon_rename_outlined.svg create mode 100644 frontend/src/assets/workspace/icon_custom-tools_colorful.png create mode 100644 frontend/src/components/drawer-filter/index.ts create mode 100644 frontend/src/components/drawer-filter/src/DrawerEnumFilter.vue create mode 100644 frontend/src/components/drawer-filter/src/DrawerFilter.vue create mode 100644 frontend/src/components/drawer-main/index.ts create mode 100644 frontend/src/components/drawer-main/src/DrawerMain.vue create mode 100644 frontend/src/components/filter-text/index.ts create mode 100644 frontend/src/components/filter-text/src/FilterText.vue create mode 100644 frontend/src/utils/propTypes.ts create mode 100644 frontend/src/views/system/user/UserImport.vue create mode 100644 frontend/src/views/system/workspace/ParamsForm.vue create mode 100644 frontend/src/views/system/workspace/index.vue diff --git a/frontend/package.json b/frontend/package.json index 862fcda4..677c94c8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,7 @@ "vue-dompurify-html": "^5.3.0", "vue-i18n": "^9.14.4", "vue-router": "^4.5.0", + "vue-types": "^6.0.0", "web-storage-cache": "^1.1.1" }, "devDependencies": { diff --git a/frontend/src/api/user.ts b/frontend/src/api/user.ts new file mode 100644 index 00000000..723010d3 --- /dev/null +++ b/frontend/src/api/user.ts @@ -0,0 +1,16 @@ +import { request } from '@/utils/request' + +export const userImportApi = { + downExcelTemplateApi: () => request.post('/user/excelTemplate', {}, { responseType: 'blob' }), + importUserApi: (data: any) => + request.post('/user/batchImport', data, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }), + downErrorRecordApi: (key: string) => + request.get(`/user/errorRecord/${key}`, { responseType: 'blob' }), + clearErrorApi: (key: string) => { + request.get(`/user/clearErrorRecord/${key}`) + }, +} diff --git a/frontend/src/api/workspace.ts b/frontend/src/api/workspace.ts new file mode 100644 index 00000000..25b8d6e7 --- /dev/null +++ b/frontend/src/api/workspace.ts @@ -0,0 +1,9 @@ +import { request } from '@/utils/request' + +export const workspaceUserList = (params: any, pageNum: number, pageSize: number) => + request.get(`/system/workspace/uws/pager/${pageNum}/${pageSize}`, { params }) + +export const workspaceCreate = (data: any) => request.post('/system/workspace/uws', data) +export const workspaceDelete = (data: any) => request.delete('/system/workspace/uws', data) +export const workspaceList = () => request.get('/system/workspace') +export const workspaceDetail = (id: any) => request.get(`/system/workspace/${id}`) diff --git a/frontend/src/assets/svg/icon_assigned_outlined.svg b/frontend/src/assets/svg/icon_assigned_outlined.svg new file mode 100644 index 00000000..ca199a73 --- /dev/null +++ b/frontend/src/assets/svg/icon_assigned_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_close_outlined.svg b/frontend/src/assets/svg/icon_close_outlined.svg new file mode 100644 index 00000000..124221e7 --- /dev/null +++ b/frontend/src/assets/svg/icon_close_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_member.svg b/frontend/src/assets/svg/icon_member.svg new file mode 100644 index 00000000..fe594998 --- /dev/null +++ b/frontend/src/assets/svg/icon_member.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_rename_outlined.svg b/frontend/src/assets/svg/icon_rename_outlined.svg new file mode 100644 index 00000000..f0af70f4 --- /dev/null +++ b/frontend/src/assets/svg/icon_rename_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/workspace/icon_custom-tools_colorful.png b/frontend/src/assets/workspace/icon_custom-tools_colorful.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ceb24607c966d6e3fb73dcac9f01e01fb7831c GIT binary patch literal 1584 zcmV-02G9A4P)>XSVoyTI9ZRLY(o>qeuLq62=?T{?(@+3Jnj-nn}A! zDT9x!`uv|28IzAN^UlOJyC_b*R0lv2t_D6J+#^!py=;W=p5!*W%xm1#%LPhMi4U&% z{NbGIJ7DI8@U!(MyiOrYP%;P9v+w}2-FNLYX$7=R2T#|t@ELept_9EOFET8EohOID zlpR?$1t8BmWcGEMAu~=i1u)LuC#S*b1P;0jc*$WfV#l>3YI_kGW8^^G4SbK1NRWpd zN-{}a(MUO00cwIe6;*vW8yy*-rB|xe-ZnPuB7fH*I@?h_0~CR<$<3Kq)UcWUJuP&h z$49M?HEOSi+IlIlFhg^(DA@^WABAiLvwr^h!!&X5owV=(=Mx9t7D_onZ5h|?zzr>w zv@BF1Z|v*R1Z;HgG8}XA>26^it#o1e22I}nk*o&p?_Tt|R{D6KHa@s~lUD!T zASF;Dv|^D>(J-B`d5U z&RVBOIY|OR4znIO&_`B)*brR0Nivb9fZWt(6|e@GDYIe)Xa&uILp0RhOLj7Odr?Y| ztSAeVlG?07R?0M;1u)}dFCD9j@H%?RtRz#IR=~pMIz|7pHb(!MRt@(3t0#;Ub1!w&JIpl!;jnEKD0VK&U=ZfZ^}syb@fE z?;RZ`6TrMt2|oM8UeN&cYO4!3VrvD*E(-shT3@Cn5h&3q76UmR_3z$)Mpi+}yDnQ|^m|HQOe7Avyp&*Jq5-+xIM4&@YkZaly9+A6P|BlbXEs)|0f#5kT7FKfm zjhZZkjH*GHK4!^C$U+#cBSNX;D`6U2otIY#$y^dEmi9{N-;1p%S(FmvtYv!i7uk1* zjH*FcgHez)T2X?z4~q)0l7`0!JTzsA0(3Bw=+*OlIAf8s*s{6ox<41o6#$C4#nk$e zCU~xbVD2M7UoR_em_bv32!gX@!xJK5C9>2>QPzZSIK#V@GG?>#^?$;3~Z{xF zoqGo7=|xed@)2?jJF;e#fOho-)g*KFLDsUkJIT+mI?f2%rl}+!$h?-NfXJKvh>Q4O zJt{#HUdRR+Gq2~}7>W4&VQ8t&ln{bUk(@n)plBP2on+Wd^|0@ zDuLAIX*w;w@wHl42C7<-(XNt@{GFbyRixyvpw?E^!o1 iookaqk-_q|&;JkTiLwnrX!oc90000 +import { propTypes } from '@/utils/propTypes' +import { reactive } from 'vue' +import { useEmitt } from '@/utils/useEmitt' + +const props = defineProps({ + optionList: propTypes.arrayOf( + propTypes.shape({ + id: propTypes.string, + name: propTypes.string, + }) + ), + index: propTypes.number, + title: propTypes.string, +}) + +const state = reactive<{ activeStatus: any[]; optionList: any[] }>({ + activeStatus: [], + optionList: [], +}) + +const nodeChange = (id: string | number) => { + const len = state.activeStatus.indexOf(id) + if (len >= 0) { + state.activeStatus.splice(len, 1) + } else { + state.activeStatus.push(id) + } + emits('filter-change', state.activeStatus) +} + +const emits = defineEmits(['filter-change']) +const clear = (index: number) => { + if (index !== props.index) return + state.activeStatus = [] +} + +useEmitt({ + name: 'clear-drawer_main', + callback: clear, +}) + + + + + diff --git a/frontend/src/components/drawer-filter/src/DrawerFilter.vue b/frontend/src/components/drawer-filter/src/DrawerFilter.vue new file mode 100644 index 00000000..06724a97 --- /dev/null +++ b/frontend/src/components/drawer-filter/src/DrawerFilter.vue @@ -0,0 +1,91 @@ + + + + diff --git a/frontend/src/components/drawer-main/index.ts b/frontend/src/components/drawer-main/index.ts new file mode 100644 index 00000000..f8c594cc --- /dev/null +++ b/frontend/src/components/drawer-main/index.ts @@ -0,0 +1,3 @@ +import DrawerMain from './src/DrawerMain.vue' + +export { DrawerMain } diff --git a/frontend/src/components/drawer-main/src/DrawerMain.vue b/frontend/src/components/drawer-main/src/DrawerMain.vue new file mode 100644 index 00000000..6f149b5b --- /dev/null +++ b/frontend/src/components/drawer-main/src/DrawerMain.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/frontend/src/components/filter-text/index.ts b/frontend/src/components/filter-text/index.ts new file mode 100644 index 00000000..343a0af8 --- /dev/null +++ b/frontend/src/components/filter-text/index.ts @@ -0,0 +1,91 @@ +import FilterText from './src/FilterText.vue' + +export { FilterText } + +const fieldText = (field: string, options: any[]) => { + for (let index = 0; index < options.length; index++) { + const element = options[index] + if (field === element.field) { + return element.title + } + } +} +const valueTextFormTree = (val: string, options: any[]) => { + let result = null + const stack = [...options] + while (stack.length) { + const item = stack.pop() + if (item.value === val) { + result = item.label + break + } + if (item.children?.length) { + item.children.forEach((kid: any) => stack.push(kid)) + } + } + return result || val +} +const timestampFormatDate = (value: string) => { + if (!value) { + return '-' + } + return new Date(value).toLocaleString() +} +const valueText = (field: string, val: string, options: any[]) => { + for (let index = 0; index < options.length; index++) { + const element = options[index] + if (field === element.field) { + let isTree = false + const selectOption = element.option + for (let i = 0; i < selectOption.length; i++) { + const item = selectOption[i] as any + if (item.children !== undefined) { + isTree = true + break + } + if (item.id === val || item.value === val) { + return item.name || item.label + } + } + if (element.type === 'time') { + return timestampFormatDate(val) + } + if (isTree) { + return valueTextFormTree(val, selectOption) + } + } + } + return val +} +export const convertFilterText = (conditions: any[], options: any[]) => { + console.log('conditions', conditions, options) + + const result: any[] = [] + conditions.forEach((condition) => { + const field = condition.field + const ope = condition.operator + const value = condition.value + const fieldName = fieldText(field, options) + const textOpe = ':' + let separator = ',' + if (ope === 'in') { + separator = '、' + } + if (ope === 'between') { + separator = '~' + } + let valText = value + + if (value) { + if (Array.isArray(value)) { + const valTextArray = value.map((val) => valueText(field, val, options)) + valText = valTextArray.join(separator) + } + if (valText?.length) { + const obj = fieldName + textOpe + valText + result.push(obj) + } + } + }) + return result +} diff --git a/frontend/src/components/filter-text/src/FilterText.vue b/frontend/src/components/filter-text/src/FilterText.vue new file mode 100644 index 00000000..71fb6329 --- /dev/null +++ b/frontend/src/components/filter-text/src/FilterText.vue @@ -0,0 +1,206 @@ + + + + + diff --git a/frontend/src/components/layout/MenuItem.vue b/frontend/src/components/layout/MenuItem.vue index 147520bf..c4665f06 100644 --- a/frontend/src/components/layout/MenuItem.vue +++ b/frontend/src/components/layout/MenuItem.vue @@ -1,15 +1,18 @@ + + + diff --git a/frontend/src/views/system/workspace/ParamsForm.vue b/frontend/src/views/system/workspace/ParamsForm.vue new file mode 100644 index 00000000..f6edbc54 --- /dev/null +++ b/frontend/src/views/system/workspace/ParamsForm.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/frontend/src/views/system/workspace/index.vue b/frontend/src/views/system/workspace/index.vue new file mode 100644 index 00000000..a725cde9 --- /dev/null +++ b/frontend/src/views/system/workspace/index.vue @@ -0,0 +1,444 @@ + + + + +