Template
调整数据库表的单复数
This commit is contained in:
1 parent
736a41a718
commit
d310a29c03
56 files changed
+45577
-506
No files matched your search
@@ -35,72 +35,72 @@ export default {
|
||||
},
|
||||
|
||||
// 用户管理
|
||||
users: {
|
||||
user: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/users", { params });
|
||||
return await request.get("auth/user", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/users/${id}`);
|
||||
return await request.get(`auth/user/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users", params);
|
||||
return await request.post("auth/user", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/users/${id}`, params);
|
||||
return await request.put(`auth/user/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/users/${id}`);
|
||||
return await request.delete(`auth/user/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-delete", params);
|
||||
return await request.post("auth/user/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-status", params);
|
||||
return await request.post("auth/user/batch-status", params);
|
||||
},
|
||||
},
|
||||
batchDepartment: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/users/batch-department",
|
||||
"auth/user/batch-department",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
batchRoles: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/batch-roles", params);
|
||||
return await request.post("auth/user/batch-roles", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/users/export", params, {
|
||||
return await request.post("auth/user/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/users/import", formData, {
|
||||
return await request.post("auth/user/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/users/download-template", {
|
||||
return await request.get("auth/user/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -108,28 +108,28 @@ export default {
|
||||
},
|
||||
|
||||
// 在线用户管理
|
||||
onlineUsers: {
|
||||
onlineUser: {
|
||||
count: {
|
||||
get: async function () {
|
||||
return await request.get("auth/online-users/count");
|
||||
return await request.get("auth/online-user/count");
|
||||
},
|
||||
},
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/online-users", { params });
|
||||
return await request.get("auth/online-user", { params });
|
||||
},
|
||||
},
|
||||
sessions: {
|
||||
get: async function (userId) {
|
||||
return await request.get(
|
||||
`auth/online-users/${userId}/sessions`,
|
||||
`auth/online-user/${userId}/sessions`,
|
||||
);
|
||||
},
|
||||
},
|
||||
offline: {
|
||||
post: async function (userId, params) {
|
||||
return await request.post(
|
||||
`auth/online-users/${userId}/offline`,
|
||||
`auth/online-user/${userId}/offline`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -137,92 +137,92 @@ export default {
|
||||
offlineAll: {
|
||||
post: async function (userId) {
|
||||
return await request.post(
|
||||
`auth/online-users/${userId}/offline-all`,
|
||||
`auth/online-user/${userId}/offline-all`,
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 角色管理
|
||||
roles: {
|
||||
role: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/roles", { params });
|
||||
return await request.get("auth/role", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("auth/roles/all");
|
||||
return await request.get("auth/role/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/roles/${id}`);
|
||||
return await request.get(`auth/role/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles", params);
|
||||
return await request.post("auth/role", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/roles/${id}`, params);
|
||||
return await request.put(`auth/role/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/roles/${id}`);
|
||||
return await request.delete(`auth/role/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-delete", params);
|
||||
return await request.post("auth/role/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-status", params);
|
||||
return await request.post("auth/role/batch-status", params);
|
||||
},
|
||||
},
|
||||
permissions: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/roles/${id}/permissions`);
|
||||
return await request.get(`auth/role/${id}/permissions`);
|
||||
},
|
||||
post: async function (id, params) {
|
||||
return await request.post(
|
||||
`auth/roles/${id}/permissions`,
|
||||
`auth/role/${id}/permissions`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
copy: {
|
||||
post: async function (id, params) {
|
||||
return await request.post(`auth/roles/${id}/copy`, params);
|
||||
return await request.post(`auth/role/${id}/copy`, params);
|
||||
},
|
||||
},
|
||||
batchCopy: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/batch-copy", params);
|
||||
return await request.post("auth/role/batch-copy", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/roles/export", params, {
|
||||
return await request.post("auth/role/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/roles/import", formData, {
|
||||
return await request.post("auth/role/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/roles/download-template", {
|
||||
return await request.get("auth/role/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -230,46 +230,46 @@ export default {
|
||||
},
|
||||
|
||||
// 权限管理
|
||||
permissions: {
|
||||
permission: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/permissions", { params });
|
||||
return await request.get("auth/permission", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/tree");
|
||||
return await request.get("auth/permission/tree");
|
||||
},
|
||||
},
|
||||
menu: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/menu");
|
||||
return await request.get("auth/permission/menu");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/permissions/${id}`);
|
||||
return await request.get(`auth/permission/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/permissions", params);
|
||||
return await request.post("auth/permission", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/permissions/${id}`, params);
|
||||
return await request.put(`auth/permission/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/permissions/${id}`);
|
||||
return await request.delete(`auth/permission/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/permissions/batch-delete",
|
||||
"auth/permission/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -277,28 +277,28 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/permissions/batch-status",
|
||||
"auth/permission/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/permissions/export", params, {
|
||||
return await request.post("auth/permission/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/permissions/import", formData, {
|
||||
return await request.post("auth/permission/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/permissions/download-template", {
|
||||
return await request.get("auth/permission/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
@@ -306,46 +306,46 @@ export default {
|
||||
},
|
||||
|
||||
// 部门管理
|
||||
departments: {
|
||||
department: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/departments", { params });
|
||||
return await request.get("auth/department", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function (params) {
|
||||
return await request.get("auth/departments/tree", { params });
|
||||
return await request.get("auth/department/tree", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("auth/departments/all");
|
||||
return await request.get("auth/department/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`auth/departments/${id}`);
|
||||
return await request.get(`auth/department/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/departments", params);
|
||||
return await request.post("auth/department", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`auth/departments/${id}`, params);
|
||||
return await request.put(`auth/department/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`auth/departments/${id}`);
|
||||
return await request.delete(`auth/department/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/departments/batch-delete",
|
||||
"auth/department/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -353,28 +353,28 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"auth/departments/batch-status",
|
||||
"auth/department/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
post: async function (params) {
|
||||
return await request.post("auth/departments/export", params, {
|
||||
return await request.post("auth/department/export", params, {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
post: async function (formData) {
|
||||
return await request.post("auth/departments/import", formData, {
|
||||
return await request.post("auth/department/import", formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadTemplate: {
|
||||
get: async function () {
|
||||
return await request.get("auth/departments/download-template", {
|
||||
return await request.get("auth/department/download-template", {
|
||||
responseType: "blob",
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2,46 +2,46 @@ import request from "@/utils/request";
|
||||
|
||||
export default {
|
||||
// 系统配置管理
|
||||
configs: {
|
||||
config: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs", { params });
|
||||
return await request.get("system/setting", { params });
|
||||
},
|
||||
},
|
||||
groups: {
|
||||
get: async function () {
|
||||
return await request.get("system/configs/groups");
|
||||
return await request.get("system/setting/groups");
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/all", { params });
|
||||
return await request.get("system/setting/all", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/configs/${id}`);
|
||||
return await request.get(`system/setting/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/configs", params);
|
||||
return await request.post("system/setting", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/configs/${id}`, params);
|
||||
return await request.put(`system/setting/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/configs/${id}`);
|
||||
return await request.delete(`system/setting/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/configs/batch-delete",
|
||||
"system/setting/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -49,7 +49,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/configs/batch-status",
|
||||
"system/setting/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -57,35 +57,35 @@ export default {
|
||||
},
|
||||
|
||||
// 操作日志管理
|
||||
logs: {
|
||||
log: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs", { params });
|
||||
return await request.get("system/log", { params });
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/logs/${id}`);
|
||||
return await request.get(`system/log/${id}`);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/logs/${id}`);
|
||||
return await request.delete(`system/log/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/logs/batch-delete", params);
|
||||
return await request.post("system/log/batch-delete", params);
|
||||
},
|
||||
},
|
||||
clear: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/logs/clear", params);
|
||||
return await request.post("system/log/clear", params);
|
||||
},
|
||||
},
|
||||
export: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs/export", {
|
||||
return await request.get("system/log/export", {
|
||||
params,
|
||||
responseType: "blob",
|
||||
});
|
||||
@@ -93,47 +93,47 @@ export default {
|
||||
},
|
||||
statistics: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/logs/statistics", { params });
|
||||
return await request.get("system/log/statistics", { params });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 数据字典管理
|
||||
dictionaries: {
|
||||
dictionary: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionaries", { params });
|
||||
return await request.get("system/dictionary", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionaries/all");
|
||||
return await request.get("system/dictionary/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionaries/${id}`);
|
||||
return await request.get(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/dictionaries", params);
|
||||
return await request.post("system/dictionary", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/dictionaries/${id}`, params);
|
||||
return await request.put(`system/dictionary/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/dictionaries/${id}`);
|
||||
return await request.delete(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionaries/batch-delete",
|
||||
"system/dictionary/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionaries/batch-status",
|
||||
"system/dictionary/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -149,7 +149,7 @@ export default {
|
||||
items: {
|
||||
all: {
|
||||
get: async function (code) {
|
||||
return await request.get(`system/dictionaries/code`, {
|
||||
return await request.get(`system/dictionary/code`, {
|
||||
params: { code },
|
||||
});
|
||||
},
|
||||
@@ -158,44 +158,44 @@ export default {
|
||||
},
|
||||
|
||||
// 数据字典项管理
|
||||
dictionaryItems: {
|
||||
dictionaryItem: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionary-items", { params });
|
||||
return await request.get("system/dictionary-item", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionary-items/all");
|
||||
return await request.get("system/dictionary-item/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionary-items/${id}`);
|
||||
return await request.get(`system/dictionary-item/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/dictionary-items", params);
|
||||
return await request.post("system/dictionary-item", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(
|
||||
`system/dictionary-items/${id}`,
|
||||
`system/dictionary-item/${id}`,
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/dictionary-items/${id}`);
|
||||
return await request.delete(`system/dictionary-item/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionary-items/batch-delete",
|
||||
"system/dictionary-item/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -203,7 +203,7 @@ export default {
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/dictionary-items/batch-status",
|
||||
"system/dictionary-item/batch-status",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -211,119 +211,119 @@ export default {
|
||||
},
|
||||
|
||||
// 任务管理
|
||||
tasks: {
|
||||
task: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/tasks", { params });
|
||||
return await request.get("system/task", { params });
|
||||
},
|
||||
},
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/tasks/all");
|
||||
return await request.get("system/task/all");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/tasks/${id}`);
|
||||
return await request.get(`system/task/${id}`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks", params);
|
||||
return await request.post("system/task", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/tasks/${id}`, params);
|
||||
return await request.put(`system/task/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/tasks/${id}`);
|
||||
return await request.delete(`system/task/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks/batch-delete", params);
|
||||
return await request.post("system/task/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/tasks/batch-status", params);
|
||||
return await request.post("system/task/batch-status", params);
|
||||
},
|
||||
},
|
||||
run: {
|
||||
post: async function (id) {
|
||||
return await request.post(`system/tasks/${id}/run`);
|
||||
return await request.post(`system/task/${id}/run`);
|
||||
},
|
||||
},
|
||||
statistics: {
|
||||
get: async function () {
|
||||
return await request.get("system/tasks/statistics");
|
||||
return await request.get("system/task/statistics");
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// 城市数据管理
|
||||
cities: {
|
||||
city: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/cities", { params });
|
||||
return await request.get("system/city", { params });
|
||||
},
|
||||
},
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/tree");
|
||||
return await request.get("system/city/tree");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}`);
|
||||
return await request.get(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
children: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}/children`);
|
||||
get: async function (code) {
|
||||
return await request.get(`system/city/code/${code}/children`);
|
||||
},
|
||||
},
|
||||
provinces: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/provinces");
|
||||
return await request.get("system/city/provinces");
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
get: async function (provinceId) {
|
||||
return await request.get(`system/cities/${provinceId}/cities`);
|
||||
return await request.get(`system/city/${provinceId}/cities`);
|
||||
},
|
||||
},
|
||||
districts: {
|
||||
get: async function (cityId) {
|
||||
return await request.get(`system/cities/${cityId}/districts`);
|
||||
return await request.get(`system/city/${cityId}/districts`);
|
||||
},
|
||||
},
|
||||
add: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities", params);
|
||||
return await request.post("system/city", params);
|
||||
},
|
||||
},
|
||||
edit: {
|
||||
put: async function (id, params) {
|
||||
return await request.put(`system/cities/${id}`, params);
|
||||
return await request.put(`system/city/${id}`, params);
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/cities/${id}`);
|
||||
return await request.delete(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities/batch-delete", params);
|
||||
return await request.post("system/city/batch-delete", params);
|
||||
},
|
||||
},
|
||||
batchStatus: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/cities/batch-status", params);
|
||||
return await request.post("system/city/batch-status", params);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -362,79 +362,79 @@ export default {
|
||||
},
|
||||
|
||||
// 通知管理
|
||||
notifications: {
|
||||
notification: {
|
||||
list: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/notifications", { params });
|
||||
return await request.get("system/notification", { params });
|
||||
},
|
||||
},
|
||||
unread: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/notifications/unread", {
|
||||
return await request.get("system/notification/unread", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
unreadCount: {
|
||||
get: async function () {
|
||||
return await request.get("system/notifications/unread-count");
|
||||
return await request.get("system/notification/unread-count");
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/notifications/${id}`);
|
||||
return await request.get(`system/notification/${id}`);
|
||||
},
|
||||
},
|
||||
markAsRead: {
|
||||
post: async function (id) {
|
||||
return await request.post(`system/notifications/${id}/read`);
|
||||
return await request.post(`system/notification/${id}/read`);
|
||||
},
|
||||
},
|
||||
batchMarkAsRead: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/batch-read",
|
||||
"system/notification/batch-read",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
markAllAsRead: {
|
||||
post: async function () {
|
||||
return await request.post("system/notifications/read-all");
|
||||
return await request.post("system/notification/read-all");
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
delete: async function (id) {
|
||||
return await request.delete(`system/notifications/${id}`);
|
||||
return await request.delete(`system/notification/${id}`);
|
||||
},
|
||||
},
|
||||
batchDelete: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/batch-delete",
|
||||
"system/notification/batch-delete",
|
||||
params,
|
||||
);
|
||||
},
|
||||
},
|
||||
clearRead: {
|
||||
post: async function () {
|
||||
return await request.post("system/notifications/clear-read");
|
||||
return await request.post("system/notification/clear-read");
|
||||
},
|
||||
},
|
||||
statistics: {
|
||||
get: async function () {
|
||||
return await request.get("system/notifications/statistics");
|
||||
return await request.get("system/notification/statistics");
|
||||
},
|
||||
},
|
||||
send: {
|
||||
post: async function (params) {
|
||||
return await request.post("system/notifications/send", params);
|
||||
return await request.post("system/notification/send", params);
|
||||
},
|
||||
},
|
||||
retryUnsent: {
|
||||
post: async function (params) {
|
||||
return await request.post(
|
||||
"system/notifications/retry-unsent",
|
||||
"system/notification/retry-unsent",
|
||||
params,
|
||||
);
|
||||
},
|
||||
@@ -443,72 +443,72 @@ export default {
|
||||
|
||||
// 公共接口 (无需认证)
|
||||
public: {
|
||||
configs: {
|
||||
config: {
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/configs");
|
||||
return await request.get("system/config");
|
||||
},
|
||||
},
|
||||
group: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/group", {
|
||||
return await request.get("system/config/group", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
key: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/configs/key", { params });
|
||||
return await request.get("system/config/key", { params });
|
||||
},
|
||||
},
|
||||
},
|
||||
dictionaries: {
|
||||
dictionary: {
|
||||
all: {
|
||||
get: async function () {
|
||||
return await request.get("system/dictionaries");
|
||||
return await request.get("system/dictionary");
|
||||
},
|
||||
},
|
||||
code: {
|
||||
get: async function (params) {
|
||||
return await request.get("system/dictionaries/code", {
|
||||
return await request.get("system/dictionary/code", {
|
||||
params,
|
||||
});
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/dictionaries/${id}`);
|
||||
return await request.get(`system/dictionary/${id}`);
|
||||
},
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
city: {
|
||||
tree: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/tree");
|
||||
return await request.get("system/city/tree");
|
||||
},
|
||||
},
|
||||
provinces: {
|
||||
get: async function () {
|
||||
return await request.get("system/cities/provinces");
|
||||
return await request.get("system/city/provinces");
|
||||
},
|
||||
},
|
||||
cities: {
|
||||
get: async function (provinceId) {
|
||||
return await request.get(
|
||||
`system/cities/${provinceId}/cities`,
|
||||
`system/city/${provinceId}/cities`,
|
||||
);
|
||||
},
|
||||
},
|
||||
districts: {
|
||||
get: async function (cityId) {
|
||||
return await request.get(
|
||||
`system/cities/${cityId}/districts`,
|
||||
`system/city/${cityId}/districts`,
|
||||
);
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
get: async function (id) {
|
||||
return await request.get(`system/cities/${id}`);
|
||||
return await request.get(`system/city/${id}`);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="visible"
|
||||
:title="title"
|
||||
:width="500"
|
||||
:confirm-loading="loading"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
>
|
||||
<a-form-item label="城市名称" name="title">
|
||||
<a-input
|
||||
v-model:value="formData.title"
|
||||
placeholder="请输入城市名称"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="城市编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
placeholder="请输入城市编码"
|
||||
allow-clear
|
||||
:disabled="mode === 'edit'"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="mode === 'add'"
|
||||
label="父级城市"
|
||||
name="parent_code"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="formData.parent_code"
|
||||
placeholder="请选择父级城市"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option :value="null"
|
||||
>无(顶级城市)</a-select-option
|
||||
>
|
||||
<a-select-option
|
||||
v-for="city in flatCities"
|
||||
:key="city.code"
|
||||
:value="city.code"
|
||||
>
|
||||
{{ city.title }} ({{ city.code }})
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="mode === 'addChild'"
|
||||
label="父级城市"
|
||||
name="parent_code"
|
||||
>
|
||||
<a-input v-model:value="parentCityTitle" disabled />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import api from "@/api/system";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
cityData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "add",
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "success"]);
|
||||
|
||||
const formRef = ref(null);
|
||||
const loading = ref(false);
|
||||
const flatCities = ref([]);
|
||||
const parentCityTitle = ref("");
|
||||
|
||||
const formData = reactive({
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: null,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
title: [
|
||||
{ required: true, message: "请输入城市名称", trigger: "blur" },
|
||||
{ max: 100, message: "城市名称不能超过100个字符", trigger: "blur" },
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: "请输入城市编码", trigger: "blur" },
|
||||
{ max: 50, message: "城市编码不能超过50个字符", trigger: "blur" },
|
||||
{
|
||||
pattern: /^[A-Za-z0-9_-]+$/,
|
||||
message: "城市编码只能包含字母、数字、下划线和横线",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const title = computed(() => {
|
||||
const titles = {
|
||||
add: "新增城市",
|
||||
addChild: "新增子城市",
|
||||
edit: "编辑城市",
|
||||
};
|
||||
return titles[props.mode] || "城市";
|
||||
});
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.visible,
|
||||
set: (val) => emit("update:visible", val),
|
||||
});
|
||||
|
||||
// 加载所有城市(用于父级选择)
|
||||
const loadAllCities = async () => {
|
||||
try {
|
||||
const res = await api.cities.list.get({ page_size: 1000 });
|
||||
if (res.code === 200) {
|
||||
flatCities.value = res.data.list || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载城市列表失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索过滤
|
||||
const filterOption = (input, option) => {
|
||||
return option.children[0].children
|
||||
.toLowerCase()
|
||||
.includes(input.toLowerCase());
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.title = "";
|
||||
formData.code = "";
|
||||
formData.parent_code = null;
|
||||
parentCityTitle.value = "";
|
||||
formRef.value?.clearValidate();
|
||||
};
|
||||
|
||||
// 监听 cityData 变化
|
||||
watch(
|
||||
() => props.cityData,
|
||||
(val) => {
|
||||
if (val && props.visible) {
|
||||
formData.title = val.title || "";
|
||||
formData.code = val.code || "";
|
||||
formData.parent_code = val.parent_code || null;
|
||||
|
||||
if (props.mode === "addChild" && val.parent_code) {
|
||||
// 查找父级城市名称
|
||||
const parentCity = flatCities.value.find(
|
||||
(city) => city.code === val.parent_code,
|
||||
);
|
||||
parentCityTitle.value = parentCity
|
||||
? `${parentCity.title} (${parentCity.code})`
|
||||
: val.parent_code;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// 监听弹窗打开
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
loadAllCities();
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// 确定
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
loading.value = true;
|
||||
|
||||
const data = {
|
||||
title: formData.title,
|
||||
code: formData.code,
|
||||
};
|
||||
|
||||
if (props.mode === "add" && formData.parent_code) {
|
||||
data.parent_code = formData.parent_code;
|
||||
}
|
||||
|
||||
let res;
|
||||
if (props.mode === "add" || props.mode === "addChild") {
|
||||
res = await api.cities.add.post(data);
|
||||
} else if (props.mode === "edit") {
|
||||
res = await api.cities.edit.put(props.cityData.id, data);
|
||||
}
|
||||
|
||||
if (res.code === 200) {
|
||||
message.success(props.mode === "edit" ? "更新成功" : "创建成功");
|
||||
emit("success");
|
||||
handleCancel();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.errorFields) {
|
||||
// 表单验证错误,不提示
|
||||
} else {
|
||||
message.error(error.message || "操作失败");
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
resetForm();
|
||||
emit("update:visible", false);
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div class="pages-base-layout city-page">
|
||||
<div class="tool-bar">
|
||||
<div class="left-panel">
|
||||
<a-space>
|
||||
<a-input
|
||||
v-model:value="searchForm.keyword"
|
||||
placeholder="城市名称/编码"
|
||||
allow-clear
|
||||
style="width: 180px"
|
||||
/>
|
||||
<a-button type="primary" @click="handleSearch">
|
||||
<template #icon><search-outlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleReset">
|
||||
<template #icon><redo-outlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<a-button type="primary" @click="handleAdd">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增
|
||||
</a-button>
|
||||
<a-dropdown>
|
||||
<a-button>
|
||||
更多
|
||||
<down-outlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleRefresh">
|
||||
<reload-outlined />
|
||||
刷新
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleExpandAll">
|
||||
<expand-outlined />
|
||||
展开全部
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleCollapseAll">
|
||||
<compress-outlined />
|
||||
折叠全部
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-content">
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:row-key="rowKey"
|
||||
:expand-row-by-click="true"
|
||||
:default-expand-all-rows="false"
|
||||
:expand-icon-column-index="1"
|
||||
:indent-size="20"
|
||||
@expand="handleExpand"
|
||||
>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<a-table
|
||||
:columns="childColumns"
|
||||
:data-source="record.children"
|
||||
:pagination="false"
|
||||
:row-key="rowKey"
|
||||
size="small"
|
||||
:show-header="false"
|
||||
>
|
||||
<template #bodyCell="{ column, record: child }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a-tag color="blue">{{ child.title }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'code'">
|
||||
{{ child.code }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAddChild(child)"
|
||||
>
|
||||
新增子级
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(child)"
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
title="确定要删除该城市吗?"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="handleDelete(child.id)"
|
||||
>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'title'">
|
||||
<a-tag color="green">{{ record.title }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'code'">
|
||||
{{ record.code }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'parent_code'">
|
||||
<a-tag v-if="record.parent_code" color="purple">{{
|
||||
record.parent_code
|
||||
}}</a-tag>
|
||||
<span v-else class="text-gray-400">-</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'has_children'">
|
||||
<a-tag v-if="hasChildren(record)" color="orange"
|
||||
>有</a-tag
|
||||
>
|
||||
<span v-else class="text-gray-400">无</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAddChild(record)"
|
||||
>
|
||||
新增子级
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
title="确定要删除该城市吗?"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="handleDelete(record.id)"
|
||||
>
|
||||
<a-button type="link" size="small" danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<SaveDialog
|
||||
v-model:visible="saveDialogVisible"
|
||||
:city-data="currentCity"
|
||||
:mode="saveMode"
|
||||
@success="handleSaveSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import api from "@/api/system";
|
||||
import SaveDialog from "./components/SaveDialog.vue";
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
keyword: "",
|
||||
});
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const loading = ref(false);
|
||||
const expandedKeys = ref([]);
|
||||
|
||||
// 新增/编辑弹窗
|
||||
const saveDialogVisible = ref(false);
|
||||
const saveMode = ref("add");
|
||||
const currentCity = ref(null);
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: "城市名称",
|
||||
key: "title",
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
title: "城市编码",
|
||||
key: "code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "父级编码",
|
||||
key: "parent_code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "子级数量",
|
||||
key: "has_children",
|
||||
width: 120,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
},
|
||||
];
|
||||
|
||||
// 子表格列配置
|
||||
const childColumns = [
|
||||
{
|
||||
title: "城市名称",
|
||||
key: "title",
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
title: "城市编码",
|
||||
key: "code",
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "action",
|
||||
width: 250,
|
||||
},
|
||||
];
|
||||
|
||||
const rowKey = (record) => record.id;
|
||||
|
||||
// 判断是否有子级
|
||||
const hasChildren = (record) => {
|
||||
return record.children && record.children.length > 0;
|
||||
};
|
||||
|
||||
// 加载城市树形数据
|
||||
const loadCityTree = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await api.cities.tree.get();
|
||||
if (res.code === 200) {
|
||||
tableData.value = res.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("加载城市数据失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchForm.keyword = "";
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
// 展开全部
|
||||
const handleExpandAll = () => {
|
||||
const allKeys = [];
|
||||
const collectKeys = (list) => {
|
||||
list.forEach((item) => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
allKeys.push(item.id);
|
||||
collectKeys(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
collectKeys(tableData.value);
|
||||
expandedKeys.value = allKeys;
|
||||
};
|
||||
|
||||
// 折叠全部
|
||||
const handleCollapseAll = () => {
|
||||
expandedKeys.value = [];
|
||||
};
|
||||
|
||||
// 展开/折叠事件
|
||||
const handleExpand = (expanded, record) => {
|
||||
if (expanded) {
|
||||
if (!expandedKeys.value.includes(record.id)) {
|
||||
expandedKeys.value.push(record.id);
|
||||
}
|
||||
} else {
|
||||
expandedKeys.value = expandedKeys.value.filter(
|
||||
(key) => key !== record.id,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
saveMode.value = "add";
|
||||
currentCity.value = {
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: null,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 新增子级
|
||||
const handleAddChild = (record) => {
|
||||
saveMode.value = "addChild";
|
||||
currentCity.value = {
|
||||
title: "",
|
||||
code: "",
|
||||
parent_code: record.code,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record) => {
|
||||
saveMode.value = "edit";
|
||||
currentCity.value = {
|
||||
id: record.id,
|
||||
title: record.title,
|
||||
code: record.code,
|
||||
parent_code: record.parent_code,
|
||||
};
|
||||
saveDialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = async (id) => {
|
||||
try {
|
||||
const res = await api.cities.delete.delete(id);
|
||||
if (res.code === 200) {
|
||||
message.success("删除成功");
|
||||
loadCityTree();
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(error.message || "删除失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 保存成功
|
||||
const handleSaveSuccess = () => {
|
||||
loadCityTree();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadCityTree();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.city-page {
|
||||
@extend .pages-base-layout;
|
||||
|
||||
.text-gray-400 {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="visible"
|
||||
title="日志详情"
|
||||
width="800px"
|
||||
:footer="null"
|
||||
>
|
||||
<a-descriptions v-if="logData" bordered :column="2" size="small">
|
||||
<a-descriptions-item label="日志ID" :span="1">
|
||||
{{ logData.id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="用户名" :span="1">
|
||||
{{ logData.username || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="模块" :span="1">
|
||||
{{ logData.module || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="操作" :span="1">
|
||||
{{ logData.action || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="请求方式" :span="1">
|
||||
<a-tag :color="getMethodColor(logData.method)">
|
||||
{{ logData.method }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="URL" :span="1">
|
||||
{{ logData.url || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="IP地址" :span="1">
|
||||
{{ logData.ip || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态码" :span="1">
|
||||
{{ logData.status_code || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态" :span="1">
|
||||
<a-tag
|
||||
:color="logData.status === 'success' ? 'success' : 'error'"
|
||||
>
|
||||
{{ logData.status === "success" ? "成功" : "失败" }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="执行时间" :span="1">
|
||||
<span
|
||||
:style="{
|
||||
color: getExecutionTimeColor(logData.execution_time),
|
||||
}"
|
||||
>
|
||||
{{ logData.execution_time }}ms
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间" :span="2">
|
||||
{{ logData.created_at || "-" }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="User Agent" :span="2">
|
||||
<div style="max-height: 60px; overflow-y: auto">
|
||||
{{ logData.user_agent || "-" }}
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.error_message"
|
||||
label="错误信息"
|
||||
:span="2"
|
||||
>
|
||||
<a-alert
|
||||
:message="logData.error_message"
|
||||
type="error"
|
||||
show-icon
|
||||
/>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.params && Object.keys(logData.params).length > 0"
|
||||
label="请求参数"
|
||||
:span="2"
|
||||
>
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="params" header="查看请求参数">
|
||||
<pre
|
||||
style="
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
"
|
||||
>{{ formatJson(logData.params) }}</pre
|
||||
>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
v-if="logData.result"
|
||||
label="返回结果"
|
||||
:span="2"
|
||||
>
|
||||
<a-collapse>
|
||||
<a-collapse-panel key="result" header="查看返回结果">
|
||||
<pre
|
||||
style="
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
"
|
||||
>{{ formatJson(logData.result) }}</pre
|
||||
>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<template #footer>
|
||||
<a-button @click="handleClose">关闭</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import systemApi from "@/api/system";
|
||||
|
||||
defineOptions({
|
||||
name: "LogDetailDialog",
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
const logData = ref(null);
|
||||
|
||||
// 获取请求方式颜色
|
||||
const getMethodColor = (method) => {
|
||||
const colors = {
|
||||
GET: "blue",
|
||||
POST: "green",
|
||||
PUT: "orange",
|
||||
DELETE: "red",
|
||||
PATCH: "purple",
|
||||
};
|
||||
return colors[method] || "default";
|
||||
};
|
||||
|
||||
// 获取执行时间颜色
|
||||
const getExecutionTimeColor = (time) => {
|
||||
if (time > 1000) return "#ff4d4f";
|
||||
if (time > 500) return "#faad14";
|
||||
return "#52c41a";
|
||||
};
|
||||
|
||||
// 格式化JSON
|
||||
const formatJson = (data) => {
|
||||
if (typeof data === "string") {
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(data), null, 2);
|
||||
} catch (e) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(data, null, 2);
|
||||
};
|
||||
|
||||
// 打开弹窗
|
||||
const open = async () => {
|
||||
visible.value = true;
|
||||
return {
|
||||
setData,
|
||||
};
|
||||
};
|
||||
|
||||
// 设置数据
|
||||
const setData = async (data) => {
|
||||
if (data && data.id) {
|
||||
// 如果传入了完整数据,直接使用
|
||||
if (data.params || data.result) {
|
||||
logData.value = data;
|
||||
} else {
|
||||
// 否则从服务器获取完整数据
|
||||
try {
|
||||
const res = await systemApi.logs.detail.get(data.id);
|
||||
if (res.code === 200) {
|
||||
logData.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取日志详情失败:", error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logData.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
logData.value = null;
|
||||
};
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
width: 120px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,604 @@
|
||||
<template>
|
||||
<div class="pages-sidebar-layout log-page">
|
||||
<div class="left-box">
|
||||
<div class="header">日志筛选</div>
|
||||
<div class="body">
|
||||
<a-tree
|
||||
v-model:selectedKeys="selectedTreeKeys"
|
||||
:tree-data="filterTreeData"
|
||||
show-line
|
||||
:field-names="{
|
||||
title: 'title',
|
||||
key: 'key',
|
||||
children: 'children',
|
||||
}"
|
||||
@select="onTreeSelect"
|
||||
>
|
||||
<template #icon="{ dataRef }">
|
||||
<ApiOutlined v-if="dataRef.type === 'method'" />
|
||||
<CheckCircleOutlined
|
||||
v-else-if="
|
||||
dataRef.type === 'status' &&
|
||||
dataRef.key === 'success'
|
||||
"
|
||||
/>
|
||||
<CloseCircleOutlined
|
||||
v-else-if="
|
||||
dataRef.type === 'status' &&
|
||||
dataRef.key === 'error'
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<!-- 统计卡片 -->
|
||||
<div class="statistics-cards">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="总日志数"
|
||||
:value="statistics.total || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<FileTextOutlined style="color: #1890ff" />
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="成功数"
|
||||
:value="statistics.success || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<CheckCircleOutlined
|
||||
style="color: #52c41a"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="失败数"
|
||||
:value="statistics.error || 0"
|
||||
>
|
||||
<template #prefix>
|
||||
<CloseCircleOutlined
|
||||
style="color: #ff4d4f"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-card size="small" class="stat-card">
|
||||
<a-statistic
|
||||
title="平均响应时间"
|
||||
:value="statistics.avg_time || 0"
|
||||
suffix="ms"
|
||||
>
|
||||
<template #prefix>
|
||||
<ClockCircleOutlined
|
||||
style="color: #faad14"
|
||||
/>
|
||||
</template>
|
||||
</a-statistic>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="tool-bar">
|
||||
<div class="left-panel">
|
||||
<a-space>
|
||||
<a-range-picker
|
||||
v-model:value="dateRange"
|
||||
:placeholder="['开始时间', '结束时间']"
|
||||
style="width: 260px"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
<a-button type="primary" @click="handleSearch">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleLogReset">
|
||||
<template #icon><RedoOutlined /></template>
|
||||
清除
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<a-space>
|
||||
<a-button
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
>
|
||||
<template #icon><DownloadOutlined /></template>
|
||||
导出
|
||||
</a-button>
|
||||
<a-dropdown>
|
||||
<a-button>
|
||||
更多
|
||||
<DownOutlined />
|
||||
</a-button>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleClearLogs">
|
||||
<DeleteOutlined />清理日志
|
||||
</a-menu-item>
|
||||
<a-menu-item @click="handleRefreshStats">
|
||||
<ReloadOutlined />刷新统计
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content">
|
||||
<sc-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
:row-key="rowKey"
|
||||
@refresh="refreshTable"
|
||||
@paginationChange="handlePaginationChange"
|
||||
>
|
||||
<template #status="{ record }">
|
||||
<a-tag
|
||||
:color="
|
||||
record.status === 'success'
|
||||
? 'success'
|
||||
: 'error'
|
||||
"
|
||||
>
|
||||
{{ record.status === "success" ? "成功" : "失败" }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #method="{ record }">
|
||||
<a-tag :color="getMethodColor(record.method)">
|
||||
{{ record.method }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template #execution_time="{ record }">
|
||||
<span
|
||||
:style="{
|
||||
color:
|
||||
record.execution_time > 1000
|
||||
? '#ff4d4f'
|
||||
: record.execution_time > 500
|
||||
? '#faad14'
|
||||
: '#52c41a',
|
||||
}"
|
||||
>
|
||||
{{ record.execution_time }}ms
|
||||
</span>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-space>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleView(record)"
|
||||
>查看详情</a-button
|
||||
>
|
||||
<a-popconfirm
|
||||
title="确定删除该日志吗?"
|
||||
@confirm="handleDelete(record)"
|
||||
>
|
||||
<a-button type="link" size="small" danger
|
||||
>删除</a-button
|
||||
>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</sc-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 日志详情弹窗 -->
|
||||
<detail-dialog ref="detailDialogRef" />
|
||||
|
||||
<!-- 清理日志确认弹窗 -->
|
||||
<a-modal
|
||||
v-model:open="dialog.clear"
|
||||
title="清理日志"
|
||||
:confirm-loading="clearLoading"
|
||||
@ok="handleConfirmClear"
|
||||
>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="清理天数">
|
||||
<a-input-number
|
||||
v-model:value="clearDays"
|
||||
:min="1"
|
||||
:max="365"
|
||||
style="width: 100%"
|
||||
placeholder="请输入天数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-alert
|
||||
message="删除指定天数之前的日志记录,此操作不可恢复"
|
||||
type="warning"
|
||||
show-icon
|
||||
/>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import {
|
||||
SearchOutlined,
|
||||
RedoOutlined,
|
||||
DeleteOutlined,
|
||||
DownOutlined,
|
||||
ApiOutlined,
|
||||
CheckCircleOutlined,
|
||||
CloseCircleOutlined,
|
||||
FileTextOutlined,
|
||||
ClockCircleOutlined,
|
||||
DownloadOutlined,
|
||||
ReloadOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import scTable from "@/components/scTable/index.vue";
|
||||
import detailDialog from "./components/DetailDialog.vue";
|
||||
import systemApi from "@/api/system";
|
||||
import { useTable } from "@/hooks/useTable";
|
||||
|
||||
defineOptions({
|
||||
name: "systemLog",
|
||||
});
|
||||
|
||||
// 统计数据
|
||||
const statistics = ref({
|
||||
total: 0,
|
||||
success: 0,
|
||||
error: 0,
|
||||
avg_time: 0,
|
||||
});
|
||||
|
||||
// 使用useTable hooks
|
||||
const {
|
||||
tableRef,
|
||||
searchForm,
|
||||
tableData,
|
||||
loading,
|
||||
pagination,
|
||||
handleSearch,
|
||||
handlePaginationChange,
|
||||
refreshTable,
|
||||
} = useTable({
|
||||
api: systemApi.logs.list.get,
|
||||
searchForm: {
|
||||
method: "",
|
||||
status: "",
|
||||
start_date: "",
|
||||
end_date: "",
|
||||
},
|
||||
columns: [],
|
||||
needPagination: true,
|
||||
});
|
||||
|
||||
// 对话框状态
|
||||
const dialog = reactive({
|
||||
detail: false,
|
||||
clear: false,
|
||||
});
|
||||
|
||||
// 弹窗引用
|
||||
const detailDialogRef = ref(null);
|
||||
|
||||
// 清理日志相关
|
||||
const clearDays = ref(30);
|
||||
const clearLoading = ref(false);
|
||||
|
||||
// 导出相关
|
||||
const exportLoading = ref(false);
|
||||
|
||||
// 日期范围
|
||||
const dateRange = ref([]);
|
||||
|
||||
// 树形筛选数据
|
||||
const treeData = ref([
|
||||
{
|
||||
title: "请求方式",
|
||||
key: "method-root",
|
||||
type: "root",
|
||||
children: [
|
||||
{ title: "GET", key: "GET", type: "method" },
|
||||
{ title: "POST", key: "POST", type: "method" },
|
||||
{ title: "PUT", key: "PUT", type: "method" },
|
||||
{ title: "DELETE", key: "DELETE", type: "method" },
|
||||
{ title: "PATCH", key: "PATCH", type: "method" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "返回状态",
|
||||
key: "status-root",
|
||||
type: "root",
|
||||
children: [
|
||||
{ title: "成功", key: "success", type: "status" },
|
||||
{ title: "失败", key: "error", type: "status" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
// 选中的树节点
|
||||
const selectedTreeKeys = ref([]);
|
||||
|
||||
// 行key
|
||||
const rowKey = "id";
|
||||
|
||||
// 过滤后的树数据
|
||||
const filterTreeData = computed(() => {
|
||||
return treeData.value;
|
||||
});
|
||||
|
||||
// 获取请求方式颜色
|
||||
const getMethodColor = (method) => {
|
||||
const colors = {
|
||||
GET: "blue",
|
||||
POST: "green",
|
||||
PUT: "orange",
|
||||
DELETE: "red",
|
||||
PATCH: "purple",
|
||||
};
|
||||
return colors[method] || "default";
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{ title: "ID", dataIndex: "id", key: "id", width: 80 },
|
||||
{ title: "用户名", dataIndex: "username", key: "username", width: 120 },
|
||||
{ title: "模块", dataIndex: "module", key: "module", width: 120 },
|
||||
{ title: "操作", dataIndex: "action", key: "action", width: 150 },
|
||||
{
|
||||
title: "请求方式",
|
||||
dataIndex: "method",
|
||||
key: "method",
|
||||
width: 100,
|
||||
align: "center",
|
||||
slot: "method",
|
||||
},
|
||||
{ title: "URL", dataIndex: "url", key: "url", ellipsis: true },
|
||||
{ title: "IP地址", dataIndex: "ip", key: "ip", width: 140 },
|
||||
{
|
||||
title: "状态码",
|
||||
dataIndex: "status_code",
|
||||
key: "status_code",
|
||||
width: 100,
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
width: 100,
|
||||
align: "center",
|
||||
slot: "status",
|
||||
},
|
||||
{
|
||||
title: "执行时间",
|
||||
dataIndex: "execution_time",
|
||||
key: "execution_time",
|
||||
width: 120,
|
||||
align: "center",
|
||||
slot: "execution_time",
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "table_action",
|
||||
key: "table_action",
|
||||
width: 150,
|
||||
align: "center",
|
||||
slot: "action",
|
||||
fixed: "right",
|
||||
},
|
||||
];
|
||||
|
||||
// 加载统计数据
|
||||
const loadStatistics = async () => {
|
||||
try {
|
||||
const res = await systemApi.logs.statistics.get(searchForm);
|
||||
if (res.code === 200) {
|
||||
statistics.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载统计数据失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 树形选择事件
|
||||
const onTreeSelect = (selectedKeys, { selectedNodes }) => {
|
||||
if (selectedKeys.length > 0) {
|
||||
const key = selectedKeys[0];
|
||||
const node = selectedNodes[0];
|
||||
|
||||
// 重置搜索表单
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
|
||||
// 根据节点类型设置对应的筛选条件
|
||||
if (node.type === "method") {
|
||||
searchForm.method = key;
|
||||
} else if (node.type === "status") {
|
||||
searchForm.status = key;
|
||||
}
|
||||
|
||||
// 触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
// 取消选择时清空筛选条件
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
}
|
||||
};
|
||||
|
||||
// 日期变化
|
||||
const handleDateChange = (dates) => {
|
||||
if (dates && dates.length === 2) {
|
||||
searchForm.start_date = dates[0].format("YYYY-MM-DD HH:mm:ss");
|
||||
searchForm.end_date = dates[1].format("YYYY-MM-DD HH:mm:ss");
|
||||
} else {
|
||||
searchForm.start_date = "";
|
||||
searchForm.end_date = "";
|
||||
}
|
||||
// 自动触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleLogReset = () => {
|
||||
// 重置日期范围
|
||||
dateRange.value = [];
|
||||
searchForm.start_date = "";
|
||||
searchForm.end_date = "";
|
||||
|
||||
// 重置树形选择
|
||||
selectedTreeKeys.value = [];
|
||||
searchForm.method = "";
|
||||
searchForm.status = "";
|
||||
|
||||
// 重置分页到第一页
|
||||
pagination.current = 1;
|
||||
|
||||
// 触发搜索
|
||||
handleSearch();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleView = async (record) => {
|
||||
const dialog = await detailDialogRef.value?.open();
|
||||
dialog?.setData(record);
|
||||
};
|
||||
|
||||
// 删除日志
|
||||
const handleDelete = async (record) => {
|
||||
try {
|
||||
const res = await systemApi.logs.delete.delete(record.id);
|
||||
if (res.code === 200) {
|
||||
message.success("删除成功");
|
||||
refreshTable();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
message.error(res.message || "删除失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除日志失败:", error);
|
||||
message.error("删除失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 清理日志
|
||||
const handleClearLogs = () => {
|
||||
dialog.clear = true;
|
||||
};
|
||||
|
||||
// 确认清理日志
|
||||
const handleConfirmClear = async () => {
|
||||
if (!clearDays.value || clearDays.value < 1) {
|
||||
message.warning("请输入有效的天数");
|
||||
return;
|
||||
}
|
||||
|
||||
clearLoading.value = true;
|
||||
try {
|
||||
const res = await systemApi.logs.clear.post({ days: clearDays.value });
|
||||
if (res.code === 200) {
|
||||
message.success("清理成功");
|
||||
dialog.clear = false;
|
||||
clearDays.value = 30;
|
||||
refreshTable();
|
||||
// 同时刷新统计数据
|
||||
loadStatistics();
|
||||
} else {
|
||||
message.error(res.message || "清理失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("清理日志失败:", error);
|
||||
message.error("清理失败");
|
||||
} finally {
|
||||
clearLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新统计
|
||||
const handleRefreshStats = () => {
|
||||
loadStatistics();
|
||||
};
|
||||
|
||||
// 导出日志
|
||||
const handleExport = async () => {
|
||||
exportLoading.value = true;
|
||||
try {
|
||||
const blob = await systemApi.logs.export.get(searchForm);
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `系统日志_${new Date().getTime()}.xlsx`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
message.success("导出成功");
|
||||
} catch (error) {
|
||||
console.error("导出失败:", error);
|
||||
message.error("导出失败");
|
||||
} finally {
|
||||
exportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 页面加载时自动搜索一次
|
||||
handleSearch();
|
||||
// 加载统计数据
|
||||
loadStatistics();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.log-page {
|
||||
.statistics-cards {
|
||||
margin-bottom: 16px;
|
||||
background: #fff;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user