From c0c127d0909cb40b6a84bec17843f54ba398ea2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9A=93=E6=9C=88=E5=BD=92=E5=B0=98?= Date: Sun, 23 Feb 2025 22:05:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=99=E7=94=A8=E6=88=B7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=80=81=E9=83=A8=E9=97=A8=E7=AE=A1=E7=90=86=E3=80=81?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86=E3=80=81=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E3=80=81=E5=9B=BD=E9=99=85=E5=8C=96=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E3=80=81=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86=E3=80=81?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=97=A5=E5=BF=97=E3=80=81=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E3=80=81=E7=BC=93=E5=AD=98=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E3=80=81=E7=BC=93=E5=AD=98=E7=9B=91=E6=8E=A7=E5=92=8C=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E7=9B=91=E6=8E=A7=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E7=BA=A7=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86;=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E5=8A=A0=E8=BD=BD=E4=B8=AA=E4=BA=BA=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/en.yaml | 17 +- locales/zh-CN.yaml | 17 +- src/api/i18n.ts | 24 ++ src/api/monitor.ts | 80 +++- src/api/system.ts | 11 +- src/router/index.ts | 5 +- src/store/modules/user.ts | 4 +- src/utils/auth.ts | 19 + .../account-settings/components/Profile.vue | 10 +- src/views/account-settings/utils/hooks.tsx | 13 +- src/views/login/components/LoginRegist.vue | 6 +- src/views/login/components/LoginUpdate.vue | 4 +- src/views/login/index.vue | 6 - src/views/monitor/cache/index.vue | 10 +- src/views/monitor/cache/list.vue | 6 + src/views/monitor/login/index.vue | 112 ++++- src/views/monitor/login/utils/hook.tsx | 149 +++++-- src/views/monitor/operation/index.vue | 121 ++++-- src/views/monitor/operation/utils/hook.tsx | 384 ++++++++++++++++++ src/views/system/config/index.vue | 10 +- src/views/system/config/utils/hook.tsx | 2 +- src/views/system/department/index.vue | 5 + src/views/system/department/utils/hook.tsx | 2 +- src/views/system/i18n/index.vue | 22 +- src/views/system/i18n/utils/hook.tsx | 308 ++++++++++++++ src/views/system/locale/components/form.vue | 50 +++ src/views/system/locale/index.vue | 219 ++++++++++ src/views/system/locale/utils/hook.tsx | 303 ++++++++++++++ .../system/permission/components/form.vue | 11 +- src/views/system/permission/index.vue | 7 +- src/views/system/permission/utils/hook.tsx | 6 +- src/views/system/role/components/form.vue | 7 +- src/views/system/role/index.vue | 50 ++- src/views/system/role/utils/hook.tsx | 98 ++++- src/views/system/user/index.vue | 16 +- src/views/system/user/utils/hook.tsx | 24 +- 36 files changed, 1980 insertions(+), 158 deletions(-) create mode 100644 src/views/monitor/operation/utils/hook.tsx create mode 100644 src/views/system/i18n/utils/hook.tsx create mode 100644 src/views/system/locale/components/form.vue create mode 100644 src/views/system/locale/index.vue create mode 100644 src/views/system/locale/utils/hook.tsx diff --git a/locales/en.yaml b/locales/en.yaml index c4ba215..dffe817 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -22,6 +22,8 @@ buttons:OpenText: Open buttons:CloseText: Close buttons:Search: Search buttons:Reset: Reset +buttons:Details: Details +buttons:DataList: DataList buttons:Add: Add buttons:Update: Update buttons:Delete: Delete @@ -40,13 +42,13 @@ buttons:More: More buttons:Deselect: Deselect buttons:DeleteInBatches: Delete In Batches buttons:ExportInBatches: Export In Batches +buttons:ExitInBatches: Exit In Batches buttons:ExportAll: Export All buttons:UploadAvatar: Upload Avatar buttons:ResetPassword: Reset Password buttons:RoleAllocation: Role Allocation buttons:PermissionDetails: Permission Details buttons:ForceToExit: Force Exit -buttons:Details: Details search:Total: Total search:History: History search:Collect: Collect @@ -174,3 +176,16 @@ logout:message: Whether to exit the system? logout:success: Logout Success logout:fail: Logout Fail logout:cancel: Logout Cancel +user:buttons:addRole: Add User Role +user:buttons:deleteRole: Delete User Role +user:buttons:updateRole: Update User Role +user:buttons:roleInfo: User Role Info +user:buttons:roleDataList: User Role Data List +user:buttons:permisssionList: User Permisssion List +user:buttons:uploadAvatar: Upload Avatar +user:buttons:resetPassword: Reset Password +role:buttons:addPermission: Add Role Permission +role:buttons:deletePermission: Delete Role Permission +role:buttons:updatePermission: Update Role Permission +role:buttons:permissiomInfo: Role Permissiom Info +role:buttons:permissionDataList: Rolr Permission Data List diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index a6d3748..69bcd91 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -22,6 +22,8 @@ buttons:OpenText: 开 buttons:CloseText: 关 buttons:Search: 搜索 buttons:Reset: 重置 +buttons:Details: 详情 +buttons:DataList: 数据列表 buttons:Add: 添加 buttons:Update: 修改 buttons:Delete: 删除 @@ -46,7 +48,7 @@ buttons:ResetPassword: 重置密码 buttons:RoleAllocation: 角色分配 buttons:PermissionDetails: 权限详情 buttons:ForceToExit: 强制退出 -buttons:Details: 详情 +buttons:ExitInBatches: 批量强退 search:Total: 共 search:History: 搜索历史 search:Collect: 收藏 @@ -174,3 +176,16 @@ logout:message: 是否退出当前系统? logout:success: 退出成功 logout:fail: 退出失败 logout:cancel: 退出取消 +user:buttons:addRole: 添加用户角色 +user:buttons:deleteRole: 删除用户角色 +user:buttons:updateRole: 更新用户角色 +user:buttons:roleInfo: 用户角色详情 +user:buttons:roleDataList: 用户角色列表 +user:buttons:permisssionList: 用户权限列表 +user:buttons:uploadAvatar: 上传头像 +user:buttons:resetPassword: 重置密码 +role:buttons:addPermission: 添加角色权限 +role:buttons:deletePermission: 删除角色权限 +role:buttons:updatePermission: 更新角色权限 +role:buttons:permissiomInfo: 角色权限详情 +role:buttons:permissionDataList: 角色权限列表 diff --git a/src/api/i18n.ts b/src/api/i18n.ts index 272e7a6..b93d01c 100644 --- a/src/api/i18n.ts +++ b/src/api/i18n.ts @@ -31,6 +31,18 @@ export const deleteLocaleAPI = (id: string) => { return http.request("post", `/api/i18n/deleteLocale/${id}`); }; +/** + * + * 批量删除语言类型 + */ +export const deleteLocaleListAPI = (ids: string[]) => { + return http.request("post", `/api/i18n/deleteLocaleList`, { + data: { + ids + } + }); +}; + /** * 修改语言类型 */ @@ -138,6 +150,18 @@ export const getI18nInfoAPI = (id: string) => { export const deleteI18nAPI = (id: string) => { return http.request("post", `/api/i18n/deleteI18n/${id}`); }; + +/** + * + * 批量删除翻译 + */ +export const deleteI18nListAPI = (ids: string[]) => { + return http.request("post", `/api/i18n/deleteI18nList`, { + data: { + ids + } + }); +}; /** * 修改翻译 * @param data diff --git a/src/api/monitor.ts b/src/api/monitor.ts index 9f5a372..48af326 100644 --- a/src/api/monitor.ts +++ b/src/api/monitor.ts @@ -14,10 +14,27 @@ import { filterEmptyObject } from "./utils"; * 用户获取登录日志 */ -export const getUserLoginLogAPI = (params: { +/**获取用户登录日志参数 */ +type GetUserLoginLogParams = { + /**页码 */ page: number; + /**每页数量 */ pageSize: number; -}) => { + /**用户账号 */ + username?: string; + /**用户昵称 */ + nickname?: string; + /**部门ID */ + department_id?: string; + /**登录状态 */ + status?: number | string; + /**开始时间 */ + startTime?: string | number; + /**结束时间 */ + endTime?: string | number; +}; + +export const getUserLoginLogAPI = (params: GetUserLoginLogParams) => { return http.request>( "get", "/api/log/login", @@ -36,24 +53,73 @@ export const deleteUserOnlineAPI = (id: string) => { return http.request("delete", `/api/log/logout/${id}`); }; +/**用户批量强退*/ +export const deleteUserOnlineListAPI = (data: { ids: string[] }) => { + return http.request("delete", `/api/log/logoutList`, { data }); +}; + +/**删除登录日志 */ +export const deleteUserLoginLogAPI = (id: string) => { + return http.request("delete", `/api/log/delete/login/${id}`); +}; +/**批量删除登录日志 */ +export const deleteUserLoginLogListAPI = (data: { ids: string[] }) => { + return http.request("delete", `/api/log/deleteList/login`, { data }); +}; + // ------------------------操作日志相关---------------------------------------- +/**获取操作日志参数 */ +type GetUserOperationParams = { + /**页码 */ + page: number; + /**每页数量 */ + pageSize: number; + /**用户账号 */ + username?: string; + /**用户昵称 */ + nickname?: string; + /**部门ID */ + department_id?: string; + /**操作名称 */ + name?: string; + /**操作状态 */ + status?: number | string; + /**操作类型 */ + type?: number | string; + /**开始时间 */ + startTime?: string | number; + /**结束时间 */ + endTime?: string | number; +}; + /** * 获取用户操作日志 */ -export const getUserOperationsAPI = (params: { - page: number; - pageSize: number; -}) => { +export const getUserOperationsAPI = (params: GetUserOperationParams) => { return http.request>( "GET", "/api/log/operation", { - params + params: filterEmptyObject(params) } ); }; +/** + * 删除操作日志 + * @returns + */ +export const deleteUserOperationsAPI = (id: string) => { + return http.request("delete", `/api/log/delete/operation/${id}`); +}; +/**批量删除操作日志 */ +export const deleteUserOperationsListAPI = (data: { ids: string[] }) => { + return http.request("delete", `/api/log/deleteList/operation`, { + data + }); +}; + // ------------------------服务相关---------------------------------------- /** diff --git a/src/api/system.ts b/src/api/system.ts index 421be6b..7c3cc06 100644 --- a/src/api/system.ts +++ b/src/api/system.ts @@ -318,6 +318,15 @@ export const deleteRoleAPI = (id: string) => { return http.request("post", `/api/role/delete/${id}`); }; +/**批量删除角色 */ +export const deleteRoleListAPI = (ids: string[]) => { + return http.request("post", `/api/role/deleteList`, { + data: { + ids + } + }); +}; + // --------------------------用户相关-------------------------------------- /**添加用户参数 */ @@ -429,7 +438,7 @@ export const deleteUserAPI = (id: string) => { * @param data 用户ID列表 * @returns */ -export const deleteUserListAPI = (data: { userIds: string[] }) => { +export const deleteUserListAPI = (data: { ids: string[] }) => { return http.request("post", `/api/user/deleteUserList`, { data }); }; diff --git a/src/router/index.ts b/src/router/index.ts index 43efc59..f85f3af 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -27,7 +27,8 @@ import { type UserInfo, userInfoKey, removeToken, - getTokenInfo + getTokenInfo, + getUserInfo } from "@/utils/auth"; /** 自动导入全部静态路由,无需再手动引入!匹配 src/router/modules 目录(任何嵌套级别)中具有 .ts 扩展名的所有文件,除了 remaining.ts 文件 @@ -129,6 +130,8 @@ router.beforeEach((to: ToRouteType, _from, next) => { whiteList.includes(to.fullPath) ? next(_from.fullPath) : next(); } const data = getTokenInfo(); + /**获取个人信息 */ + getUserInfo(); if (!data.isExpire) { // 无权限跳转403页面 if ( diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index cf6f725..e1f5563 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -150,7 +150,7 @@ export const useUserStore = defineStore({ return new Promise>((resolve, reject) => { getLogin(data) .then(data => { - if (data.code === 200) { + if (data.success) { setToken(data.data); } resolve(data); @@ -189,7 +189,7 @@ export const useUserStore = defineStore({ return new Promise>((resolve, reject) => { refreshTokenApi(data) .then(data => { - if (data.code === 200) { + if (data.success) { setToken(data.data); } resolve(data); diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 40a25e3..5fad242 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,5 +1,6 @@ import { storageLocal } from "@pureadmin/utils"; import { useUserStoreHook } from "@/store/modules/user"; +import { getUserInfoAPI } from "@/api/login"; export interface UserInfo { /** 用户名 */ @@ -109,3 +110,21 @@ export function getTokenInfo(): { }; } } + +/**判断是否有权限 */ +export const hasAuth = (auth: string) => { + return useUserStoreHook().permissions.includes(auth); +}; + +/**获取用户信息 */ +export const getUserInfo = async () => { + const res = await getUserInfoAPI(); + if (res.success) { + const user = storageLocal().getItem(userInfoKey); + storageLocal().setItem(userInfoKey, { + ...user, + ...res.data + }); + setUserInfo(res.data); + } +}; diff --git a/src/views/account-settings/components/Profile.vue b/src/views/account-settings/components/Profile.vue index 4be8a58..47506d5 100644 --- a/src/views/account-settings/components/Profile.vue +++ b/src/views/account-settings/components/Profile.vue @@ -1,6 +1,7 @@ diff --git a/src/views/system/locale/utils/hook.tsx b/src/views/system/locale/utils/hook.tsx new file mode 100644 index 0000000..66ffdb8 --- /dev/null +++ b/src/views/system/locale/utils/hook.tsx @@ -0,0 +1,303 @@ +import dayjs from "dayjs"; +import editForm from "../components/form.vue"; +import { message } from "@/utils/message"; +import { type Ref, ref, reactive, onMounted, h } from "vue"; +import type { LanguageInfo, TranslationInfo } from "types/system"; +import type { PaginationProps } from "@pureadmin/table"; +import { addDialog } from "@/components/ReDialog"; +import { + getLocaleListAPI, + deleteLocaleAPI, + deleteLocaleListAPI, + postAddLocaleAPI, + putUpdateLocaleAPI, + getI18nHandleListAPI +} from "@/api/i18n"; + +import jsyaml from "js-yaml"; +import { getKeyList } from "@pureadmin/utils"; + +export const useLocale = (tableRef: Ref) => { + /** + * 查询表单 + */ + const form = reactive({ + name: "", + code: "" + }); + /** + * 表单Ref + */ + const formRef = ref(null); + /** + * 数据列表 + */ + const dataList = ref([]); + /** + * 加载状态 + */ + const loading = ref(true); + /** + * 已选数量 + */ + const selectedNum = ref(0); + /** + * 分页参数 + */ + const pagination = reactive({ + total: 0, + pageSize: 10, + currentPage: 1, + background: true, + pageSizes: [10, 20, 30, 40, 50] + }); + /** + * 表格列设置 + */ + const columns: TableColumnList = [ + { + label: "勾选列", // 如果需要表格多选,此处label必须设置 + type: "selection", + fixed: "left", + reserveSelection: true // 数据刷新后保留选项 + }, + { + label: "语言编码", + prop: "code" + }, + { + label: "语言名称", + prop: "name" + }, + { + label: "创建时间", + prop: "create_time", + formatter: ({ create_time }) => + dayjs(create_time).format("YYYY-MM-DD HH:mm:ss") + }, + { + label: "操作", + fixed: "right", + width: 250, + slot: "operation" + } + ]; + + /** + * 初次查询 + */ + const onSearch = async () => { + loading.value = true; + const res = await getLocaleListAPI({ + page: pagination.currentPage, + pageSize: pagination.pageSize, + name: form.name, + code: form.code + }); + if (res.success) { + dataList.value = res.data.result; + pagination.total = res.data.total; + pagination.currentPage = res.data.page; + } + message(res.msg, { + type: res.success ? "success" : "error" + }); + loading.value = false; + }; + /** + * 重置表单 + * @param formEl 表单ref + * @returns + */ + const resetForm = (formEl: any) => { + if (!formEl) return; + formEl.resetFields(); + onSearch(); + }; + /** + * 处理删除 + * @param row + */ + const handleDelete = async (row: TranslationInfo) => { + const res = await deleteLocaleAPI(row.id); + if (res.success) { + onSearch(); + } + message(res.msg, { + type: res.success ? "success" : "error" + }); + }; + /** + * 处理每页数量变化 + */ + const handleSizeChange = async (val: number) => { + const res = await getLocaleListAPI({ + page: pagination.currentPage, + pageSize: val, + name: form.name, + code: form.code + }); + if (res.success) { + dataList.value = res.data.result; + pagination.total = res.data.total; + pagination.currentPage = res.data.page; + } + message(res.msg, { + type: res.success ? "success" : "error" + }); + }; + + /** + * 处理页码变化 + * @param val + */ + const handleCurrentChange = async (val: number) => { + const res = await getLocaleListAPI({ + page: val, + pageSize: pagination.pageSize, + name: form.name, + code: form.code + }); + if (res.success) { + dataList.value = res.data.result; + pagination.total = res.data.total; + pagination.currentPage = res.data.page; + } + message(res.msg, { + type: res.success ? "success" : "error" + }); + }; + /** 当CheckBox选择项发生变化时会触发该事件 */ + const handleSelectionChange = async (val: any) => { + selectedNum.value = val.length; + // 重置表格高度 + tableRef.value.setAdaptive(); + }; + + /** 取消选择 */ + const onSelectionCancel = async () => { + selectedNum.value = 0; + // 用于多选表格,清空用户的选择 + tableRef.value.getTableRef().clearSelection(); + }; + + /** + * 批量删除 + */ + const onbatchDel = async () => { + // 返回当前选中的行 + const curSelected = tableRef.value.getTableRef().getSelectionRows(); + const res = await deleteLocaleListAPI(getKeyList(curSelected, "id")); + if (res.success) { + message(res.msg, { + type: "success" + }); + tableRef.value.getTableRef().clearSelection(); + onSearch(); + } else { + message(res.msg, { type: "error", duration: 5000 }); + } + }; + + const openDialog = async (title = "新增", row?: LanguageInfo) => { + addDialog({ + title: `${title}国际化项`, + props: { + formInline: { + title: title, + name: row?.name ?? "", + code: row?.code ?? "" + } + }, + width: "45%", + draggable: true, + fullscreenIcon: true, + closeOnClickModal: false, + contentRenderer: () => + h(editForm, { + formInline: { + title: title, + name: row?.name ?? "", + code: row?.code ?? "" + }, + ref: formRef + }), + beforeSure: async (done, {}) => { + const FormData = formRef.value.newFormInline; + let form = { + name: FormData.name ?? "", + code: FormData.code ?? "" + }; + if (title === "新增") { + const res = await postAddLocaleAPI(form); + if (res.success) { + done(); + await onSearch(); + } + message(res.msg, { type: res.success ? "success" : "error" }); + } else { + const res = await putUpdateLocaleAPI(form, row.id); + if (res.success) { + done(); + await onSearch(); + } + message(res.msg, { type: res.success ? "success" : "error" }); + } + } + }); + }; + + /** + * 导出 YAML 文件 + */ + const export_to_yaml = async (row: LanguageInfo) => { + const res = await getI18nHandleListAPI(row.id); // 调用 API 获取数据 + if (res.success) { + // 将 JSON 转换为 YAML + const yamlString = jsyaml.dump(res.data.data); + + // 创建 Blob 对象 + const blob = new Blob([yamlString], { type: "text/yaml" }); + + // 生成下载链接 + const url = URL.createObjectURL(blob); + + // 创建 元素并触发下载 + const link = document.createElement("a"); + link.href = url; + link.download = `${row.code}.yaml`; // 设置下载文件名 + document.body.appendChild(link); // 将 元素添加到 DOM 中 + link.click(); // 模拟点击下载 + + // 清理 URL 对象 + URL.revokeObjectURL(url); + document.body.removeChild(link); // 移除 元素 + } + }; + /** + * 页面加载执行 + */ + onMounted(async () => { + await onSearch(); + }); + + return { + form, + formRef, + dataList, + loading, + pagination, + columns, + selectedNum, + onSearch, + openDialog, + resetForm, + export_to_yaml, + handleDelete, + handleSizeChange, + handleCurrentChange, + handleSelectionChange, + onSelectionCancel, + onbatchDel + }; +}; diff --git a/src/views/system/permission/components/form.vue b/src/views/system/permission/components/form.vue index 8dad0db..c7c37ae 100644 --- a/src/views/system/permission/components/form.vue +++ b/src/views/system/permission/components/form.vue @@ -224,11 +224,14 @@ defineExpose({ getRef }); - + @@ -287,7 +290,9 @@ defineExpose({ getRef }); - + { >