perf: 完善系统管理-部门管理页面

This commit is contained in:
xiaoxian521 2023-05-11 15:11:58 +08:00
parent 47f951312e
commit a71bf0befb
13 changed files with 576 additions and 179 deletions

View File

@ -1,6 +1,7 @@
import { MockMethod } from "vite-plugin-mock"; import { MockMethod } from "vite-plugin-mock";
export default [ export default [
// 角色
{ {
url: "/role", url: "/role",
method: "post", method: "post",
@ -10,7 +11,7 @@ export default [
data: { data: {
list: [ list: [
{ {
createTime: 1609837428000, createTime: 1605456000000,
updateTime: 1645477701000, updateTime: 1645477701000,
creator: "admin", creator: "admin",
updater: "", updater: "",
@ -27,7 +28,7 @@ export default [
dataScopeDeptIds: null dataScopeDeptIds: null
}, },
{ {
createTime: 1609837428000, createTime: 1605456000000,
updateTime: 1645477700000, updateTime: 1645477700000,
creator: "admin", creator: "admin",
updater: "", updater: "",
@ -44,7 +45,7 @@ export default [
dataScopeDeptIds: null dataScopeDeptIds: null
}, },
{ {
createTime: 1609912175000, createTime: 1605456000000,
updateTime: 1647698441000, updateTime: 1647698441000,
creator: "", creator: "",
updater: "1", updater: "1",
@ -66,6 +67,7 @@ export default [
}; };
} }
}, },
// 部门
{ {
url: "/dept", url: "/dept",
method: "post", method: "post",
@ -75,138 +77,139 @@ export default [
data: [ data: [
{ {
name: "杭州总公司", name: "杭州总公司",
type: 1, // 1 公司 2 分公司 3 部门
parentId: 0, parentId: 0,
sort: 0,
leaderUserId: 1,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 100, id: 100,
createTime: 1609837427000, sort: 0,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 1, // 1 公司 2 分公司 3 部门
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "郑州分公司", name: "郑州分公司",
type: 2,
parentId: 100, parentId: 100,
sort: 1,
leaderUserId: 104,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 101, id: 101,
createTime: 1609837427000, sort: 1,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 2,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "研发部门", name: "研发部门",
type: 3,
parentId: 101, parentId: 101,
sort: 1,
leaderUserId: 104,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 103, id: 103,
createTime: 1609837427000, sort: 1,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "市场部门", name: "市场部门",
type: 3,
parentId: 102, parentId: 102,
sort: 1,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 108, id: 108,
createTime: 1609837427000, sort: 1,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "深圳分公司", name: "深圳分公司",
type: 2,
parentId: 100, parentId: 100,
sort: 2,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 102, id: 102,
createTime: 1609837427000, sort: 2,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 2,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "市场部门", name: "市场部门",
type: 3,
parentId: 101, parentId: 101,
sort: 2,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 1,
id: 104, id: 104,
createTime: 1609837427000, sort: 2,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "财务部门", name: "财务部门",
type: 3,
parentId: 102, parentId: 102,
sort: 2,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 109, id: 109,
createTime: 1609837427000, sort: 2,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "测试部门", name: "测试部门",
type: 3,
parentId: 101, parentId: 101,
sort: 3,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 105, id: 105,
createTime: 1609837427000, sort: 3,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 0,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "财务部门", name: "财务部门",
type: 3,
parentId: 101, parentId: 101,
sort: 4,
leaderUserId: 103,
phone: "15888888888",
email: "ry@qq.com",
status: 1,
id: 106, id: 106,
createTime: 1609837427000, sort: 4,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 1,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
}, },
{ {
name: "运维部门", name: "运维部门",
type: 3,
parentId: 101, parentId: 101,
sort: 5,
leaderUserId: null,
phone: "15888888888",
email: "ry@qq.com",
status: 0,
id: 107, id: 107,
createTime: 1609837427000, sort: 5,
remark: "备注、备注、备注、备注、备注、备注、备注" phone: "15888888888",
principal: "@cname()",
email: "@email",
status: 0,
type: 3,
createTime: 1605456000000,
remark: "@cparagraph(1, 3)"
} }
] ]
}; };
} }
}, },
// 用户
{ {
url: "/user", url: "/user",
method: "post", method: "post",
@ -225,7 +228,7 @@ export default [
sex: 0, sex: 0,
id: 1, id: 1,
status: 0, status: 0,
createTime: 1609837427000, createTime: 1605456000000,
dept: { dept: {
id: 103, id: 103,
name: "研发部门" name: "研发部门"
@ -241,7 +244,7 @@ export default [
sex: 0, sex: 0,
id: 100, id: 100,
status: 1, status: 1,
createTime: 1609981637000, createTime: 1605456000000,
dept: { dept: {
id: 104, id: 104,
name: "市场部门" name: "市场部门"
@ -257,7 +260,7 @@ export default [
sex: 1, sex: 1,
id: 103, id: 103,
status: 1, status: 1,
createTime: 1610553035000, createTime: 1605456000000,
dept: { dept: {
id: 106, id: 106,
name: "财务部门" name: "财务部门"
@ -273,7 +276,7 @@ export default [
sex: 0, sex: 0,
id: 104, id: 104,
status: 0, status: 0,
createTime: 1611166433000, createTime: 1605456000000,
dept: { dept: {
id: 107, id: 107,
name: "运维部门" name: "运维部门"

View File

@ -94,8 +94,8 @@
"@types/qrcode": "^1.5.0", "@types/qrcode": "^1.5.0",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@types/sortablejs": "^1.15.1", "@types/sortablejs": "^1.15.1",
"@typescript-eslint/eslint-plugin": "^5.59.2", "@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.59.2", "@typescript-eslint/parser": "^5.59.5",
"@vitejs/plugin-vue": "^4.2.1", "@vitejs/plugin-vue": "^4.2.1",
"@vitejs/plugin-vue-jsx": "^3.0.1", "@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0", "@vue/eslint-config-prettier": "^7.1.0",
@ -105,7 +105,7 @@
"cssnano": "^6.0.1", "cssnano": "^6.0.1",
"eslint": "^8.40.0", "eslint": "^8.40.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.11.1", "eslint-plugin-vue": "^9.12.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^13.2.2", "lint-staged": "^13.2.2",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",

92
pnpm-lock.yaml generated
View File

@ -24,8 +24,8 @@ specifiers:
"@types/qrcode": ^1.5.0 "@types/qrcode": ^1.5.0
"@types/qs": ^6.9.7 "@types/qs": ^6.9.7
"@types/sortablejs": ^1.15.1 "@types/sortablejs": ^1.15.1
"@typescript-eslint/eslint-plugin": ^5.59.2 "@typescript-eslint/eslint-plugin": ^5.59.5
"@typescript-eslint/parser": ^5.59.2 "@typescript-eslint/parser": ^5.59.5
"@vitejs/plugin-vue": ^4.2.1 "@vitejs/plugin-vue": ^4.2.1
"@vitejs/plugin-vue-jsx": ^3.0.1 "@vitejs/plugin-vue-jsx": ^3.0.1
"@vue/eslint-config-prettier": ^7.1.0 "@vue/eslint-config-prettier": ^7.1.0
@ -48,7 +48,7 @@ specifiers:
element-resize-detector: ^1.2.4 element-resize-detector: ^1.2.4
eslint: ^8.40.0 eslint: ^8.40.0
eslint-plugin-prettier: ^4.2.1 eslint-plugin-prettier: ^4.2.1
eslint-plugin-vue: ^9.11.1 eslint-plugin-vue: ^9.12.0
husky: ^8.0.3 husky: ^8.0.3
intro.js: ^7.0.1 intro.js: ^7.0.1
js-cookie: ^3.0.5 js-cookie: ^3.0.5
@ -180,18 +180,18 @@ devDependencies:
"@types/qrcode": 1.5.0 "@types/qrcode": 1.5.0
"@types/qs": 6.9.7 "@types/qs": 6.9.7
"@types/sortablejs": 1.15.1 "@types/sortablejs": 1.15.1
"@typescript-eslint/eslint-plugin": 5.59.2_xukgzdyhwbmahvl54wfj63w474 "@typescript-eslint/eslint-plugin": 5.59.5_zaj6dsh3leplki3sfxgbx2w2za
"@typescript-eslint/parser": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/parser": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
"@vitejs/plugin-vue": 4.2.1_vite@4.3.5+vue@3.2.47 "@vitejs/plugin-vue": 4.2.1_vite@4.3.5+vue@3.2.47
"@vitejs/plugin-vue-jsx": 3.0.1_vite@4.3.5+vue@3.2.47 "@vitejs/plugin-vue-jsx": 3.0.1_vite@4.3.5+vue@3.2.47
"@vue/eslint-config-prettier": 7.1.0_cpow4lz2r544yrekpzuutjvo2i "@vue/eslint-config-prettier": 7.1.0_cpow4lz2r544yrekpzuutjvo2i
"@vue/eslint-config-typescript": 11.0.3_bpsvh4wngwxirjqntlxkeawmpq "@vue/eslint-config-typescript": 11.0.3_nhvncizgwdwdw3lhirpwnri2za
autoprefixer: 10.4.14_postcss@8.4.23 autoprefixer: 10.4.14_postcss@8.4.23
cloc: 2.11.0 cloc: 2.11.0
cssnano: 6.0.1_postcss@8.4.23 cssnano: 6.0.1_postcss@8.4.23
eslint: 8.40.0 eslint: 8.40.0
eslint-plugin-prettier: 4.2.1_cpow4lz2r544yrekpzuutjvo2i eslint-plugin-prettier: 4.2.1_cpow4lz2r544yrekpzuutjvo2i
eslint-plugin-vue: 9.11.1_eslint@8.40.0 eslint-plugin-vue: 9.12.0_eslint@8.40.0
husky: 8.0.3 husky: 8.0.3
lint-staged: 13.2.2 lint-staged: 13.2.2
picocolors: 1.0.0 picocolors: 1.0.0
@ -2430,10 +2430,10 @@ packages:
"@types/yargs-parser": 21.0.0 "@types/yargs-parser": 21.0.0
dev: false dev: false
/@typescript-eslint/eslint-plugin/5.59.2_xukgzdyhwbmahvl54wfj63w474: /@typescript-eslint/eslint-plugin/5.59.5_zaj6dsh3leplki3sfxgbx2w2za:
resolution: resolution:
{ {
integrity: sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== integrity: sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:
@ -2445,10 +2445,10 @@ packages:
optional: true optional: true
dependencies: dependencies:
"@eslint-community/regexpp": 4.5.0 "@eslint-community/regexpp": 4.5.0
"@typescript-eslint/parser": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/parser": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
"@typescript-eslint/scope-manager": 5.59.2 "@typescript-eslint/scope-manager": 5.59.5
"@typescript-eslint/type-utils": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/type-utils": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
"@typescript-eslint/utils": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/utils": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
debug: 4.3.4 debug: 4.3.4
eslint: 8.40.0 eslint: 8.40.0
grapheme-splitter: 1.0.4 grapheme-splitter: 1.0.4
@ -2461,10 +2461,10 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/parser/5.59.2_3qfatcekpgbllh6uk5ivyhkbxq: /@typescript-eslint/parser/5.59.5_3qfatcekpgbllh6uk5ivyhkbxq:
resolution: resolution:
{ {
integrity: sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== integrity: sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:
@ -2474,9 +2474,9 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
"@typescript-eslint/scope-manager": 5.59.2 "@typescript-eslint/scope-manager": 5.59.5
"@typescript-eslint/types": 5.59.2 "@typescript-eslint/types": 5.59.5
"@typescript-eslint/typescript-estree": 5.59.2_typescript@5.0.4 "@typescript-eslint/typescript-estree": 5.59.5_typescript@5.0.4
debug: 4.3.4 debug: 4.3.4
eslint: 8.40.0 eslint: 8.40.0
typescript: 5.0.4 typescript: 5.0.4
@ -2484,21 +2484,21 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/scope-manager/5.59.2: /@typescript-eslint/scope-manager/5.59.5:
resolution: resolution:
{ {
integrity: sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA== integrity: sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
dependencies: dependencies:
"@typescript-eslint/types": 5.59.2 "@typescript-eslint/types": 5.59.5
"@typescript-eslint/visitor-keys": 5.59.2 "@typescript-eslint/visitor-keys": 5.59.5
dev: true dev: true
/@typescript-eslint/type-utils/5.59.2_3qfatcekpgbllh6uk5ivyhkbxq: /@typescript-eslint/type-utils/5.59.5_3qfatcekpgbllh6uk5ivyhkbxq:
resolution: resolution:
{ {
integrity: sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== integrity: sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:
@ -2508,8 +2508,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
"@typescript-eslint/typescript-estree": 5.59.2_typescript@5.0.4 "@typescript-eslint/typescript-estree": 5.59.5_typescript@5.0.4
"@typescript-eslint/utils": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/utils": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
debug: 4.3.4 debug: 4.3.4
eslint: 8.40.0 eslint: 8.40.0
tsutils: 3.21.0_typescript@5.0.4 tsutils: 3.21.0_typescript@5.0.4
@ -2518,18 +2518,18 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/types/5.59.2: /@typescript-eslint/types/5.59.5:
resolution: resolution:
{ {
integrity: sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== integrity: sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
dev: true dev: true
/@typescript-eslint/typescript-estree/5.59.2_typescript@5.0.4: /@typescript-eslint/typescript-estree/5.59.5_typescript@5.0.4:
resolution: resolution:
{ {
integrity: sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q== integrity: sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:
@ -2538,8 +2538,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
"@typescript-eslint/types": 5.59.2 "@typescript-eslint/types": 5.59.5
"@typescript-eslint/visitor-keys": 5.59.2 "@typescript-eslint/visitor-keys": 5.59.5
debug: 4.3.4 debug: 4.3.4
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
@ -2550,10 +2550,10 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils/5.59.2_3qfatcekpgbllh6uk5ivyhkbxq: /@typescript-eslint/utils/5.59.5_3qfatcekpgbllh6uk5ivyhkbxq:
resolution: resolution:
{ {
integrity: sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== integrity: sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:
@ -2562,9 +2562,9 @@ packages:
"@eslint-community/eslint-utils": 4.4.0_eslint@8.40.0 "@eslint-community/eslint-utils": 4.4.0_eslint@8.40.0
"@types/json-schema": 7.0.11 "@types/json-schema": 7.0.11
"@types/semver": 7.3.13 "@types/semver": 7.3.13
"@typescript-eslint/scope-manager": 5.59.2 "@typescript-eslint/scope-manager": 5.59.5
"@typescript-eslint/types": 5.59.2 "@typescript-eslint/types": 5.59.5
"@typescript-eslint/typescript-estree": 5.59.2_typescript@5.0.4 "@typescript-eslint/typescript-estree": 5.59.5_typescript@5.0.4
eslint: 8.40.0 eslint: 8.40.0
eslint-scope: 5.1.1 eslint-scope: 5.1.1
semver: 7.5.0 semver: 7.5.0
@ -2573,14 +2573,14 @@ packages:
- typescript - typescript
dev: true dev: true
/@typescript-eslint/visitor-keys/5.59.2: /@typescript-eslint/visitor-keys/5.59.5:
resolution: resolution:
{ {
integrity: sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig== integrity: sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==
} }
engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 }
dependencies: dependencies:
"@typescript-eslint/types": 5.59.2 "@typescript-eslint/types": 5.59.5
eslint-visitor-keys: 3.4.1 eslint-visitor-keys: 3.4.1
dev: true dev: true
@ -2840,7 +2840,7 @@ packages:
prettier: 2.8.7 prettier: 2.8.7
dev: true dev: true
/@vue/eslint-config-typescript/11.0.3_bpsvh4wngwxirjqntlxkeawmpq: /@vue/eslint-config-typescript/11.0.3_nhvncizgwdwdw3lhirpwnri2za:
resolution: resolution:
{ {
integrity: sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw== integrity: sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw==
@ -2854,10 +2854,10 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
"@typescript-eslint/eslint-plugin": 5.59.2_xukgzdyhwbmahvl54wfj63w474 "@typescript-eslint/eslint-plugin": 5.59.5_zaj6dsh3leplki3sfxgbx2w2za
"@typescript-eslint/parser": 5.59.2_3qfatcekpgbllh6uk5ivyhkbxq "@typescript-eslint/parser": 5.59.5_3qfatcekpgbllh6uk5ivyhkbxq
eslint: 8.40.0 eslint: 8.40.0
eslint-plugin-vue: 9.11.1_eslint@8.40.0 eslint-plugin-vue: 9.12.0_eslint@8.40.0
typescript: 5.0.4 typescript: 5.0.4
vue-eslint-parser: 9.2.1_eslint@8.40.0 vue-eslint-parser: 9.2.1_eslint@8.40.0
transitivePeerDependencies: transitivePeerDependencies:
@ -5574,10 +5574,10 @@ packages:
prettier-linter-helpers: 1.0.0 prettier-linter-helpers: 1.0.0
dev: true dev: true
/eslint-plugin-vue/9.11.1_eslint@8.40.0: /eslint-plugin-vue/9.12.0_eslint@8.40.0:
resolution: resolution:
{ {
integrity: sha512-SNtBGDrRkPUFsREswPceqdvZ7YVdWY+iCYiDC+RoxwVieeQ7GJU1FLDlkcaYTOD2os/YuVgI1Fdu8YGM7fmoow== integrity: sha512-xH8PgpDW2WwmFSmRfs/3iWogef1CJzQqX264I65zz77jDuxF2yLy7+GA2diUM8ZNATuSl1+UehMQkb5YEyau5w==
} }
engines: { node: ^14.17.0 || >=16.0.0 } engines: { node: ^14.17.0 || >=16.0.0 }
peerDependencies: peerDependencies:

View File

@ -22,7 +22,7 @@ const footerButtons = computed(() => {
const done = () => const done = () =>
closeDialog(options, index, { command: "cancel" }); closeDialog(options, index, { command: "cancel" });
if (options?.beforeCancel && isFunction(options?.beforeCancel)) { if (options?.beforeCancel && isFunction(options?.beforeCancel)) {
options.beforeCancel(done); options.beforeCancel(done, { options, index });
} else { } else {
done(); done();
} }
@ -37,7 +37,7 @@ const footerButtons = computed(() => {
const done = () => const done = () =>
closeDialog(options, index, { command: "sure" }); closeDialog(options, index, { command: "sure" });
if (options?.beforeSure && isFunction(options?.beforeSure)) { if (options?.beforeSure && isFunction(options?.beforeSure)) {
options.beforeSure(done); options.beforeSure(done, { options, index });
} else { } else {
done(); done();
} }

View File

@ -190,9 +190,27 @@ interface DialogOptions extends DialogProps {
index: number; index: number;
}) => void; }) => void;
/** 点击底部取消按钮的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */ /** 点击底部取消按钮的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */
beforeCancel?: (done: Function) => void; beforeCancel?: (
done: Function,
{
options,
index
}: {
options: DialogOptions;
index: number;
}
) => void;
/** 点击底部确定按钮的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */ /** 点击底部确定按钮的回调,会暂停 `Dialog` 的关闭. 回调函数内执行 `done` 参数方法的时候才是真正关闭对话框的时候 */
beforeSure?: (done: Function) => void; beforeSure?: (
done: Function,
{
options,
index
}: {
options: DialogOptions;
index: number;
}
) => void;
} }
export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions }; export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions };

View File

@ -191,6 +191,7 @@ function onCloseCallBackClick() {
}); });
} }
// 便使 addDialog
function onNestingClick() { function onNestingClick() {
addDialog({ addDialog({
title: "嵌套的弹框", title: "嵌套的弹框",
@ -323,6 +324,44 @@ function onFormFourClick() {
} }
}); });
} }
function onBeforeCancelClick() {
addDialog({
title: "点击底部取消按钮的回调",
contentRenderer: () => (
<p>弹框内容-点击底部取消按钮的回调会暂停弹框的关闭</p>
),
beforeCancel: (done, { options, index }) => {
console.log(
"%coptions, index===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
options,
index
);
// done(); //
}
});
}
function onBeforeSureClick() {
addDialog({
title: "点击底部确定按钮的回调",
contentRenderer: () => (
<p>
弹框内容-点击底部确定按钮的回调会暂停弹框的关闭经常用于新增编辑弹框内容后调用接口
</p>
),
beforeSure: (done, { options, index }) => {
console.log(
"%coptions, index===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
options,
index
);
// done(); //
}
});
}
</script> </script>
<template> <template>
@ -338,7 +377,13 @@ function onFormFourClick() {
> >
Dialog Dialog
</el-link> </el-link>
采用函数式调用弹框组件 采用函数式调用弹框组件更多操作实例请参考
<span
class="cursor-pointer text-primary"
@click="$router.push({ name: 'Dept' })"
>系统管理页面</span
>
</span> </span>
</div> </div>
</template> </template>
@ -380,5 +425,14 @@ function onFormFourClick() {
结合Form表单第四种方式 结合Form表单第四种方式
</el-button> </el-button>
</el-space> </el-space>
<el-divider />
<el-space wrap>
<el-button @click="onBeforeCancelClick">
点击底部取消按钮的回调会暂停弹框的关闭
</el-button>
<el-button @click="onBeforeSureClick">
点击底部确定按钮的回调会暂停弹框的关闭经常用于新增编辑弹框内容后调用接口
</el-button>
</el-space>
</el-card> </el-card>
</template> </template>

View File

@ -0,0 +1,155 @@
<script setup lang="ts">
import { ref } from "vue";
import { formRules } from "./rule";
import ReCol from "@/components/ReCol";
import { usePublicHooks } from "../hooks";
/** TODO
* 针对类型的props/emit声明vue3.3.0版本以下不支持复杂的类型和从其他文件进行类型导入等后续vue正式发布3.3.0版本再优化
* https://cn.vuejs.org/api/sfc-script-setup.html#typescript-only-features
*/
interface FormProps {
formInline: {
higherDeptOptions: Record<string, unknown>[];
parentId: number;
name: string;
principal: string;
phone: string | number;
email: string;
sort: number;
status: number;
remark: string;
};
}
const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({
higherDeptOptions: [],
parentId: 0,
name: "",
principal: "",
phone: "",
email: "",
sort: 0,
status: 1,
remark: ""
})
});
const ruleFormRef = ref();
const { switchStyle } = usePublicHooks();
const newFormInline = ref(props.formInline);
function getRef() {
return ruleFormRef.value;
}
defineExpose({ getRef });
</script>
<template>
<el-form
ref="ruleFormRef"
:model="newFormInline"
:rules="formRules"
label-width="82px"
>
<el-row :gutter="30">
<re-col>
<el-form-item label="上级部门">
<el-cascader
class="w-full"
v-model="newFormInline.parentId"
:options="newFormInline.higherDeptOptions"
:props="{
value: 'id',
label: 'name',
emitPath: false,
checkStrictly: true
}"
clearable
filterable
placeholder="请选择上级部门"
>
<template #default="{ node, data }">
<span>{{ data.name }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门名称" prop="name">
<el-input
v-model="newFormInline.name"
clearable
placeholder="请输入部门名称"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门负责人">
<el-input
v-model="newFormInline.principal"
clearable
placeholder="请输入部门负责人"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="手机号" prop="phone">
<el-input
v-model="newFormInline.phone"
clearable
placeholder="请输入手机号"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="邮箱" prop="email">
<el-input
v-model="newFormInline.email"
clearable
placeholder="请输入邮箱"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="排序">
<el-input-number
v-model="newFormInline.sort"
:min="0"
:max="9999"
controls-position="right"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="部门状态">
<el-switch
v-model="newFormInline.status"
inline-prompt
:active-value="1"
:inactive-value="0"
active-text="启用"
inactive-text="停用"
:style="switchStyle"
/>
</el-form-item>
</re-col>
<re-col>
<el-form-item label="备注">
<el-input
v-model="newFormInline.remark"
placeholder="请输入备注信息"
type="textarea"
/>
</el-form-item>
</re-col>
</el-row>
</el-form>
</template>

View File

@ -1,22 +1,26 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import editForm from "./form.vue";
import { handleTree } from "@/utils/tree"; import { handleTree } from "@/utils/tree";
import { usePublicHooks } from "../hooks";
import { message } from "@/utils/message";
import { getDeptList } from "@/api/system"; import { getDeptList } from "@/api/system";
import { reactive, ref, onMounted } from "vue"; import { type FormItemProps } from "./types";
import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue";
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
export function useDept() { export function useDept() {
const form = reactive({ const form = reactive({
user: "", name: "",
status: "" status: null
}); });
const formRef = ref();
const dataList = ref([]); const dataList = ref([]);
const loading = ref(true); const loading = ref(true);
const { tagStyle } = usePublicHooks();
const columns: TableColumnList = [ const columns: TableColumnList = [
{
label: "序号",
type: "index",
minWidth: 70
},
{ {
label: "部门名称", label: "部门名称",
prop: "name", prop: "name",
@ -33,12 +37,8 @@ export function useDept() {
prop: "status", prop: "status",
minWidth: 100, minWidth: 100,
cellRenderer: ({ row, props }) => ( cellRenderer: ({ row, props }) => (
<el-tag <el-tag size={props.size} style={tagStyle.value(row.status)}>
size={props.size} {row.status === 1 ? "启用" : "停用"}
type={row.status === 1 ? "danger" : "success"}
effect="plain"
>
{row.status === 0 ? "关闭" : "开启"}
</el-tag> </el-tag>
) )
}, },
@ -52,7 +52,7 @@ export function useDept() {
{ {
label: "备注", label: "备注",
prop: "remark", prop: "remark",
minWidth: 200 minWidth: 320
}, },
{ {
label: "操作", label: "操作",
@ -62,14 +62,6 @@ export function useDept() {
} }
]; ];
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleSelectionChange(val) { function handleSelectionChange(val) {
console.log("handleSelectionChange", val); console.log("handleSelectionChange", val);
} }
@ -82,13 +74,86 @@ export function useDept() {
async function onSearch() { async function onSearch() {
loading.value = true; loading.value = true;
const { data } = await getDeptList(); const { data } = await getDeptList(); // 这里是返回一维数组结构前端自行处理成树结构返回格式要求唯一id加父节点parentIdparentId取父节点id
dataList.value = handleTree(data); let newData = data;
if (!isAllEmpty(form.name)) {
// 前端搜索部门名称
newData = newData.filter(item => item.name.includes(form.name));
}
if (!isAllEmpty(form.status)) {
// 前端搜索状态
newData = newData.filter(item => item.status === form.status);
}
dataList.value = handleTree(newData); // 处理成树结构
setTimeout(() => { setTimeout(() => {
loading.value = false; loading.value = false;
}, 500); }, 500);
} }
function formatHigherDeptOptions(treeList) {
// 根据返回数据的status字段值判断追加是否禁用disabled字段返回处理后的树结构用于上级部门级联选择器的展示实际开发中也是如此不可能前端需要的每个字段后端都会返回这时需要前端自行根据后端返回的某些字段做逻辑处理
if (!treeList || !treeList.length) return;
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) {
treeList[i].disabled = treeList[i].status === 0 ? true : false;
formatHigherDeptOptions(treeList[i].children);
newTreeList.push(treeList[i]);
}
return newTreeList;
}
function openDialog(title = "新增", row?: FormItemProps) {
addDialog({
title: `${title}部门`,
props: {
formInline: {
higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)),
parentId: row?.parentId ?? 0,
name: row?.name ?? "",
principal: row?.principal ?? "",
phone: row?.phone ?? "",
email: row?.email ?? "",
sort: row?.sort ?? 0,
status: row?.status ?? 1,
remark: row?.remark ?? ""
}
},
width: "40%",
draggable: true,
closeOnClickModal: false,
contentRenderer: () => h(editForm, { ref: formRef }),
beforeSure: (done, { options }) => {
const FormRef = formRef.value.getRef();
const curData = options.props.formInline as FormItemProps;
function chores() {
message(`${title}了部门名称为${curData.name}的这条数据`, {
type: "success"
});
done(); // 关闭弹框
onSearch(); // 刷新表格数据
}
FormRef.validate(valid => {
if (valid) {
console.log("curData", curData);
// 表单规则校验通过
if (title === "新增") {
// 实际开发先调用新增接口,再进行下面操作
chores();
} else {
// 实际开发先调用编辑接口,再进行下面操作
chores();
}
}
});
}
});
}
function handleDelete(row) {
message(`您删除了部门名称为${row.name}的这条数据`, { type: "success" });
onSearch();
}
onMounted(() => { onMounted(() => {
onSearch(); onSearch();
}); });
@ -98,9 +163,13 @@ export function useDept() {
loading, loading,
columns, columns,
dataList, dataList,
/** 搜索 */
onSearch, onSearch,
/** 重置 */
resetForm, resetForm,
handleUpdate, /** 新增、编辑部门 */
openDialog,
/** 删除部门 */
handleDelete, handleDelete,
handleSelectionChange handleSelectionChange
}; };

View File

@ -23,7 +23,7 @@ const {
dataList, dataList,
onSearch, onSearch,
resetForm, resetForm,
handleUpdate, openDialog,
handleDelete, handleDelete,
handleSelectionChange handleSelectionChange
} = useDept(); } = useDept();
@ -37,9 +37,9 @@ const {
:model="form" :model="form"
class="bg-bg_color w-[99/100] pl-8 pt-4" class="bg-bg_color w-[99/100] pl-8 pt-4"
> >
<el-form-item label="部门名称:" prop="user"> <el-form-item label="部门名称:" prop="name">
<el-input <el-input
v-model="form.user" v-model="form.name"
placeholder="请输入部门名称" placeholder="请输入部门名称"
clearable clearable
class="!w-[200px]" class="!w-[200px]"
@ -52,8 +52,8 @@ const {
clearable clearable
class="!w-[180px]" class="!w-[180px]"
> >
<el-option label="开启" value="1" /> <el-option label="启用" :value="1" />
<el-option label="关闭" value="0" /> <el-option label="停用" :value="0" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
@ -72,13 +72,17 @@ const {
</el-form> </el-form>
<PureTableBar <PureTableBar
title="部门列表" title="部门列表(仅演示,操作后不生效)"
:columns="columns" :columns="columns"
:tableRef="tableRef?.getTableRef()" :tableRef="tableRef?.getTableRef()"
@refresh="onSearch" @refresh="onSearch"
> >
<template #buttons> <template #buttons>
<el-button type="primary" :icon="useRenderIcon(AddFill)"> <el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
新增部门 新增部门
</el-button> </el-button>
</template> </template>
@ -107,12 +111,15 @@ const {
link link
type="primary" type="primary"
:size="size" :size="size"
@click="handleUpdate(row)"
:icon="useRenderIcon(EditPen)" :icon="useRenderIcon(EditPen)"
@click="openDialog('编辑', row)"
> >
修改 编辑
</el-button> </el-button>
<el-popconfirm title="是否确认删除?"> <el-popconfirm
:title="`是否确认删除部门名称为${row.name}的这条数据`"
@confirm="handleDelete(row)"
>
<template #reference> <template #reference>
<el-button <el-button
class="reset-margin" class="reset-margin"
@ -120,7 +127,6 @@ const {
type="primary" type="primary"
:size="size" :size="size"
:icon="useRenderIcon(Delete)" :icon="useRenderIcon(Delete)"
@click="handleDelete(row)"
> >
删除 删除
</el-button> </el-button>

View File

@ -0,0 +1,37 @@
import { reactive } from "vue";
import type { FormRules } from "element-plus";
import { isPhone, isEmail } from "@pureadmin/utils";
/** 自定义表单规则校验 */
export const formRules = reactive(<FormRules>{
name: [{ required: true, message: "部门名称为必填项", trigger: "blur" }],
phone: [
{
validator: (rule, value, callback) => {
if (value === "") {
callback();
} else if (!isPhone(value)) {
callback(new Error("请输入正确的手机号码格式"));
} else {
callback();
}
},
trigger: "blur"
// trigger: "click" // 如果想在点击确定按钮时触发这个校验trigger 设置成 click 即可
}
],
email: [
{
validator: (rule, value, callback) => {
if (value === "") {
callback();
} else if (!isEmail(value)) {
callback(new Error("请输入正确的邮箱格式"));
} else {
callback();
}
},
trigger: "blur"
}
]
});

View File

@ -0,0 +1,16 @@
interface FormItemProps {
higherDeptOptions: Record<string, unknown>[];
parentId: number;
name: string;
principal: string;
phone: string | number;
email: string;
sort: number;
status: number;
remark: string;
}
interface FormProps {
formInline: FormItemProps;
}
export type { FormItemProps, FormProps };

39
src/views/system/hooks.ts Normal file
View File

@ -0,0 +1,39 @@
// 抽离可公用的工具函数等用于系统管理页面逻辑
import { computed } from "vue";
import { useDark } from "@pureadmin/utils";
export function usePublicHooks() {
const { isDark } = useDark();
const switchStyle = computed(() => {
return {
"--el-switch-on-color": "#6abe39",
"--el-switch-off-color": "#e84749"
};
});
const tagStyle = computed(() => {
return (status: number) => {
return status === 1
? {
"--el-tag-text-color": isDark.value ? "#6abe39" : "#389e0d",
"--el-tag-bg-color": isDark.value ? "#172412" : "#f6ffed",
"--el-tag-border-color": isDark.value ? "#274a17" : "#b7eb8f"
}
: {
"--el-tag-text-color": isDark.value ? "#e84749" : "#cf1322",
"--el-tag-bg-color": isDark.value ? "#2b1316" : "#fff1f0",
"--el-tag-border-color": isDark.value ? "#58191c" : "#ffa39e"
};
};
});
return {
/** 当前网页是否为`dark`模式 */
isDark,
/** 表现更鲜明的`el-switch`组件 */
switchStyle,
/** 表现更鲜明的`el-tag`组件 */
tagStyle
};
}

View File

@ -11,7 +11,7 @@ declare module "vue" {
} }
/** /**
* todohttps://github.com/element-plus/element-plus/blob/dev/global.d.ts#L2 * TODO https://github.com/element-plus/element-plus/blob/dev/global.d.ts#L2
* No need to install @vue/runtime-core * No need to install @vue/runtime-core
*/ */
declare module "vue" { declare module "vue" {