feat: 补齐用户管理与接口文档能力
This commit is contained in:
parent
29663ef369
commit
e60e98bf49
@ -26,6 +26,7 @@
|
|||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@kwitsukasa/knife4j-swagger-vue3": "0.1.2",
|
||||||
"@nestjs/common": "^9.4.3",
|
"@nestjs/common": "^9.4.3",
|
||||||
"@nestjs/config": "^2.3.4",
|
"@nestjs/config": "^2.3.4",
|
||||||
"@nestjs/core": "^9.4.3",
|
"@nestjs/core": "^9.4.3",
|
||||||
@ -37,7 +38,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mqtt": "^5.15.1",
|
"mqtt": "^5.15.1",
|
||||||
"mysql2": "^3.22.3",
|
"mysql2": "^3.22.3",
|
||||||
"nestjs-knife4j-plus": "^1.0.9",
|
|
||||||
"nestjs-minio-client": "^2.2.0",
|
"nestjs-minio-client": "^2.2.0",
|
||||||
"reflect-metadata": "^0.1.14",
|
"reflect-metadata": "^0.1.14",
|
||||||
"rxjs": "^7.8.2",
|
"rxjs": "^7.8.2",
|
||||||
|
|||||||
@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@kwitsukasa/knife4j-swagger-vue3':
|
||||||
|
specifier: 0.1.2
|
||||||
|
version: 0.1.2(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))
|
||||||
'@nestjs/common':
|
'@nestjs/common':
|
||||||
specifier: ^9.4.3
|
specifier: ^9.4.3
|
||||||
version: 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
version: 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
||||||
@ -41,9 +44,6 @@ importers:
|
|||||||
mysql2:
|
mysql2:
|
||||||
specifier: ^3.22.3
|
specifier: ^3.22.3
|
||||||
version: 3.22.3(@types/node@18.11.18)
|
version: 3.22.3(@types/node@18.11.18)
|
||||||
nestjs-knife4j-plus:
|
|
||||||
specifier: ^1.0.9
|
|
||||||
version: 1.0.9(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2)
|
|
||||||
nestjs-minio-client:
|
nestjs-minio-client:
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3)
|
version: 2.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3)
|
||||||
@ -554,6 +554,11 @@ packages:
|
|||||||
'@js-joda/core@5.7.0':
|
'@js-joda/core@5.7.0':
|
||||||
resolution: {integrity: sha512-WBu4ULVVxySLLzK1Ppq+OdfP+adRS4ntmDQT915rzDJ++i95gc2jZkM5B6LWEAwN3lGXpfie3yPABozdD3K3Vg==}
|
resolution: {integrity: sha512-WBu4ULVVxySLLzK1Ppq+OdfP+adRS4ntmDQT915rzDJ++i95gc2jZkM5B6LWEAwN3lGXpfie3yPABozdD3K3Vg==}
|
||||||
|
|
||||||
|
'@kwitsukasa/knife4j-swagger-vue3@0.1.2':
|
||||||
|
resolution: {integrity: sha512-OsVKUo/URe1zONjW4ZmxXIdRiVHLNufkjYYDi1DuZqXm0a743NlezAAb12wwOajwkyyUNCCgs6NP5x6WkK8NEw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@nestjs/common': '*'
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0':
|
'@lukeed/csprng@1.1.0':
|
||||||
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -2664,19 +2669,6 @@ packages:
|
|||||||
neo-async@2.6.2:
|
neo-async@2.6.2:
|
||||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
|
|
||||||
nestjs-knife4j-plus@1.0.9:
|
|
||||||
resolution: {integrity: sha512-MgMrfXgJfRgwW43BbMAKvInxluuvdNjSiYmkBvQvUawJMwn6+Op4W8/iYG1Q7u4D7mefWtM4zwVA7gBHErWCzg==}
|
|
||||||
peerDependencies:
|
|
||||||
'@fastify/static': '*'
|
|
||||||
'@nestjs/common': '*'
|
|
||||||
express: '*'
|
|
||||||
fastify: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@fastify/static':
|
|
||||||
optional: true
|
|
||||||
fastify:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
nestjs-minio-client@2.2.0:
|
nestjs-minio-client@2.2.0:
|
||||||
resolution: {integrity: sha512-mz1vfJq/7YfSyVCIeZwOCfIfBz+msI9QynHS2QGO9GB+tVNnQOYta8PxFsH9tMxN7gNrjrf5jXsEIpgBB1oTeA==}
|
resolution: {integrity: sha512-mz1vfJq/7YfSyVCIeZwOCfIfBz+msI9QynHS2QGO9GB+tVNnQOYta8PxFsH9tMxN7gNrjrf5jXsEIpgBB1oTeA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -4422,6 +4414,10 @@ snapshots:
|
|||||||
'@js-joda/core@5.7.0':
|
'@js-joda/core@5.7.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@kwitsukasa/knife4j-swagger-vue3@0.1.2(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))':
|
||||||
|
dependencies:
|
||||||
|
'@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0': {}
|
'@lukeed/csprng@1.1.0': {}
|
||||||
|
|
||||||
'@microsoft/tsdoc@0.15.1': {}
|
'@microsoft/tsdoc@0.15.1': {}
|
||||||
@ -7074,11 +7070,6 @@ snapshots:
|
|||||||
|
|
||||||
neo-async@2.6.2: {}
|
neo-async@2.6.2: {}
|
||||||
|
|
||||||
nestjs-knife4j-plus@1.0.9(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2):
|
|
||||||
dependencies:
|
|
||||||
'@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
|
||||||
express: 4.18.2
|
|
||||||
|
|
||||||
nestjs-minio-client@2.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3):
|
nestjs-minio-client@2.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
'@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)
|
||||||
|
|||||||
@ -45,6 +45,7 @@ CREATE TABLE IF NOT EXISTS `admin_user` (
|
|||||||
`username` varchar(255) NOT NULL,
|
`username` varchar(255) NOT NULL,
|
||||||
`password` varchar(255) NOT NULL,
|
`password` varchar(255) NOT NULL,
|
||||||
`real_name` varchar(255) NOT NULL,
|
`real_name` varchar(255) NOT NULL,
|
||||||
|
`dept_id` bigint DEFAULT NULL,
|
||||||
`home_path` varchar(255) NOT NULL DEFAULT '',
|
`home_path` varchar(255) NOT NULL DEFAULT '',
|
||||||
`timezone` varchar(255) NOT NULL DEFAULT 'Asia/Shanghai',
|
`timezone` varchar(255) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||||
`status` int NOT NULL DEFAULT 1,
|
`status` int NOT NULL DEFAULT 1,
|
||||||
@ -52,7 +53,8 @@ CREATE TABLE IF NOT EXISTS `admin_user` (
|
|||||||
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `uk_admin_user_username` (`username`)
|
UNIQUE KEY `uk_admin_user_username` (`username`),
|
||||||
|
KEY `idx_admin_user_dept_id` (`dept_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `admin_dept` (
|
CREATE TABLE IF NOT EXISTS `admin_dept` (
|
||||||
@ -68,6 +70,38 @@ CREATE TABLE IF NOT EXISTS `admin_dept` (
|
|||||||
KEY `idx_admin_dept_pid` (`pid`)
|
KEY `idx_admin_dept_pid` (`pid`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
SET @admin_user_dept_id_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = 'admin_user'
|
||||||
|
AND COLUMN_NAME = 'dept_id'
|
||||||
|
);
|
||||||
|
SET @admin_user_dept_id_sql := IF(
|
||||||
|
@admin_user_dept_id_exists = 0,
|
||||||
|
'ALTER TABLE `admin_user` ADD COLUMN `dept_id` bigint NULL AFTER `real_name`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE admin_user_dept_id_stmt FROM @admin_user_dept_id_sql;
|
||||||
|
EXECUTE admin_user_dept_id_stmt;
|
||||||
|
DEALLOCATE PREPARE admin_user_dept_id_stmt;
|
||||||
|
|
||||||
|
SET @admin_user_dept_idx_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM INFORMATION_SCHEMA.STATISTICS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = 'admin_user'
|
||||||
|
AND INDEX_NAME = 'idx_admin_user_dept_id'
|
||||||
|
);
|
||||||
|
SET @admin_user_dept_idx_sql := IF(
|
||||||
|
@admin_user_dept_idx_exists = 0,
|
||||||
|
'ALTER TABLE `admin_user` ADD INDEX `idx_admin_user_dept_id` (`dept_id`)',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE admin_user_dept_idx_stmt FROM @admin_user_dept_idx_sql;
|
||||||
|
EXECUTE admin_user_dept_idx_stmt;
|
||||||
|
DEALLOCATE PREPARE admin_user_dept_idx_stmt;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `admin_dict` (
|
CREATE TABLE IF NOT EXISTS `admin_dict` (
|
||||||
`id` bigint NOT NULL,
|
`id` bigint NOT NULL,
|
||||||
`dict_code` varchar(255) NOT NULL,
|
`dict_code` varchar(255) NOT NULL,
|
||||||
@ -125,19 +159,23 @@ VALUES
|
|||||||
(2041700000000100101, 2041700000000100001, 'Analytics', '/analytics', '/dashboard/analytics/index', NULL, NULL, 'menu', '{"affixTab":true,"title":"page.dashboard.analytics"}', 1, 0),
|
(2041700000000100101, 2041700000000100001, 'Analytics', '/analytics', '/dashboard/analytics/index', NULL, NULL, 'menu', '{"affixTab":true,"title":"page.dashboard.analytics"}', 1, 0),
|
||||||
(2041700000000100102, 2041700000000100001, 'Workspace', '/workspace', '/dashboard/workspace/index', NULL, NULL, 'menu', '{"icon":"carbon:workspace","title":"page.dashboard.workspace"}', 1, 0),
|
(2041700000000100102, 2041700000000100001, 'Workspace', '/workspace', '/dashboard/workspace/index', NULL, NULL, 'menu', '{"icon":"carbon:workspace","title":"page.dashboard.workspace"}', 1, 0),
|
||||||
(2041700000000100002, 0, 'System', '/system', NULL, NULL, NULL, 'catalog', '{"badge":"new","badgeType":"normal","badgeVariants":"primary","icon":"carbon:settings","order":9997,"title":"system.title"}', 1, 9997),
|
(2041700000000100002, 0, 'System', '/system', NULL, NULL, NULL, 'catalog', '{"badge":"new","badgeType":"normal","badgeVariants":"primary","icon":"carbon:settings","order":9997,"title":"system.title"}', 1, 9997),
|
||||||
(2041700000000100200, 2041700000000100002, 'SystemRole', '/system/role', '/system/role/list', NULL, 'System:Role:List', 'menu', '{"icon":"carbon:user-role","title":"system.role.title"}', 1, 0),
|
(2041700000000100199, 2041700000000100002, 'SystemUser', '/system/user', '/system/user/list', NULL, 'System:User:List', 'menu', '{"icon":"carbon:user-profile","title":"system.user.title"}', 1, 0),
|
||||||
|
(2041700000000120191, 2041700000000100199, 'SystemUserCreate', NULL, NULL, NULL, 'System:User:Create', 'button', '{"title":"common.create"}', 1, 0),
|
||||||
|
(2041700000000120192, 2041700000000100199, 'SystemUserEdit', NULL, NULL, NULL, 'System:User:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
||||||
|
(2041700000000120193, 2041700000000100199, 'SystemUserDelete', NULL, NULL, NULL, 'System:User:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
||||||
|
(2041700000000100200, 2041700000000100002, 'SystemRole', '/system/role', '/system/role/list', NULL, 'System:Role:List', 'menu', '{"icon":"carbon:user-role","title":"system.role.title"}', 1, 1),
|
||||||
(2041700000000120001, 2041700000000100200, 'SystemRoleCreate', NULL, NULL, NULL, 'System:Role:Create', 'button', '{"title":"common.create"}', 1, 0),
|
(2041700000000120001, 2041700000000100200, 'SystemRoleCreate', NULL, NULL, NULL, 'System:Role:Create', 'button', '{"title":"common.create"}', 1, 0),
|
||||||
(2041700000000120002, 2041700000000100200, 'SystemRoleEdit', NULL, NULL, NULL, 'System:Role:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
(2041700000000120002, 2041700000000100200, 'SystemRoleEdit', NULL, NULL, NULL, 'System:Role:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
||||||
(2041700000000120003, 2041700000000100200, 'SystemRoleDelete', NULL, NULL, NULL, 'System:Role:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
(2041700000000120003, 2041700000000100200, 'SystemRoleDelete', NULL, NULL, NULL, 'System:Role:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
||||||
(2041700000000100201, 2041700000000100002, 'SystemMenu', '/system/menu', '/system/menu/list', NULL, 'System:Menu:List', 'menu', '{"icon":"carbon:menu","title":"system.menu.title"}', 1, 0),
|
(2041700000000100201, 2041700000000100002, 'SystemMenu', '/system/menu', '/system/menu/list', NULL, 'System:Menu:List', 'menu', '{"icon":"carbon:menu","title":"system.menu.title"}', 1, 2),
|
||||||
(2041700000000120101, 2041700000000100201, 'SystemMenuCreate', NULL, NULL, NULL, 'System:Menu:Create', 'button', '{"title":"common.create"}', 1, 0),
|
(2041700000000120101, 2041700000000100201, 'SystemMenuCreate', NULL, NULL, NULL, 'System:Menu:Create', 'button', '{"title":"common.create"}', 1, 0),
|
||||||
(2041700000000120102, 2041700000000100201, 'SystemMenuEdit', NULL, NULL, NULL, 'System:Menu:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
(2041700000000120102, 2041700000000100201, 'SystemMenuEdit', NULL, NULL, NULL, 'System:Menu:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
||||||
(2041700000000120103, 2041700000000100201, 'SystemMenuDelete', NULL, NULL, NULL, 'System:Menu:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
(2041700000000120103, 2041700000000100201, 'SystemMenuDelete', NULL, NULL, NULL, 'System:Menu:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
||||||
(2041700000000100202, 2041700000000100002, 'SystemDept', '/system/dept', '/system/dept/list', NULL, 'System:Dept:List', 'menu', '{"icon":"carbon:container-services","title":"system.dept.title"}', 1, 0),
|
(2041700000000100202, 2041700000000100002, 'SystemDept', '/system/dept', '/system/dept/list', NULL, 'System:Dept:List', 'menu', '{"icon":"carbon:container-services","title":"system.dept.title"}', 1, 3),
|
||||||
(2041700000000120201, 2041700000000100202, 'SystemDeptCreate', NULL, NULL, NULL, 'System:Dept:Create', 'button', '{"title":"common.create"}', 1, 0),
|
(2041700000000120201, 2041700000000100202, 'SystemDeptCreate', NULL, NULL, NULL, 'System:Dept:Create', 'button', '{"title":"common.create"}', 1, 0),
|
||||||
(2041700000000120202, 2041700000000100202, 'SystemDeptEdit', NULL, NULL, NULL, 'System:Dept:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
(2041700000000120202, 2041700000000100202, 'SystemDeptEdit', NULL, NULL, NULL, 'System:Dept:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
||||||
(2041700000000120203, 2041700000000100202, 'SystemDeptDelete', NULL, NULL, NULL, 'System:Dept:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
(2041700000000120203, 2041700000000100202, 'SystemDeptDelete', NULL, NULL, NULL, 'System:Dept:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
||||||
(2041700000000100203, 2041700000000100002, 'SystemKtTableDemo', '/system/ktTableDemo', '/system/ktTableDemo/list', NULL, 'System:KtTableDemo:List', 'menu', '{"icon":"lucide:table-2","title":"system.ktTableDemo.title"}', 1, 3),
|
(2041700000000100203, 2041700000000100002, 'SystemKtTableDemo', '/system/ktTableDemo', '/system/ktTableDemo/list', NULL, 'System:KtTableDemo:List', 'menu', '{"icon":"lucide:table-2","title":"system.ktTableDemo.title"}', 1, 4),
|
||||||
(2041700000000120204, 2041700000000100203, 'SystemKtTableDemoCreate', NULL, NULL, NULL, 'System:KtTableDemo:Create', 'button', '{"title":"common.create"}', 1, 0),
|
(2041700000000120204, 2041700000000100203, 'SystemKtTableDemoCreate', NULL, NULL, NULL, 'System:KtTableDemo:Create', 'button', '{"title":"common.create"}', 1, 0),
|
||||||
(2041700000000120205, 2041700000000100203, 'SystemKtTableDemoEdit', NULL, NULL, NULL, 'System:KtTableDemo:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
(2041700000000120205, 2041700000000100203, 'SystemKtTableDemoEdit', NULL, NULL, NULL, 'System:KtTableDemo:Edit', 'button', '{"title":"common.edit"}', 1, 0),
|
||||||
(2041700000000120206, 2041700000000100203, 'SystemKtTableDemoDelete', NULL, NULL, NULL, 'System:KtTableDemo:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
(2041700000000120206, 2041700000000100203, 'SystemKtTableDemoDelete', NULL, NULL, NULL, 'System:KtTableDemo:Delete', 'button', '{"title":"common.delete"}', 1, 0),
|
||||||
@ -181,14 +219,15 @@ ON DUPLICATE KEY UPDATE
|
|||||||
`status` = VALUES(`status`),
|
`status` = VALUES(`status`),
|
||||||
`is_deleted` = 0;
|
`is_deleted` = 0;
|
||||||
|
|
||||||
INSERT INTO `admin_user` (`id`, `username`, `password`, `real_name`, `home_path`, `timezone`, `status`)
|
INSERT INTO `admin_user` (`id`, `username`, `password`, `real_name`, `dept_id`, `home_path`, `timezone`, `status`)
|
||||||
VALUES
|
VALUES
|
||||||
(2041700000000000001, 'vben', '123456', 'Vben', '/workspace', 'Asia/Shanghai', 1),
|
(2041700000000000001, 'vben', '123456', 'Vben', 2041700000000200002, '/workspace', 'Asia/Shanghai', 1),
|
||||||
(2041700000000000002, 'admin', '123456', 'Admin', '/workspace', 'Asia/Shanghai', 1),
|
(2041700000000000002, 'admin', '123456', 'Admin', 2041700000000200001, '/workspace', 'Asia/Shanghai', 1),
|
||||||
(2041700000000000003, 'jack', '123456', 'Jack', '/analytics', 'Asia/Shanghai', 1)
|
(2041700000000000003, 'jack', '123456', 'Jack', 2041700000000200003, '/analytics', 'Asia/Shanghai', 1)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
`password` = VALUES(`password`),
|
`password` = VALUES(`password`),
|
||||||
`real_name` = VALUES(`real_name`),
|
`real_name` = VALUES(`real_name`),
|
||||||
|
`dept_id` = VALUES(`dept_id`),
|
||||||
`home_path` = VALUES(`home_path`),
|
`home_path` = VALUES(`home_path`),
|
||||||
`timezone` = VALUES(`timezone`),
|
`timezone` = VALUES(`timezone`),
|
||||||
`status` = VALUES(`status`),
|
`status` = VALUES(`status`),
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { AdminRole } from './role/admin-role.entity';
|
|||||||
import { AdminRoleService } from './role/admin-role.service';
|
import { AdminRoleService } from './role/admin-role.service';
|
||||||
import { AdminTimezoneController } from './timezone/admin-timezone.controller';
|
import { AdminTimezoneController } from './timezone/admin-timezone.controller';
|
||||||
import { AdminTimezoneService } from './timezone/admin-timezone.service';
|
import { AdminTimezoneService } from './timezone/admin-timezone.service';
|
||||||
|
import { AdminUserManageController } from './user/admin-user-manage.controller';
|
||||||
import { AdminUserController } from './user/admin-user.controller';
|
import { AdminUserController } from './user/admin-user.controller';
|
||||||
import { AdminUser } from './user/admin-user.entity';
|
import { AdminUser } from './user/admin-user.entity';
|
||||||
import { AdminUserService } from './user/admin-user.service';
|
import { AdminUserService } from './user/admin-user.service';
|
||||||
@ -42,6 +43,7 @@ import { WordpressModule } from '@/wordpress/wordpress.module';
|
|||||||
controllers: [
|
controllers: [
|
||||||
AdminAuthController,
|
AdminAuthController,
|
||||||
AdminUserController,
|
AdminUserController,
|
||||||
|
AdminUserManageController,
|
||||||
AdminMenuController,
|
AdminMenuController,
|
||||||
AdminRoleController,
|
AdminRoleController,
|
||||||
AdminDeptController,
|
AdminDeptController,
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
Res,
|
Res,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import { CurrentAdminUser, Public, vbenSuccess } from '@/common';
|
import { CurrentAdminUser, Public, vbenSuccess } from '@/common';
|
||||||
import { AdminMenuService } from '../menu/admin-menu.service';
|
import { AdminMenuService } from '../menu/admin-menu.service';
|
||||||
@ -29,6 +29,7 @@ export class AdminAuthController {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('auth/login')
|
@Post('auth/login')
|
||||||
|
@ApiOperation({ summary: 'Admin 用户登录' })
|
||||||
@Public()
|
@Public()
|
||||||
async login(
|
async login(
|
||||||
@Body() body: { password?: string; username?: string },
|
@Body() body: { password?: string; username?: string },
|
||||||
@ -63,6 +64,7 @@ export class AdminAuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post('auth/refresh')
|
@Post('auth/refresh')
|
||||||
|
@ApiOperation({ summary: '刷新 Admin 访问令牌' })
|
||||||
@Public()
|
@Public()
|
||||||
async refresh(
|
async refresh(
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@ -76,6 +78,7 @@ export class AdminAuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post('auth/logout')
|
@Post('auth/logout')
|
||||||
|
@ApiOperation({ summary: 'Admin 用户退出登录' })
|
||||||
@Public()
|
@Public()
|
||||||
logout(@Res({ passthrough: true }) res: Response) {
|
logout(@Res({ passthrough: true }) res: Response) {
|
||||||
this.authService.clearAccessTokenCookie(res);
|
this.authService.clearAccessTokenCookie(res);
|
||||||
@ -85,6 +88,7 @@ export class AdminAuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('auth/codes')
|
@Get('auth/codes')
|
||||||
|
@ApiOperation({ summary: '获取当前用户按钮权限码' })
|
||||||
async getAccessCodes(@CurrentAdminUser() user: AdminUser) {
|
async getAccessCodes(@CurrentAdminUser() user: AdminUser) {
|
||||||
return vbenSuccess(await this.menuService.getAccessCodes(user));
|
return vbenSuccess(await this.menuService.getAccessCodes(user));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import {
|
|||||||
Put,
|
Put,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { vbenSuccess } from '@/common';
|
import { vbenSuccess } from '@/common';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { AdminDept } from './admin-dept.entity';
|
import { AdminDept } from './admin-dept.entity';
|
||||||
@ -21,16 +21,19 @@ export class AdminDeptController {
|
|||||||
constructor(private readonly deptService: AdminDeptService) {}
|
constructor(private readonly deptService: AdminDeptService) {}
|
||||||
|
|
||||||
@Get('list')
|
@Get('list')
|
||||||
|
@ApiOperation({ summary: '获取部门列表' })
|
||||||
async list() {
|
async list() {
|
||||||
return vbenSuccess(await this.deptService.getDeptList());
|
return vbenSuccess(await this.deptService.getDeptList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
|
@ApiOperation({ summary: '新增部门' })
|
||||||
async create(@Body() body: Partial<AdminDept>) {
|
async create(@Body() body: Partial<AdminDept>) {
|
||||||
return vbenSuccess(await this.deptService.createDept(body));
|
return vbenSuccess(await this.deptService.createDept(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put(':id')
|
@Put(':id')
|
||||||
|
@ApiOperation({ summary: '编辑部门' })
|
||||||
async update(
|
async update(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() body: Partial<AdminDept>,
|
@Body() body: Partial<AdminDept>,
|
||||||
@ -39,6 +42,7 @@ export class AdminDeptController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
|
@ApiOperation({ summary: '删除部门' })
|
||||||
async remove(@Param('id') id: string) {
|
async remove(@Param('id') id: string) {
|
||||||
return vbenSuccess(await this.deptService.deleteDept(id));
|
return vbenSuccess(await this.deptService.deleteDept(id));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
UseInterceptors,
|
UseInterceptors,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FileInterceptor } from '@nestjs/platform-express';
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { Public, vbenPage, vbenSuccess } from '@/common';
|
import { Public, vbenPage, vbenSuccess } from '@/common';
|
||||||
@ -73,6 +73,7 @@ export class AdminExampleController {
|
|||||||
constructor(private readonly minioClientService: MinioClientService) {}
|
constructor(private readonly minioClientService: MinioClientService) {}
|
||||||
|
|
||||||
@Post('upload')
|
@Post('upload')
|
||||||
|
@ApiOperation({ summary: '上传示例文件' })
|
||||||
@UseInterceptors(FileInterceptor('file'))
|
@UseInterceptors(FileInterceptor('file'))
|
||||||
async upload(@UploadedFile() file: MinioUploadFile) {
|
async upload(@UploadedFile() file: MinioUploadFile) {
|
||||||
const result = await this.minioClientService.uploadObject({ file });
|
const result = await this.minioClientService.uploadObject({ file });
|
||||||
@ -83,6 +84,7 @@ export class AdminExampleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('table/list')
|
@Get('table/list')
|
||||||
|
@ApiOperation({ summary: '获取示例表格分页列表' })
|
||||||
async tableList(
|
async tableList(
|
||||||
@Query() query: Record<string, any>,
|
@Query() query: Record<string, any>,
|
||||||
) {
|
) {
|
||||||
@ -95,6 +97,7 @@ export class AdminExampleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('status')
|
@Get('status')
|
||||||
|
@ApiOperation({ summary: '返回指定状态码示例' })
|
||||||
@Public()
|
@Public()
|
||||||
status(@Query('status') status: string, @Res() res: Response) {
|
status(@Query('status') status: string, @Res() res: Response) {
|
||||||
const code = Number(status) || 200;
|
const code = Number(status) || 200;
|
||||||
@ -112,6 +115,7 @@ export class AdminExampleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('demo/bigint')
|
@Get('demo/bigint')
|
||||||
|
@ApiOperation({ summary: '获取 BigInt 序列化示例' })
|
||||||
async bigint(@Res() res: Response) {
|
async bigint(@Res() res: Response) {
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.send(`{
|
res.send(`{
|
||||||
@ -135,12 +139,14 @@ export class AdminExampleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('test')
|
@Get('test')
|
||||||
|
@ApiOperation({ summary: 'GET 测试接口' })
|
||||||
@Public()
|
@Public()
|
||||||
testGet() {
|
testGet() {
|
||||||
return vbenSuccess('Test get handler');
|
return vbenSuccess('Test get handler');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('test')
|
@Post('test')
|
||||||
|
@ApiOperation({ summary: 'POST 测试接口' })
|
||||||
@Public()
|
@Public()
|
||||||
testPost() {
|
testPost() {
|
||||||
return vbenSuccess('Test post handler');
|
return vbenSuccess('Test post handler');
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { AdminUser } from '../user/admin-user.entity';
|
import { AdminUser } from '../user/admin-user.entity';
|
||||||
@ -23,16 +23,19 @@ export class AdminMenuController {
|
|||||||
constructor(private readonly menuService: AdminMenuService) {}
|
constructor(private readonly menuService: AdminMenuService) {}
|
||||||
|
|
||||||
@Get('menu/all')
|
@Get('menu/all')
|
||||||
|
@ApiOperation({ summary: '获取当前用户路由菜单' })
|
||||||
async all(@CurrentAdminUser() user: AdminUser) {
|
async all(@CurrentAdminUser() user: AdminUser) {
|
||||||
return vbenSuccess(await this.menuService.getRouteMenus(user));
|
return vbenSuccess(await this.menuService.getRouteMenus(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('system/menu/list')
|
@Get('system/menu/list')
|
||||||
|
@ApiOperation({ summary: '获取系统菜单列表' })
|
||||||
async list() {
|
async list() {
|
||||||
return vbenSuccess(await this.menuService.getMenuList());
|
return vbenSuccess(await this.menuService.getMenuList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('system/menu/name-exists')
|
@Get('system/menu/name-exists')
|
||||||
|
@ApiOperation({ summary: '校验菜单名称是否存在' })
|
||||||
async nameExists(
|
async nameExists(
|
||||||
@Query('name') name: string,
|
@Query('name') name: string,
|
||||||
@Query('id') id?: string,
|
@Query('id') id?: string,
|
||||||
@ -41,6 +44,7 @@ export class AdminMenuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('system/menu/path-exists')
|
@Get('system/menu/path-exists')
|
||||||
|
@ApiOperation({ summary: '校验菜单路径是否存在' })
|
||||||
async pathExists(
|
async pathExists(
|
||||||
@Query('path') path: string,
|
@Query('path') path: string,
|
||||||
@Query('id') id?: string,
|
@Query('id') id?: string,
|
||||||
@ -49,11 +53,13 @@ export class AdminMenuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post('system/menu')
|
@Post('system/menu')
|
||||||
|
@ApiOperation({ summary: '新增系统菜单' })
|
||||||
async create(@Body() body: Partial<AdminMenu>) {
|
async create(@Body() body: Partial<AdminMenu>) {
|
||||||
return vbenSuccess(await this.menuService.createMenu(body));
|
return vbenSuccess(await this.menuService.createMenu(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put('system/menu/:id')
|
@Put('system/menu/:id')
|
||||||
|
@ApiOperation({ summary: '编辑系统菜单' })
|
||||||
async update(
|
async update(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() body: Partial<AdminMenu>,
|
@Body() body: Partial<AdminMenu>,
|
||||||
@ -62,6 +68,7 @@ export class AdminMenuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete('system/menu/:id')
|
@Delete('system/menu/:id')
|
||||||
|
@ApiOperation({ summary: '删除系统菜单' })
|
||||||
async remove(@Param('id') id: string) {
|
async remove(@Param('id') id: string) {
|
||||||
return vbenSuccess(await this.menuService.deleteMenu(id));
|
return vbenSuccess(await this.menuService.deleteMenu(id));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { vbenPage, vbenSuccess } from '@/common';
|
import { vbenPage, vbenSuccess } from '@/common';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { AdminRoleService } from './admin-role.service';
|
import { AdminRoleService } from './admin-role.service';
|
||||||
@ -21,17 +21,20 @@ export class AdminRoleController {
|
|||||||
constructor(private readonly roleService: AdminRoleService) {}
|
constructor(private readonly roleService: AdminRoleService) {}
|
||||||
|
|
||||||
@Get('list')
|
@Get('list')
|
||||||
|
@ApiOperation({ summary: '获取角色分页列表' })
|
||||||
async list(@Query() query: Record<string, any>) {
|
async list(@Query() query: Record<string, any>) {
|
||||||
const page = await this.roleService.getRoleList(query);
|
const page = await this.roleService.getRoleList(query);
|
||||||
return vbenPage(page.items, page.total);
|
return vbenPage(page.items, page.total);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
|
@ApiOperation({ summary: '新增角色' })
|
||||||
async create(@Body() body: Record<string, any>) {
|
async create(@Body() body: Record<string, any>) {
|
||||||
return vbenSuccess(await this.roleService.createRole(body));
|
return vbenSuccess(await this.roleService.createRole(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put(':id')
|
@Put(':id')
|
||||||
|
@ApiOperation({ summary: '编辑角色' })
|
||||||
async update(
|
async update(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() body: Record<string, any>,
|
@Body() body: Record<string, any>,
|
||||||
@ -40,6 +43,7 @@ export class AdminRoleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
|
@ApiOperation({ summary: '删除角色' })
|
||||||
async remove(@Param('id') id: string) {
|
async remove(@Param('id') id: string) {
|
||||||
return vbenSuccess(await this.roleService.deleteRole(id));
|
return vbenSuccess(await this.roleService.deleteRole(id));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { AdminUser } from '../user/admin-user.entity';
|
import { AdminUser } from '../user/admin-user.entity';
|
||||||
@ -20,16 +20,19 @@ export class AdminTimezoneController {
|
|||||||
constructor(private readonly timezoneService: AdminTimezoneService) {}
|
constructor(private readonly timezoneService: AdminTimezoneService) {}
|
||||||
|
|
||||||
@Get('getTimezoneOptions')
|
@Get('getTimezoneOptions')
|
||||||
|
@ApiOperation({ summary: '获取时区选项' })
|
||||||
getOptions() {
|
getOptions() {
|
||||||
return vbenSuccess(TIMEZONE_OPTIONS);
|
return vbenSuccess(TIMEZONE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('getTimezone')
|
@Get('getTimezone')
|
||||||
|
@ApiOperation({ summary: '获取当前用户时区' })
|
||||||
async getTimezone(@CurrentAdminUser() user: AdminUser) {
|
async getTimezone(@CurrentAdminUser() user: AdminUser) {
|
||||||
return vbenSuccess(await this.timezoneService.getTimezone(user));
|
return vbenSuccess(await this.timezoneService.getTimezone(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('setTimezone')
|
@Post('setTimezone')
|
||||||
|
@ApiOperation({ summary: '设置当前用户时区' })
|
||||||
async setTimezone(
|
async setTimezone(
|
||||||
@CurrentAdminUser() user: AdminUser,
|
@CurrentAdminUser() user: AdminUser,
|
||||||
@Body() body: { timezone?: string },
|
@Body() body: { timezone?: string },
|
||||||
|
|||||||
51
src/admin/user/admin-user-manage.controller.ts
Normal file
51
src/admin/user/admin-user-manage.controller.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Query,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CurrentAdminUser, vbenPage, vbenSuccess } from '@/common';
|
||||||
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
|
import { AdminUser } from './admin-user.entity';
|
||||||
|
import { AdminUserService } from './admin-user.service';
|
||||||
|
|
||||||
|
@ApiTags('Admin - 用户管理')
|
||||||
|
@Controller('system/user')
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
export class AdminUserManageController {
|
||||||
|
constructor(private readonly userService: AdminUserService) {}
|
||||||
|
|
||||||
|
@Get('list')
|
||||||
|
@ApiOperation({ summary: '获取用户分页列表' })
|
||||||
|
async list(@Query() query: Record<string, any>) {
|
||||||
|
const page = await this.userService.getUserList(query);
|
||||||
|
return vbenPage(page.items, page.total);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({ summary: '新增用户' })
|
||||||
|
async create(@Body() body: Record<string, any>) {
|
||||||
|
return vbenSuccess(await this.userService.createUser(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put(':id')
|
||||||
|
@ApiOperation({ summary: '编辑用户' })
|
||||||
|
async update(@Param('id') id: string, @Body() body: Record<string, any>) {
|
||||||
|
return vbenSuccess(await this.userService.updateUser(id, body));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@ApiOperation({ summary: '删除用户' })
|
||||||
|
async remove(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@CurrentAdminUser() currentUser: AdminUser,
|
||||||
|
) {
|
||||||
|
return vbenSuccess(await this.userService.deleteUser(id, currentUser?.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
import { CurrentAdminUser, vbenSuccess } from '@/common';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { AdminUser } from './admin-user.entity';
|
import { AdminUser } from './admin-user.entity';
|
||||||
@ -12,6 +12,7 @@ export class AdminUserController {
|
|||||||
constructor(private readonly userService: AdminUserService) {}
|
constructor(private readonly userService: AdminUserService) {}
|
||||||
|
|
||||||
@Get('info')
|
@Get('info')
|
||||||
|
@ApiOperation({ summary: '获取当前用户信息' })
|
||||||
async info(@CurrentAdminUser() user: AdminUser) {
|
async info(@CurrentAdminUser() user: AdminUser) {
|
||||||
return vbenSuccess(this.userService.serializeUser(user));
|
return vbenSuccess(this.userService.serializeUser(user));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,15 @@ import {
|
|||||||
Column,
|
Column,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
|
JoinColumn,
|
||||||
JoinTable,
|
JoinTable,
|
||||||
ManyToMany,
|
ManyToMany,
|
||||||
|
ManyToOne,
|
||||||
PrimaryColumn,
|
PrimaryColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { ensureSnowflakeId } from '@/common';
|
import { ensureSnowflakeId } from '@/common';
|
||||||
|
import { AdminDept } from '../dept/admin-dept.entity';
|
||||||
import { AdminRole } from '../role/admin-role.entity';
|
import { AdminRole } from '../role/admin-role.entity';
|
||||||
|
|
||||||
@Entity('admin_user')
|
@Entity('admin_user')
|
||||||
@ -31,6 +34,13 @@ export class AdminUser {
|
|||||||
})
|
})
|
||||||
realName: string;
|
realName: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
name: 'dept_id',
|
||||||
|
nullable: true,
|
||||||
|
type: 'bigint',
|
||||||
|
})
|
||||||
|
deptId?: string | null;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
default: '',
|
default: '',
|
||||||
name: 'home_path',
|
name: 'home_path',
|
||||||
@ -79,6 +89,15 @@ export class AdminUser {
|
|||||||
})
|
})
|
||||||
roles: AdminRole[];
|
roles: AdminRole[];
|
||||||
|
|
||||||
|
@ManyToOne(() => AdminDept, {
|
||||||
|
eager: true,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
@JoinColumn({
|
||||||
|
name: 'dept_id',
|
||||||
|
})
|
||||||
|
dept?: AdminDept | null;
|
||||||
|
|
||||||
@BeforeInsert()
|
@BeforeInsert()
|
||||||
createId() {
|
createId() {
|
||||||
ensureSnowflakeId(this);
|
ensureSnowflakeId(this);
|
||||||
|
|||||||
@ -1,8 +1,152 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Not, Repository } from 'typeorm';
|
||||||
|
import { throwVbenError } from '@/common';
|
||||||
|
import { AdminDept } from '../dept/admin-dept.entity';
|
||||||
|
import { AdminRole } from '../role/admin-role.entity';
|
||||||
import { AdminUser } from './admin-user.entity';
|
import { AdminUser } from './admin-user.entity';
|
||||||
|
|
||||||
|
type UserInput = Partial<AdminUser> & {
|
||||||
|
roleIds?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type ListQuery = Record<string, any>;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminUserService {
|
export class AdminUserService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(AdminUser)
|
||||||
|
private readonly userRepository: Repository<AdminUser>,
|
||||||
|
@InjectRepository(AdminRole)
|
||||||
|
private readonly roleRepository: Repository<AdminRole>,
|
||||||
|
@InjectRepository(AdminDept)
|
||||||
|
private readonly deptRepository: Repository<AdminDept>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async getUserList(query: ListQuery) {
|
||||||
|
const page = Number(query.page || 1);
|
||||||
|
const pageSize = Number(query.pageSize || 20);
|
||||||
|
const builder = this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.leftJoinAndSelect('user.roles', 'role')
|
||||||
|
.leftJoinAndSelect('user.dept', 'dept')
|
||||||
|
.where('user.isDeleted = :isDeleted', { isDeleted: false });
|
||||||
|
|
||||||
|
if (query.id) {
|
||||||
|
builder.andWhere('user.id LIKE :id', { id: `%${query.id}%` });
|
||||||
|
}
|
||||||
|
if (query.username) {
|
||||||
|
builder.andWhere('user.username LIKE :username', {
|
||||||
|
username: `%${query.username}%`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (query.realName) {
|
||||||
|
builder.andWhere('user.realName LIKE :realName', {
|
||||||
|
realName: `%${query.realName}%`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (['0', '1'].includes(String(query.status))) {
|
||||||
|
builder.andWhere('user.status = :status', {
|
||||||
|
status: Number(query.status),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (query.deptId) {
|
||||||
|
const deptIds = await this.collectDeptIds(String(query.deptId));
|
||||||
|
builder.andWhere('user.deptId IN (:...deptIds)', { deptIds });
|
||||||
|
}
|
||||||
|
if (query.roleId) {
|
||||||
|
builder.andWhere('role.id = :roleId', { roleId: String(query.roleId) });
|
||||||
|
}
|
||||||
|
if (query.startTime) {
|
||||||
|
builder.andWhere('user.createTime >= :startTime', {
|
||||||
|
startTime: query.startTime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (query.endTime) {
|
||||||
|
builder.andWhere('user.createTime <= :endTime', {
|
||||||
|
endTime: query.endTime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const [users, total] = await builder
|
||||||
|
.orderBy('user.createTime', 'ASC')
|
||||||
|
.skip((page - 1) * pageSize)
|
||||||
|
.take(pageSize)
|
||||||
|
.getManyAndCount();
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: users.map((user) => this.serializeUserForList(user)),
|
||||||
|
total,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async createUser(data: UserInput) {
|
||||||
|
await this.ensureUsernameAvailable(String(data.username || ''));
|
||||||
|
|
||||||
|
const user = this.userRepository.create({
|
||||||
|
deptId: data.deptId || null,
|
||||||
|
homePath: data.homePath || '/workspace',
|
||||||
|
password: data.password || '123456',
|
||||||
|
realName: data.realName,
|
||||||
|
status: data.status ?? 1,
|
||||||
|
timezone: data.timezone || 'Asia/Shanghai',
|
||||||
|
username: data.username,
|
||||||
|
});
|
||||||
|
user.roles = await this.findRolesByIds(data.roleIds || []);
|
||||||
|
await this.userRepository.save(user);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateUser(id: string, data: UserInput) {
|
||||||
|
const user = await this.userRepository.findOne({
|
||||||
|
relations: ['roles'],
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
isDeleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) throwVbenError('用户不存在', HttpStatus.BAD_REQUEST);
|
||||||
|
|
||||||
|
if (data.username !== undefined && data.username !== user.username) {
|
||||||
|
await this.ensureUsernameAvailable(data.username, id);
|
||||||
|
user.username = data.username;
|
||||||
|
}
|
||||||
|
if (data.password) user.password = data.password;
|
||||||
|
if (data.deptId !== undefined) user.deptId = data.deptId || null;
|
||||||
|
if (data.realName !== undefined) user.realName = data.realName;
|
||||||
|
if (data.homePath !== undefined) user.homePath = data.homePath;
|
||||||
|
if (data.timezone !== undefined) user.timezone = data.timezone;
|
||||||
|
if (data.status !== undefined) user.status = data.status;
|
||||||
|
if (data.roleIds) user.roles = await this.findRolesByIds(data.roleIds);
|
||||||
|
|
||||||
|
await this.userRepository.save(user);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteUser(id: string, currentUserId?: string) {
|
||||||
|
const user = await this.userRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
isDeleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) throwVbenError('用户不存在', HttpStatus.BAD_REQUEST);
|
||||||
|
if (id === currentUserId) {
|
||||||
|
throwVbenError('不能删除当前登录用户', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (user.username === 'admin') {
|
||||||
|
throwVbenError('不能删除内置管理员账号', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.userRepository.update(
|
||||||
|
{ id },
|
||||||
|
{
|
||||||
|
isDeleted: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
serializeUser(user: AdminUser) {
|
serializeUser(user: AdminUser) {
|
||||||
return {
|
return {
|
||||||
homePath: user.homePath,
|
homePath: user.homePath,
|
||||||
@ -14,4 +158,88 @@ export class AdminUserService {
|
|||||||
username: user.username,
|
username: user.username,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private serializeUserForList(user: AdminUser) {
|
||||||
|
const activeRoles = (user.roles || []).filter((role) => !role.isDeleted);
|
||||||
|
return {
|
||||||
|
createTime: user.createTime,
|
||||||
|
dept: user.dept
|
||||||
|
? {
|
||||||
|
id: user.dept.id,
|
||||||
|
name: user.dept.name,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
deptId: user.deptId,
|
||||||
|
deptName: user.dept?.name || '',
|
||||||
|
homePath: user.homePath,
|
||||||
|
id: user.id,
|
||||||
|
realName: user.realName,
|
||||||
|
roleIds: activeRoles.map((role) => role.id),
|
||||||
|
roleNames: activeRoles.map((role) => role.name),
|
||||||
|
roles: activeRoles.map((role) => ({
|
||||||
|
id: role.id,
|
||||||
|
name: role.name,
|
||||||
|
roleCode: role.roleCode,
|
||||||
|
status: role.status,
|
||||||
|
})),
|
||||||
|
status: user.status,
|
||||||
|
timezone: user.timezone,
|
||||||
|
updateTime: user.updateTime,
|
||||||
|
username: user.username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findRolesByIds(ids: string[]) {
|
||||||
|
const normalizedIds = ids.map((id) => String(id)).filter(Boolean);
|
||||||
|
if (!normalizedIds.length) return [];
|
||||||
|
return this.roleRepository.find({
|
||||||
|
where: normalizedIds.map((id) => ({
|
||||||
|
id,
|
||||||
|
isDeleted: false,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async collectDeptIds(deptId: string) {
|
||||||
|
if (deptId === '0') return ['0'];
|
||||||
|
|
||||||
|
const depts = await this.deptRepository.find({
|
||||||
|
where: {
|
||||||
|
isDeleted: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const result = new Set<string>([deptId]);
|
||||||
|
let changed = true;
|
||||||
|
|
||||||
|
while (changed) {
|
||||||
|
changed = false;
|
||||||
|
for (const dept of depts) {
|
||||||
|
if (result.has(String(dept.pid)) && !result.has(dept.id)) {
|
||||||
|
result.add(dept.id);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ensureUsernameAvailable(username: string, ignoreId?: string) {
|
||||||
|
if (!username.trim()) {
|
||||||
|
throwVbenError('用户名不能为空', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
const where = ignoreId
|
||||||
|
? {
|
||||||
|
id: Not(ignoreId),
|
||||||
|
username,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
username,
|
||||||
|
};
|
||||||
|
const existing = await this.userRepository.findOne({ where });
|
||||||
|
if (existing) {
|
||||||
|
throwVbenError('用户名已存在', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,10 @@ import {
|
|||||||
ApiOperation,
|
ApiOperation,
|
||||||
ApiTags,
|
ApiTags,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { AppService } from './app.service';
|
|
||||||
|
|
||||||
@ApiTags('基础能力 - 根入口')
|
@ApiTags('基础能力 - 根入口')
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly appService: AppService) {}
|
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@Redirect('/api#/', 301)
|
@Redirect('/api#/', 301)
|
||||||
@ApiOperation({ summary: '重定向到Swagger文档' })
|
@ApiOperation({ summary: '重定向到Swagger文档' })
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { AppModule } from './app.module';
|
|||||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||||
import type { OpenAPIObject } from '@nestjs/swagger';
|
import type { OpenAPIObject } from '@nestjs/swagger';
|
||||||
import { urlencoded, json } from 'express';
|
import { urlencoded, json } from 'express';
|
||||||
import { knife4jSetup } from 'nestjs-knife4j-plus';
|
import { knife4jSetup } from '@kwitsukasa/knife4j-swagger-vue3';
|
||||||
import type { Service } from 'nestjs-knife4j-plus';
|
import type { Service } from '@kwitsukasa/knife4j-swagger-vue3';
|
||||||
import { applySwaggerResponseExamples } from './common';
|
import { applySwaggerResponseExamples } from './common';
|
||||||
|
|
||||||
type SwaggerPathMatcher = (path: string) => boolean;
|
type SwaggerPathMatcher = (path: string) => boolean;
|
||||||
|
|||||||
@ -300,11 +300,11 @@ export class QqbotFf14ClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fuzzyItems = await this.searchItemsByLanguage(keyword, language, '~');
|
const fuzzyItems = await this.searchItemsByLanguage(keyword, language, '~');
|
||||||
const fuzzyItem = this.pickSingleFuzzySearchItem(keyword, fuzzyItems);
|
const fuzzyItem = this.pickSingleFuzzySearchItem(fuzzyItems);
|
||||||
if (fuzzyItem || language === 'en') return fuzzyItem;
|
if (fuzzyItem || language === 'en') return fuzzyItem;
|
||||||
|
|
||||||
const enFuzzyItems = await this.searchItemsByLanguage(keyword, 'en', '~');
|
const enFuzzyItems = await this.searchItemsByLanguage(keyword, 'en', '~');
|
||||||
return this.pickSingleFuzzySearchItem(keyword, enFuzzyItems);
|
return this.pickSingleFuzzySearchItem(enFuzzyItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async searchItemsByLanguage(
|
private async searchItemsByLanguage(
|
||||||
@ -337,10 +337,7 @@ export class QqbotFf14ClientService {
|
|||||||
return items[0];
|
return items[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private pickSingleFuzzySearchItem(
|
private pickSingleFuzzySearchItem(items: XivapiSearchItem[]) {
|
||||||
keyword: string,
|
|
||||||
items: XivapiSearchItem[],
|
|
||||||
) {
|
|
||||||
if (items.length <= 1) return items[0];
|
if (items.length <= 1) return items[0];
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`找到多个相似物品,请输入更完整名称或物品 ID:${this.formatSearchCandidates(
|
`找到多个相似物品,请输入更完整名称或物品 ID:${this.formatSearchCandidates(
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
"ignoreDeprecations": "6.0",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
@ -15,6 +16,8 @@
|
|||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"strictBindCallApply": false,
|
"strictBindCallApply": false,
|
||||||
"forceConsistentCasingInFileNames": false,
|
"forceConsistentCasingInFileNames": false,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": false,
|
"noFallthroughCasesInSwitch": false,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user