feat: 给用户管理、部门管理、权限管理、系统配置、国际化配置、角色管理、登录日志、操作日志、缓存列表、缓存监控和性能监控添加按钮级权限管理;调整加载个人信息逻辑
This commit is contained in:
parent
475a8e4058
commit
c0c127d090
@ -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
|
||||
|
@ -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: 角色权限列表
|
||||
|
@ -31,6 +31,18 @@ export const deleteLocaleAPI = (id: string) => {
|
||||
return http.request<null>("post", `/api/i18n/deleteLocale/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* 批量删除语言类型
|
||||
*/
|
||||
export const deleteLocaleListAPI = (ids: string[]) => {
|
||||
return http.request<null>("post", `/api/i18n/deleteLocaleList`, {
|
||||
data: {
|
||||
ids
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改语言类型
|
||||
*/
|
||||
@ -138,6 +150,18 @@ export const getI18nInfoAPI = (id: string) => {
|
||||
export const deleteI18nAPI = (id: string) => {
|
||||
return http.request<null>("post", `/api/i18n/deleteI18n/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* 批量删除翻译
|
||||
*/
|
||||
export const deleteI18nListAPI = (ids: string[]) => {
|
||||
return http.request<null>("post", `/api/i18n/deleteI18nList`, {
|
||||
data: {
|
||||
ids
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 修改翻译
|
||||
* @param data
|
||||
|
@ -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<QueryListResult<UserLoginLogInfo>>(
|
||||
"get",
|
||||
"/api/log/login",
|
||||
@ -36,24 +53,73 @@ export const deleteUserOnlineAPI = (id: string) => {
|
||||
return http.request<null>("delete", `/api/log/logout/${id}`);
|
||||
};
|
||||
|
||||
/**用户批量强退*/
|
||||
export const deleteUserOnlineListAPI = (data: { ids: string[] }) => {
|
||||
return http.request<null>("delete", `/api/log/logoutList`, { data });
|
||||
};
|
||||
|
||||
/**删除登录日志 */
|
||||
export const deleteUserLoginLogAPI = (id: string) => {
|
||||
return http.request<null>("delete", `/api/log/delete/login/${id}`);
|
||||
};
|
||||
/**批量删除登录日志 */
|
||||
export const deleteUserLoginLogListAPI = (data: { ids: string[] }) => {
|
||||
return http.request<null>("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<QueryListResult<OperationLogInfo>>(
|
||||
"GET",
|
||||
"/api/log/operation",
|
||||
{
|
||||
params
|
||||
params: filterEmptyObject(params)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除操作日志
|
||||
* @returns
|
||||
*/
|
||||
export const deleteUserOperationsAPI = (id: string) => {
|
||||
return http.request<null>("delete", `/api/log/delete/operation/${id}`);
|
||||
};
|
||||
/**批量删除操作日志 */
|
||||
export const deleteUserOperationsListAPI = (data: { ids: string[] }) => {
|
||||
return http.request<null>("delete", `/api/log/deleteList/operation`, {
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
// ------------------------服务相关----------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -318,6 +318,15 @@ export const deleteRoleAPI = (id: string) => {
|
||||
return http.request<null>("post", `/api/role/delete/${id}`);
|
||||
};
|
||||
|
||||
/**批量删除角色 */
|
||||
export const deleteRoleListAPI = (ids: string[]) => {
|
||||
return http.request<null>("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<null>("post", `/api/user/deleteUserList`, { data });
|
||||
};
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -150,7 +150,7 @@ export const useUserStore = defineStore({
|
||||
return new Promise<ResponseResult<LoginResult>>((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<ResponseResult<LoginResult>>((resolve, reject) => {
|
||||
refreshTokenApi(data)
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
if (data.success) {
|
||||
setToken(data.data);
|
||||
}
|
||||
resolve(data);
|
||||
|
@ -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<object>(userInfoKey);
|
||||
storageLocal().setItem(userInfoKey, {
|
||||
...user,
|
||||
...res.data
|
||||
});
|
||||
setUserInfo(res.data);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { message } from "@/utils/message";
|
||||
import Avatar from "@/assets/user.png";
|
||||
import type { FormInstance } from "element-plus";
|
||||
import ReCropperPreview from "@/components/ReCropperPreview";
|
||||
import { deviceDetection } from "@pureadmin/utils";
|
||||
@ -47,7 +48,7 @@ const handleSubmitImage = async () => {
|
||||
const res = await postUploadAvatarAPI(userInfo.id, {
|
||||
file: cropperBlob.value
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message("更新头像成功", { type: "success" });
|
||||
userInfo.avatar = `/file/${res.data.id}`;
|
||||
const user = storageLocal().getItem<object>(userInfoKey);
|
||||
@ -71,7 +72,7 @@ const onSubmit = async (formEl: FormInstance) => {
|
||||
gender: userInfo.gender
|
||||
};
|
||||
const res = await putUpdateBaseUserInfoAPI(updateForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(res.msg, { type: "success" });
|
||||
await getUserInfo();
|
||||
} else {
|
||||
@ -94,7 +95,10 @@ const onSubmit = async (formEl: FormInstance) => {
|
||||
<h3 class="my-8">个人信息</h3>
|
||||
<el-form ref="userInfoFormRef" label-position="top" :model="userInfo">
|
||||
<el-form-item label="头像">
|
||||
<el-avatar :size="80" :src="`/api/${userInfo.avatar}`" />
|
||||
<el-avatar
|
||||
:size="80"
|
||||
:src="userInfo.avatar ? `/api/${userInfo.avatar}` : Avatar"
|
||||
/>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
accept="image/*"
|
||||
|
@ -2,7 +2,6 @@ import { message } from "@/utils/message";
|
||||
import { addDialog } from "@/components/ReDialog";
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { ElForm, ElFormItem, ElInput, ElProgress } from "element-plus";
|
||||
import type { UserInfo } from "types/user";
|
||||
import { getUserInfoAPI } from "@/api/login";
|
||||
import {
|
||||
putUpdateEmailAPI,
|
||||
@ -12,6 +11,7 @@ import {
|
||||
import { isAllEmpty, isEmail, isPhone, storageLocal } from "@pureadmin/utils";
|
||||
import { zxcvbn } from "@zxcvbn-ts/core";
|
||||
import { setUserInfo, userInfoKey } from "@/utils/auth";
|
||||
import type { UserInfo } from "types/system";
|
||||
|
||||
export const useUserInfo = () => {
|
||||
/** 密码正则(密码格式应为8-18位数字、字母、符号的任意两种组合) */
|
||||
@ -52,10 +52,9 @@ export const useUserInfo = () => {
|
||||
nickname: "",
|
||||
phone: "",
|
||||
status: 0,
|
||||
department_id: "",
|
||||
create_time: "",
|
||||
update_time: "",
|
||||
roles: [],
|
||||
permissions: []
|
||||
update_time: ""
|
||||
});
|
||||
/**获取个人信息 */
|
||||
const getUserInfo = async () => {
|
||||
@ -200,7 +199,7 @@ export const useUserInfo = () => {
|
||||
if (valid) {
|
||||
// 表单规则校验通过
|
||||
const res = await putUpdatePasswordAPI(passwordForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
done();
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
@ -262,7 +261,7 @@ export const useUserInfo = () => {
|
||||
if (valid) {
|
||||
// 表单规则校验通过
|
||||
const res = await putUpdatePhoneAPI(phoneForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
done();
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
@ -323,7 +322,7 @@ export const useUserInfo = () => {
|
||||
if (valid) {
|
||||
// 表单规则校验通过
|
||||
const res = await putUpdateEmailAPI(emailForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
done();
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
|
@ -91,7 +91,7 @@ const onUpdate = async (formEl: FormInstance | undefined) => {
|
||||
code: ruleForm.code,
|
||||
department_id: ruleForm.department_id
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(transformI18n($t("login:RegisterSuccess")), {
|
||||
type: "success"
|
||||
});
|
||||
@ -124,10 +124,10 @@ const start = async (
|
||||
if (isValid) {
|
||||
const res = await postGetCodeAPI({
|
||||
username: ruleForm.username,
|
||||
title: "注册",
|
||||
title: "Register",
|
||||
mail: ruleForm.email
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
clearInterval(timer.value);
|
||||
isDisabled.value = true;
|
||||
text.value = `${time}`;
|
||||
|
@ -81,10 +81,10 @@ const start = async (
|
||||
if (isValid) {
|
||||
const res = await postGetCodeAPI({
|
||||
username: ruleForm.username,
|
||||
title: "重置",
|
||||
title: "Reset",
|
||||
mail: ruleForm.email
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
clearInterval(timer.value);
|
||||
isDisabled.value = true;
|
||||
text.value = `${time}`;
|
||||
|
@ -34,8 +34,6 @@ import Check from "@iconify-icons/ep/check";
|
||||
import User from "@iconify-icons/ri/user-3-fill";
|
||||
import Info from "@iconify-icons/ri/information-line";
|
||||
import { GetCaptchaAPI } from "@/api/login";
|
||||
import { getUserInfoAPI } from "@/api/login";
|
||||
import { setUserInfo } from "@/utils/auth";
|
||||
const Period = getConfig("Period");
|
||||
|
||||
defineOptions({
|
||||
@ -88,10 +86,6 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
// 获取后端路由
|
||||
return initRouter().then(async () => {
|
||||
disabled.value = true;
|
||||
const res = await getUserInfoAPI();
|
||||
if (res.success) {
|
||||
setUserInfo(res.data);
|
||||
}
|
||||
router
|
||||
.push(getTopMenu(true).path)
|
||||
.then(() => {
|
||||
|
10
src/views/monitor/cache/index.vue
vendored
10
src/views/monitor/cache/index.vue
vendored
@ -121,6 +121,7 @@ import * as echarts from "echarts";
|
||||
import Monitor from "@iconify-icons/ep/monitor";
|
||||
import PieChart from "@iconify-icons/ep/pie-chart";
|
||||
import Odometer from "@iconify-icons/ep/odometer";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const cache = reactive({
|
||||
commandStats: [] as { name: string; value: number }[],
|
||||
@ -240,13 +241,18 @@ const initUsedMemoryChart = () => {
|
||||
|
||||
chart.setOption(option);
|
||||
};
|
||||
|
||||
/**定时ID */
|
||||
const timer = ref();
|
||||
onMounted(async () => {
|
||||
await getCacheInfo();
|
||||
setInterval(() => {
|
||||
timer.value = setInterval(() => {
|
||||
getCacheInfo();
|
||||
}, 60000);
|
||||
});
|
||||
/**页面离开时清除定时器 */
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(timer.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
6
src/views/monitor/cache/list.vue
vendored
6
src/views/monitor/cache/list.vue
vendored
@ -13,6 +13,7 @@
|
||||
link
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!hasAuth('cache:btn:list')"
|
||||
:icon="useRenderIcon(Refresh)"
|
||||
@click="refreshCacheNames()"
|
||||
/>
|
||||
@ -61,6 +62,7 @@
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:disabled="!hasAuth('cache:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
/>
|
||||
</template>
|
||||
@ -83,6 +85,7 @@
|
||||
type="primary"
|
||||
link
|
||||
size="large"
|
||||
:disabled="!hasAuth('cache:btn:list')"
|
||||
:icon="useRenderIcon(Refresh)"
|
||||
@click="refreshCacheKeys()"
|
||||
/>
|
||||
@ -122,6 +125,7 @@
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:disabled="!hasAuth('cache:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
/>
|
||||
</template>
|
||||
@ -153,6 +157,7 @@
|
||||
style="float: right; padding: 3px 0"
|
||||
link
|
||||
type="primary"
|
||||
:disabled="!hasAuth('cache:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>清理全部</el-button
|
||||
>
|
||||
@ -207,6 +212,7 @@ import Document from "@iconify-icons/ep/document";
|
||||
import Delete from "@iconify-icons/ep/delete";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import { message } from "@/utils/message";
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
defineOptions({
|
||||
name: "CacheList"
|
||||
});
|
||||
|
@ -5,9 +5,10 @@ import { getPickerShortcuts } from "../utils";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Delete from "@iconify-icons/ep/delete";
|
||||
import Plane from "@iconify-icons/ri/plane-line";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
defineOptions({
|
||||
name: "MonitorLogin"
|
||||
});
|
||||
@ -23,13 +24,16 @@ const {
|
||||
dataList,
|
||||
pagination,
|
||||
selectedNum,
|
||||
departments,
|
||||
onSearch,
|
||||
deleteUserHandle,
|
||||
resetForm,
|
||||
onbatchDel,
|
||||
onbatchForce,
|
||||
resetForm,
|
||||
deleteUserHandle,
|
||||
onSelectionCancel,
|
||||
handleCurrentChange,
|
||||
handleSizeChange,
|
||||
handleDelete,
|
||||
handleSelectionChange
|
||||
} = useLogin(tableRef);
|
||||
</script>
|
||||
@ -42,12 +46,20 @@ const {
|
||||
:model="form"
|
||||
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
|
||||
>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-form-item label="用户账号" prop="username">
|
||||
<el-input
|
||||
v-model="form.username"
|
||||
placeholder="请输入用户名"
|
||||
placeholder="请输入用户账号~"
|
||||
clearable
|
||||
class="!w-[150px]"
|
||||
class="!w-[200px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名称" prop="nickname">
|
||||
<el-input
|
||||
v-model="form.nickname"
|
||||
placeholder="请输入用户名称~"
|
||||
clearable
|
||||
class="!w-[200px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录状态" prop="status">
|
||||
@ -55,12 +67,33 @@ const {
|
||||
v-model="form.status"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
class="!w-[150px]"
|
||||
class="!w-[200px]"
|
||||
>
|
||||
<el-option label="成功" value="1" />
|
||||
<el-option label="失败" value="0" />
|
||||
<el-option label="成功" :value="1" />
|
||||
<el-option label="失败" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门:" prop="department_id">
|
||||
<el-cascader
|
||||
v-model="form.department_id"
|
||||
class="!w-[200px]"
|
||||
:options="departments"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
emitPath: false,
|
||||
checkStrictly: true
|
||||
}"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择所属部门~"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||
</template>
|
||||
</el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录时间" prop="loginTime">
|
||||
<el-date-picker
|
||||
v-model="form.loginTime"
|
||||
@ -69,6 +102,8 @@ const {
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期时间"
|
||||
end-placeholder="结束日期时间"
|
||||
value-format="x"
|
||||
unlink-panels
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@ -86,16 +121,7 @@ const {
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<PureTableBar title="登录日志" :columns="columns" @refresh="onSearch">
|
||||
<!-- <template #buttons>
|
||||
<el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
|
||||
<template #reference>
|
||||
<el-button type="danger" :icon="useRenderIcon(Delete)">
|
||||
清空日志
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template> -->
|
||||
<PureTableBar title="登录日志管理" :columns="columns" @refresh="onSearch">
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<div
|
||||
v-if="selectedNum > 0"
|
||||
@ -113,9 +139,34 @@ const {
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('login:btn:logout')"
|
||||
title="是否确认强制退出?"
|
||||
@confirm="onbatchForce"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" text class="mr-1">
|
||||
<el-button
|
||||
type="warning"
|
||||
text
|
||||
class="mr-1"
|
||||
:disabled="selectedNum < 0 || !hasAuth('login:btn:logout')"
|
||||
>
|
||||
{{ t("buttons:ExitInBatches") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('login:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
class="mr-1"
|
||||
:disabled="selectedNum < 0 || !hasAuth('login:btn:delete')"
|
||||
>
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
</el-button>
|
||||
</template>
|
||||
@ -142,6 +193,23 @@ const {
|
||||
@page-current-change="handleCurrentChange"
|
||||
>
|
||||
<template #operation="{ row }">
|
||||
<el-popconfirm
|
||||
:title="`是否删除这条登录记录?`"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="danger"
|
||||
:disabled="!hasAuth('login:btn:delete')"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm
|
||||
:title="`是否强制下线${row.username}`"
|
||||
@confirm="deleteUserHandle(row.session_id)"
|
||||
@ -151,7 +219,7 @@ const {
|
||||
class="reset-margin"
|
||||
link
|
||||
type="primary"
|
||||
:disabled="!row.online"
|
||||
:disabled="!row.online || !hasAuth('login:btn:logout')"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(Plane)"
|
||||
>
|
||||
|
@ -1,17 +1,27 @@
|
||||
import dayjs from "dayjs";
|
||||
import { message } from "@/utils/message";
|
||||
import { getKeyList } from "@pureadmin/utils";
|
||||
import { deleteUserOnlineAPI, getUserLoginLogAPI } from "@/api/monitor";
|
||||
import { getKeyList, handleTree } from "@pureadmin/utils";
|
||||
import {
|
||||
deleteUserOnlineAPI,
|
||||
getUserLoginLogAPI,
|
||||
deleteUserLoginLogAPI,
|
||||
deleteUserOnlineListAPI,
|
||||
deleteUserLoginLogListAPI
|
||||
} from "@/api/monitor";
|
||||
import { usePublicHooks } from "@/views/system/hooks";
|
||||
import type { PaginationProps } from "@pureadmin/table";
|
||||
import { type Ref, reactive, ref, onMounted } from "vue";
|
||||
import type { UserLoginLogInfo } from "types/monitor";
|
||||
import type { DepartmentInfo } from "types/system";
|
||||
import { getDepartmentListAPI } from "@/api/system";
|
||||
|
||||
export const useLogin = (tableRef: Ref) => {
|
||||
const form = reactive({
|
||||
username: "",
|
||||
nickname: "",
|
||||
status: "",
|
||||
loginTime: ""
|
||||
department_id: "",
|
||||
loginTime: []
|
||||
});
|
||||
/**
|
||||
* 表格数据
|
||||
@ -93,6 +103,16 @@ export const useLogin = (tableRef: Ref) => {
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "在线状态",
|
||||
prop: "online",
|
||||
minWidth: 100,
|
||||
cellRenderer: ({ row, props }) => (
|
||||
<el-tag size={props.size} type={row.online ? "success" : ""}>
|
||||
{row.online ? "在线" : "离线"}
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "登录时间",
|
||||
prop: "login_time",
|
||||
@ -103,7 +123,8 @@ export const useLogin = (tableRef: Ref) => {
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
slot: "operation"
|
||||
slot: "operation",
|
||||
width: 200
|
||||
}
|
||||
];
|
||||
|
||||
@ -114,12 +135,19 @@ export const useLogin = (tableRef: Ref) => {
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
const res = await getUserLoginLogAPI({
|
||||
page: val,
|
||||
pageSize: pagination.pageSize
|
||||
pageSize: pagination.pageSize,
|
||||
department_id: form.department_id,
|
||||
status: form.status,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
startTime: form.loginTime[0] ? form.loginTime[0] : null,
|
||||
endTime: form.loginTime[1] ? form.loginTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
};
|
||||
|
||||
@ -127,12 +155,19 @@ export const useLogin = (tableRef: Ref) => {
|
||||
const handleSizeChange = async (val: number) => {
|
||||
const res = await getUserLoginLogAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: val
|
||||
pageSize: val,
|
||||
department_id: form.department_id,
|
||||
status: form.status,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
startTime: form.loginTime[0] ? form.loginTime[0] : null,
|
||||
endTime: form.loginTime[1] ? form.loginTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
};
|
||||
|
||||
@ -149,38 +184,77 @@ export const useLogin = (tableRef: Ref) => {
|
||||
// 用于多选表格,清空用户的选择
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
};
|
||||
|
||||
/**处理删除 */
|
||||
/**
|
||||
* 处理删除
|
||||
* @param row
|
||||
*/
|
||||
const handleDelete = async (row: UserLoginLogInfo) => {
|
||||
const res = await deleteUserLoginLogAPI(row.id);
|
||||
if (res.success) {
|
||||
onSearch();
|
||||
}
|
||||
message(res.msg, {
|
||||
type: res.success ? "success" : "error"
|
||||
});
|
||||
};
|
||||
/** 批量删除 */
|
||||
const onbatchDel = () => {
|
||||
const onbatchDel = async () => {
|
||||
// 返回当前选中的行
|
||||
const curSelected = tableRef.value.getTableRef().getSelectionRows();
|
||||
// 接下来根据实际业务,通过选中行的某项数据,比如下面的id,调用接口进行批量删除
|
||||
message(`已删除序号为 ${getKeyList(curSelected, "id")} 的数据`, {
|
||||
type: "success"
|
||||
const res = await deleteUserLoginLogListAPI({
|
||||
ids: getKeyList(curSelected, "id")
|
||||
});
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
onSearch();
|
||||
if (res.success) {
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
});
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
onSearch();
|
||||
} else {
|
||||
message(res.msg, {
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** 清空日志 */
|
||||
const clearAll = async () => {
|
||||
// 根据实际业务,调用接口删除所有日志数据
|
||||
message("已删除所有日志数据", {
|
||||
type: "success"
|
||||
/**批量强退 */
|
||||
const onbatchForce = async () => {
|
||||
// 返回当前选中的行
|
||||
const curSelected = tableRef.value.getTableRef().getSelectionRows();
|
||||
const res = await deleteUserOnlineListAPI({
|
||||
ids: getKeyList(curSelected, "id")
|
||||
});
|
||||
await onSearch();
|
||||
if (res.success) {
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
});
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
onSearch();
|
||||
} else {
|
||||
message(res.msg, {
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onSearch = async () => {
|
||||
loading.value = true;
|
||||
const res = await getUserLoginLogAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize
|
||||
pageSize: pagination.pageSize,
|
||||
department_id: form.department_id,
|
||||
status: form.status,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
startTime: form.loginTime[0] ? form.loginTime[0] : null,
|
||||
endTime: form.loginTime[1] ? form.loginTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
@ -201,9 +275,34 @@ export const useLogin = (tableRef: Ref) => {
|
||||
onSearch();
|
||||
}
|
||||
};
|
||||
/**部门列表 */
|
||||
const departments = ref<DepartmentInfo[]>([]);
|
||||
/**获取部门列表 */
|
||||
const getDepartments = async () => {
|
||||
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||
if (res.success) {
|
||||
departments.value = formatHigherOptions(
|
||||
handleTree(res.data.result, "id", "parent_id")
|
||||
);
|
||||
} else {
|
||||
departments.value = [];
|
||||
}
|
||||
};
|
||||
const formatHigherOptions = (treeList: any) => {
|
||||
// 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示(实际开发中也是如此,不可能前端需要的每个字段后端都会返回,这时需要前端自行根据后端返回的某些字段做逻辑处理)
|
||||
if (!treeList || !treeList.length) return;
|
||||
const newTreeList = [];
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
treeList[i].disabled = treeList[i].status === 0 ? true : false;
|
||||
formatHigherOptions(treeList[i].children);
|
||||
newTreeList.push(treeList[i]);
|
||||
}
|
||||
return newTreeList;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
onSearch();
|
||||
onMounted(async () => {
|
||||
await onSearch();
|
||||
await getDepartments();
|
||||
});
|
||||
|
||||
return {
|
||||
@ -213,14 +312,16 @@ export const useLogin = (tableRef: Ref) => {
|
||||
dataList,
|
||||
pagination,
|
||||
selectedNum,
|
||||
departments,
|
||||
onSearch,
|
||||
clearAll,
|
||||
resetForm,
|
||||
onbatchDel,
|
||||
onbatchForce,
|
||||
resetForm,
|
||||
deleteUserHandle,
|
||||
onSelectionCancel,
|
||||
handleCurrentChange,
|
||||
handleSizeChange,
|
||||
handleDelete,
|
||||
handleSelectionChange
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import dayjs from "dayjs";
|
||||
import { ref, reactive, computed } from "vue";
|
||||
import { useOperation } from "./hook";
|
||||
import { useOperation } from "./utils/hook";
|
||||
import { getPickerShortcuts } from "../utils";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
@ -12,7 +12,7 @@ import View from "@iconify-icons/ep/view";
|
||||
import Delete from "@iconify-icons/ep/delete";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import { OperationLogInfo } from "types/monitor";
|
||||
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
defineOptions({
|
||||
name: "OperationLog"
|
||||
});
|
||||
@ -86,11 +86,12 @@ const {
|
||||
dataList,
|
||||
pagination,
|
||||
selectedNum,
|
||||
departments,
|
||||
onSearch,
|
||||
clearAll,
|
||||
resetForm,
|
||||
onbatchDel,
|
||||
getOperationName,
|
||||
handleDelete,
|
||||
handleSizeChange,
|
||||
onSelectionCancel,
|
||||
handleCurrentChange,
|
||||
@ -106,33 +107,89 @@ const {
|
||||
:model="form"
|
||||
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
|
||||
>
|
||||
<el-form-item label="所属模块" prop="module">
|
||||
<el-form-item label="操作名称" prop="name">
|
||||
<el-input
|
||||
v-model="form.module"
|
||||
placeholder="请输入所属模块"
|
||||
v-model="form.name"
|
||||
placeholder="请输入操作名称"
|
||||
clearable
|
||||
class="!w-[170px]"
|
||||
class="!w-[200px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作类型" prop="type">
|
||||
<el-select
|
||||
v-model="form.type"
|
||||
placeholder="请选择操作类型~"
|
||||
clearable
|
||||
class="!w-[200px]"
|
||||
>
|
||||
<el-option label="查询" :value="1" />
|
||||
<el-option label="新增" :value="2" />
|
||||
<el-option label="修改" :value="3" />
|
||||
<el-option label="删除" :value="4" />
|
||||
<el-option label="授权" :value="5" />
|
||||
<el-option label="导出" :value="6" />
|
||||
<el-option label="导入" :value="7" />
|
||||
<el-option label="强退" :value="8" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户账号" prop="username">
|
||||
<el-input
|
||||
v-model="form.username"
|
||||
placeholder="请输入用户账号~"
|
||||
clearable
|
||||
class="!w-[200px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名称" prop="nickname">
|
||||
<el-input
|
||||
v-model="form.nickname"
|
||||
placeholder="请输入用户名称~"
|
||||
clearable
|
||||
class="!w-[200px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作状态" prop="status">
|
||||
<el-select
|
||||
v-model="form.status"
|
||||
placeholder="请选择"
|
||||
placeholder="请选择操作状态~"
|
||||
clearable
|
||||
class="!w-[150px]"
|
||||
class="!w-[200px]"
|
||||
>
|
||||
<el-option label="成功" value="1" />
|
||||
<el-option label="失败" value="0" />
|
||||
<el-option label="成功" :value="1" />
|
||||
<el-option label="失败" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门:" prop="department_id">
|
||||
<el-cascader
|
||||
v-model="form.department_id"
|
||||
class="!w-[200px]"
|
||||
:options="departments"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
emitPath: false,
|
||||
checkStrictly: true
|
||||
}"
|
||||
clearable
|
||||
filterable
|
||||
placeholder="请选择所属部门~"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||
</template>
|
||||
</el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作时间" prop="operatingTime">
|
||||
<el-date-picker
|
||||
v-model="form.operatingTime"
|
||||
v-model="form.operationTime"
|
||||
:shortcuts="getPickerShortcuts()"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期时间"
|
||||
end-placeholder="结束日期时间"
|
||||
value-format="x"
|
||||
unlink-panels
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@ -151,15 +208,6 @@ const {
|
||||
</el-form>
|
||||
|
||||
<PureTableBar title="操作日志" :columns="columns" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<!-- <el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
|
||||
<template #reference>
|
||||
<el-button type="danger" :icon="useRenderIcon(Delete)">
|
||||
清空日志
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm> -->
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<div
|
||||
v-if="selectedNum > 0"
|
||||
@ -177,9 +225,18 @@ const {
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('operation:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" text class="mr-1">
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
class="mr-1"
|
||||
:disabled="selectedNum < 0 || !hasAuth('operation:btn:delete')"
|
||||
>
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
</el-button>
|
||||
</template>
|
||||
@ -211,11 +268,29 @@ const {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('operation:btn:info')"
|
||||
:icon="useRenderIcon(View)"
|
||||
@click="onDetailHandle(row)"
|
||||
>
|
||||
{{ t("buttons:Details") }}
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
:title="`是否删除这条操作记录?`"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="danger"
|
||||
:disabled="!hasAuth('operation:btn:delete')"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
|
384
src/views/monitor/operation/utils/hook.tsx
Normal file
384
src/views/monitor/operation/utils/hook.tsx
Normal file
@ -0,0 +1,384 @@
|
||||
import dayjs from "dayjs";
|
||||
// import Detail from "../components/form.vue";
|
||||
import { message } from "@/utils/message";
|
||||
// import { addDialog } from "@/components/ReDialog";
|
||||
import { getKeyList, handleTree } from "@pureadmin/utils";
|
||||
import {
|
||||
getUserOperationsAPI,
|
||||
deleteUserOperationsAPI,
|
||||
deleteUserOperationsListAPI
|
||||
} from "@/api/monitor";
|
||||
import { usePublicHooks } from "@/views/system/hooks";
|
||||
import type { PaginationProps } from "@pureadmin/table";
|
||||
import { type Ref, reactive, ref, onMounted } from "vue";
|
||||
import type { OperationLogInfo } from "types/monitor";
|
||||
import type { DepartmentInfo } from "types/system";
|
||||
import { getDepartmentListAPI } from "@/api/system";
|
||||
|
||||
export function useOperation(tableRef: Ref) {
|
||||
const form = reactive({
|
||||
name: "",
|
||||
type: "",
|
||||
username: "",
|
||||
nickname: "",
|
||||
status: "",
|
||||
department_id: "",
|
||||
operationTime: ""
|
||||
});
|
||||
const dataList = ref<OperationLogInfo[]>([]);
|
||||
const loading = ref(true);
|
||||
const selectedNum = ref(0);
|
||||
const { tagStyle } = usePublicHooks();
|
||||
|
||||
const pagination = reactive<PaginationProps>({
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
background: true,
|
||||
pageSizes: [10, 20, 30, 40, 50]
|
||||
});
|
||||
|
||||
const getOperationType = (type: number) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return "primary";
|
||||
case 2:
|
||||
return "success";
|
||||
case 3:
|
||||
return "warning";
|
||||
case 4:
|
||||
return "danger";
|
||||
case 5:
|
||||
return "success";
|
||||
case 6:
|
||||
return "primary";
|
||||
case 7:
|
||||
return "success";
|
||||
case 8:
|
||||
return "danger";
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
};
|
||||
const getOperationName = (type: number) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return "查询";
|
||||
case 2:
|
||||
return "新增";
|
||||
case 3:
|
||||
return "修改";
|
||||
case 4:
|
||||
return "删除";
|
||||
case 5:
|
||||
return "授权";
|
||||
case 6:
|
||||
return "导出";
|
||||
case 7:
|
||||
return "导入";
|
||||
case 8:
|
||||
return "强退";
|
||||
default:
|
||||
return "其他";
|
||||
}
|
||||
};
|
||||
const getRequestType = (method: string) => {
|
||||
switch (method) {
|
||||
case "GET":
|
||||
return "primary";
|
||||
case "POST":
|
||||
return "success";
|
||||
case "PUT":
|
||||
return "warning";
|
||||
case "DELETE":
|
||||
return "danger";
|
||||
case "PATCH":
|
||||
return "info";
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
};
|
||||
const columns: TableColumnList = [
|
||||
{
|
||||
label: "勾选列", // 如果需要表格多选,此处label必须设置
|
||||
type: "selection",
|
||||
fixed: "left",
|
||||
reserveSelection: true // 数据刷新后保留选项
|
||||
},
|
||||
{
|
||||
label: "操作人员账号",
|
||||
prop: "operator_name"
|
||||
},
|
||||
{
|
||||
label: "操作人员昵称",
|
||||
prop: "operator_nickname"
|
||||
},
|
||||
{
|
||||
label: "所属部门",
|
||||
prop: "department_name"
|
||||
},
|
||||
{
|
||||
label: "操作名称",
|
||||
prop: "operation_name"
|
||||
},
|
||||
{
|
||||
label: "操作类型",
|
||||
prop: "operation_type",
|
||||
cellRenderer: ({ row, props }) => (
|
||||
<el-tag size={props.size} type={getOperationType(row.operation_type)}>
|
||||
{getOperationName(row.operation_type)}
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "操作IP",
|
||||
prop: "host"
|
||||
},
|
||||
{
|
||||
label: "操作地点",
|
||||
prop: "location"
|
||||
},
|
||||
{
|
||||
label: "请求方法",
|
||||
prop: "request_method",
|
||||
cellRenderer: ({ row, props }) => (
|
||||
<el-tag size={props.size} type={getRequestType(row.request_method)}>
|
||||
{row.request_method}
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "请求路径",
|
||||
prop: "request_path"
|
||||
},
|
||||
{
|
||||
label: "请求耗时",
|
||||
prop: "cost_time",
|
||||
cellRenderer: ({ row, props }) => (
|
||||
<el-tag
|
||||
size={props.size}
|
||||
type={row.cost_time < 1000 ? "success" : "warning"}
|
||||
effect="plain"
|
||||
>
|
||||
{row.cost_time.toFixed(2)} ms
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "操作系统",
|
||||
prop: "os",
|
||||
hide: true
|
||||
},
|
||||
{
|
||||
label: "浏览器类型",
|
||||
prop: "browser",
|
||||
hide: true
|
||||
},
|
||||
{
|
||||
label: "操作状态",
|
||||
prop: "status",
|
||||
cellRenderer: ({ row, props }) => (
|
||||
<el-tag size={props.size} style={tagStyle.value(row.status)}>
|
||||
{row.status === 1 ? "成功" : "失败"}
|
||||
</el-tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "操作时间",
|
||||
prop: "operation_time",
|
||||
minWidth: 180,
|
||||
formatter: ({ operation_time }) =>
|
||||
dayjs(operation_time).format("YYYY-MM-DD HH:mm:ss")
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 180,
|
||||
slot: "operation"
|
||||
}
|
||||
];
|
||||
|
||||
const handleSizeChange = async (val: number) => {
|
||||
const res = await getUserOperationsAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: val,
|
||||
name: form.name,
|
||||
type: form.type,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
status: form.status,
|
||||
department_id: form.department_id,
|
||||
startTime: form.operationTime[0] ? form.operationTime[0] : null,
|
||||
endTime: form.operationTime[1] ? form.operationTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
const res = await getUserOperationsAPI({
|
||||
page: val,
|
||||
pageSize: pagination.pageSize,
|
||||
name: form.name,
|
||||
type: form.type,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
status: form.status,
|
||||
department_id: form.department_id,
|
||||
startTime: form.operationTime[0] ? form.operationTime[0] : null,
|
||||
endTime: form.operationTime[1] ? form.operationTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
};
|
||||
|
||||
/** 当CheckBox选择项发生变化时会触发该事件 */
|
||||
const handleSelectionChange = val => {
|
||||
selectedNum.value = val.length;
|
||||
// 重置表格高度
|
||||
tableRef.value.setAdaptive();
|
||||
};
|
||||
|
||||
/** 取消选择 */
|
||||
const onSelectionCancel = () => {
|
||||
selectedNum.value = 0;
|
||||
// 用于多选表格,清空用户的选择
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
};
|
||||
/**
|
||||
* 处理删除
|
||||
* @param row
|
||||
*/
|
||||
const handleDelete = async (row: OperationLogInfo) => {
|
||||
const res = await deleteUserOperationsAPI(row.id);
|
||||
if (res.success) {
|
||||
onSearch();
|
||||
}
|
||||
message(res.msg, {
|
||||
type: res.success ? "success" : "error"
|
||||
});
|
||||
};
|
||||
/** 批量删除 */
|
||||
const onbatchDel = async () => {
|
||||
// 返回当前选中的行
|
||||
const curSelected = tableRef.value.getTableRef().getSelectionRows();
|
||||
const res = await deleteUserOperationsListAPI({
|
||||
ids: getKeyList(curSelected, "id")
|
||||
});
|
||||
if (res.success) {
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
});
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
onSearch();
|
||||
} else {
|
||||
message(res.msg, {
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onSearch = async () => {
|
||||
loading.value = true;
|
||||
const res = await getUserOperationsAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
name: form.name,
|
||||
type: form.type,
|
||||
username: form.username,
|
||||
nickname: form.nickname,
|
||||
status: form.status,
|
||||
department_id: form.department_id,
|
||||
startTime: form.operationTime[0] ? form.operationTime[0] : null,
|
||||
endTime: form.operationTime[1] ? form.operationTime[1] : null
|
||||
});
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const resetForm = formEl => {
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
onSearch();
|
||||
};
|
||||
|
||||
// const onDetailHandle = () => {
|
||||
// addDialog({
|
||||
// title: `详情`,
|
||||
// props: {},
|
||||
// width: "40%",
|
||||
// draggable: true,
|
||||
// fullscreenIcon: true,
|
||||
// closeOnClickModal: false,
|
||||
// contentRenderer: () => h(Detail, {}),
|
||||
// beforeSure: (done, {}) => {
|
||||
// done();
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
/**部门列表 */
|
||||
const departments = ref<DepartmentInfo[]>([]);
|
||||
/**获取部门列表 */
|
||||
const getDepartments = async () => {
|
||||
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||
if (res.success) {
|
||||
departments.value = formatHigherOptions(
|
||||
handleTree(res.data.result, "id", "parent_id")
|
||||
);
|
||||
} else {
|
||||
departments.value = [];
|
||||
}
|
||||
};
|
||||
const formatHigherOptions = (treeList: any) => {
|
||||
// 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示(实际开发中也是如此,不可能前端需要的每个字段后端都会返回,这时需要前端自行根据后端返回的某些字段做逻辑处理)
|
||||
if (!treeList || !treeList.length) return;
|
||||
const newTreeList = [];
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
treeList[i].disabled = treeList[i].status === 0 ? true : false;
|
||||
formatHigherOptions(treeList[i].children);
|
||||
newTreeList.push(treeList[i]);
|
||||
}
|
||||
return newTreeList;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await onSearch();
|
||||
await getDepartments();
|
||||
});
|
||||
|
||||
return {
|
||||
form,
|
||||
loading,
|
||||
columns,
|
||||
dataList,
|
||||
pagination,
|
||||
selectedNum,
|
||||
departments,
|
||||
onSearch,
|
||||
resetForm,
|
||||
onbatchDel,
|
||||
getOperationName,
|
||||
handleDelete,
|
||||
handleSizeChange,
|
||||
onSelectionCancel,
|
||||
handleCurrentChange,
|
||||
handleSelectionChange
|
||||
};
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
<PureTableBar title="配置管理" :columns="columns" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('config:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog('新增')"
|
||||
@ -69,7 +70,11 @@
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('config:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" text class="mr-1">
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
@ -106,6 +111,7 @@
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('config:btn:update')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
@ -119,6 +125,7 @@
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
:disabled="!hasAuth('config:btn:delete')"
|
||||
type="danger"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
@ -148,6 +155,7 @@ import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
const { t } = useI18n();
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
/**
|
||||
* 表格Ref
|
||||
*/
|
||||
|
@ -202,7 +202,7 @@ export const useConfig = (tableRef: Ref) => {
|
||||
const res = await deleteConfigListAPI({
|
||||
ids: getKeyList(curSelected, "id")
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`已删除项目名称为 ${getKeyList(curSelected, "name")} 的数据`, {
|
||||
type: "success"
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
import { onBeforeRouteUpdate } from "vue-router";
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
|
||||
defineOptions({
|
||||
name: "SystemDepartment"
|
||||
@ -82,6 +83,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
>
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('department:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog()"
|
||||
@ -117,6 +119,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('department:btn:update')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
@ -127,6 +130,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('department:btn:add')"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog('新增', { parent_id: row.id } as any)"
|
||||
>
|
||||
@ -142,6 +146,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="danger"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('department:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
|
@ -219,7 +219,7 @@ export const useDepartment = () => {
|
||||
*/
|
||||
const handleDelete = async (row: DepartmentInfo) => {
|
||||
const res = await deleteDepartmentAPI(row.id);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`您删除了部门:${row.name}及其附属部门`, { type: "success" });
|
||||
onSearch();
|
||||
} else {
|
||||
|
@ -54,6 +54,7 @@
|
||||
<PureTableBar title="国际化管理" :columns="columns" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('i18n:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog('新增')"
|
||||
@ -78,9 +79,18 @@
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?">
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('i18n:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" text class="mr-1">
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
class="mr-1"
|
||||
:disabled="selectedNum < 0 || !hasAuth('i18n:btn:delete')"
|
||||
>
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
</el-button>
|
||||
</template>
|
||||
@ -115,6 +125,7 @@
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('i18n:btn:update')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
@ -130,6 +141,7 @@
|
||||
link
|
||||
type="danger"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('i18n:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
@ -148,7 +160,7 @@ defineOptions({
|
||||
name: "I18nIndex"
|
||||
});
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "./hook";
|
||||
import { useI18n } from "./utils/hook";
|
||||
import { useI18n as i18n } from "vue-i18n";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
@ -156,6 +168,7 @@ import Delete from "@iconify-icons/ep/delete";
|
||||
import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
const { t } = i18n();
|
||||
/**
|
||||
* 表格Ref
|
||||
@ -177,7 +190,8 @@ const {
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
handleSelectionChange,
|
||||
onSelectionCancel
|
||||
onSelectionCancel,
|
||||
onbatchDel
|
||||
} = useI18n(tableRef);
|
||||
</script>
|
||||
|
||||
|
308
src/views/system/i18n/utils/hook.tsx
Normal file
308
src/views/system/i18n/utils/hook.tsx
Normal file
@ -0,0 +1,308 @@
|
||||
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 {
|
||||
deleteI18nAPI,
|
||||
deleteI18nListAPI,
|
||||
getI18nListAPI,
|
||||
getLocaleListAPI,
|
||||
postAddI18nAPI,
|
||||
putUpdateI18nAPI
|
||||
} from "@/api/i18n";
|
||||
import { getKeyList } from "@pureadmin/utils";
|
||||
|
||||
export const useI18n = (tableRef: Ref) => {
|
||||
/**
|
||||
* 查询表单
|
||||
*/
|
||||
const form = reactive({
|
||||
key: "",
|
||||
locale_id: "",
|
||||
translation: ""
|
||||
});
|
||||
/**
|
||||
* 表单Ref
|
||||
*/
|
||||
const formRef = ref(null);
|
||||
/**
|
||||
* 数据列表
|
||||
*/
|
||||
const dataList = ref<TranslationInfo[]>([]);
|
||||
/**
|
||||
* 加载状态
|
||||
*/
|
||||
const loading = ref(true);
|
||||
/**
|
||||
* 已选数量
|
||||
*/
|
||||
const selectedNum = ref<number>(0);
|
||||
/**
|
||||
* 分页参数
|
||||
*/
|
||||
const pagination = reactive<PaginationProps>({
|
||||
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: "国际化key",
|
||||
prop: "key"
|
||||
},
|
||||
{
|
||||
label: "国际化值",
|
||||
prop: "translation"
|
||||
},
|
||||
{
|
||||
label: "语言编码",
|
||||
prop: "locale_code"
|
||||
},
|
||||
{
|
||||
label: "语言名称",
|
||||
prop: "locale_name"
|
||||
},
|
||||
{
|
||||
label: "创建时间",
|
||||
prop: "create_time",
|
||||
formatter: ({ create_time }) =>
|
||||
dayjs(create_time).format("YYYY-MM-DD HH:mm:ss")
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 220,
|
||||
slot: "operation"
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* 初次查询
|
||||
*/
|
||||
const onSearch = async () => {
|
||||
loading.value = true;
|
||||
const res = await getI18nListAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
key: form.key,
|
||||
locale_id: form.locale_id,
|
||||
translation: form.translation
|
||||
});
|
||||
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 deleteI18nAPI(row.id);
|
||||
if (res.success) {
|
||||
onSearch();
|
||||
}
|
||||
message(res.msg, {
|
||||
type: res.success ? "success" : "error"
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 处理每页数量变化
|
||||
*/
|
||||
const handleSizeChange = async (val: number) => {
|
||||
const res = await getI18nListAPI({
|
||||
page: pagination.currentPage,
|
||||
pageSize: val,
|
||||
key: form.key,
|
||||
locale_id: form.locale_id,
|
||||
translation: form.translation
|
||||
});
|
||||
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 getI18nListAPI({
|
||||
page: val,
|
||||
pageSize: pagination.pageSize,
|
||||
key: form.key,
|
||||
locale_id: form.locale_id,
|
||||
translation: form.translation
|
||||
});
|
||||
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 deleteI18nListAPI(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?: TranslationInfo) => {
|
||||
addDialog({
|
||||
title: `${title}国际化项`,
|
||||
props: {
|
||||
formInline: {
|
||||
title: title,
|
||||
key: row?.key ?? "",
|
||||
locale_id: row?.locale_id ?? "",
|
||||
translation: row?.translation ?? ""
|
||||
}
|
||||
},
|
||||
width: "45%",
|
||||
draggable: true,
|
||||
fullscreenIcon: true,
|
||||
closeOnClickModal: false,
|
||||
contentRenderer: () =>
|
||||
h(editForm, {
|
||||
formInline: {
|
||||
title: title,
|
||||
key: row?.key ?? "",
|
||||
locale_id: row?.locale_id ?? "",
|
||||
translation: row?.translation ?? ""
|
||||
},
|
||||
ref: formRef
|
||||
}),
|
||||
beforeSure: async (done, {}) => {
|
||||
const FormData = formRef.value.newFormInline;
|
||||
let form = {
|
||||
key: FormData.key ?? "",
|
||||
locale_id: FormData.locale_id ?? "",
|
||||
translation: FormData.translation ?? ""
|
||||
};
|
||||
if (title === "新增") {
|
||||
const res = await postAddI18nAPI(form);
|
||||
if (res.success) {
|
||||
done();
|
||||
await onSearch();
|
||||
}
|
||||
message(res.msg, { type: res.success ? "success" : "error" });
|
||||
} else {
|
||||
const res = await putUpdateI18nAPI(form, row.id);
|
||||
if (res.success) {
|
||||
done();
|
||||
await onSearch();
|
||||
}
|
||||
message(res.msg, { type: res.success ? "success" : "error" });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**语言类型 */
|
||||
const localeList = ref<LanguageInfo[]>([]);
|
||||
|
||||
/**
|
||||
* 获取语言类型
|
||||
*/
|
||||
const getLocaleList = async () => {
|
||||
const res = await getLocaleListAPI({
|
||||
page: 1,
|
||||
pageSize: 9999
|
||||
});
|
||||
if (res.success) {
|
||||
localeList.value = res.data.result;
|
||||
}
|
||||
message(res.msg, {
|
||||
type: res.success ? "success" : "error"
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 页面加载执行
|
||||
*/
|
||||
onMounted(async () => {
|
||||
await onSearch();
|
||||
await getLocaleList();
|
||||
});
|
||||
|
||||
return {
|
||||
form,
|
||||
formRef,
|
||||
dataList,
|
||||
loading,
|
||||
pagination,
|
||||
columns,
|
||||
selectedNum,
|
||||
localeList,
|
||||
onSearch,
|
||||
openDialog,
|
||||
resetForm,
|
||||
handleDelete,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
handleSelectionChange,
|
||||
onSelectionCancel,
|
||||
onbatchDel,
|
||||
getLocaleList
|
||||
};
|
||||
};
|
50
src/views/system/locale/components/form.vue
Normal file
50
src/views/system/locale/components/form.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<el-form ref="ruleFormRef" :model="newFormInline" label-width="82px">
|
||||
<el-row :gutter="30">
|
||||
<re-col :value="24" :xm="24" :sm="24">
|
||||
<el-form-item label="语言编码" prop="code">
|
||||
<el-input
|
||||
v-model="newFormInline.code"
|
||||
placeholder="请输入语言编码~"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</el-form-item>
|
||||
</re-col>
|
||||
<re-col :value="24" :xm="24" :sm="24">
|
||||
<el-form-item label="语言名称" prop="name">
|
||||
<el-input
|
||||
v-model="newFormInline.name"
|
||||
placeholder="请输入语言名称~"
|
||||
clearable
|
||||
class="w-full"
|
||||
/>
|
||||
</el-form-item>
|
||||
</re-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import ReCol from "@/components/ReCol";
|
||||
const ruleFormRef = ref();
|
||||
interface PropsInfo {
|
||||
title: string;
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ProsData = {
|
||||
formInline: PropsInfo;
|
||||
};
|
||||
const props = withDefaults(defineProps<ProsData>(), {
|
||||
formInline: () => ({
|
||||
title: "新增",
|
||||
code: "",
|
||||
name: ""
|
||||
})
|
||||
});
|
||||
const newFormInline = ref<PropsInfo>(props.formInline);
|
||||
defineExpose({ newFormInline });
|
||||
</script>
|
219
src/views/system/locale/index.vue
Normal file
219
src/views/system/locale/index.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:inline="true"
|
||||
:model="form"
|
||||
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
|
||||
>
|
||||
<el-form-item label="语言编码" prop="code">
|
||||
<el-input
|
||||
v-model="form.code"
|
||||
placeholder="请输入语言编码~"
|
||||
clearable
|
||||
class="!w-[180px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="语言名称" prop="name">
|
||||
<el-input
|
||||
v-model="form.name"
|
||||
placeholder="请输入语言名称~"
|
||||
clearable
|
||||
class="!w-[180px]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="useRenderIcon('ri:search-line')"
|
||||
:loading="loading"
|
||||
@click="onSearch"
|
||||
>
|
||||
{{ t("buttons:Search") }}
|
||||
</el-button>
|
||||
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
|
||||
{{ t("buttons:Reset") }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<PureTableBar title="语言类型管理" :columns="columns" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('locale:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog('新增')"
|
||||
>
|
||||
{{ t("buttons:Add") }}
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<div
|
||||
v-if="selectedNum > 0"
|
||||
v-motion-fade
|
||||
class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center"
|
||||
>
|
||||
<div class="flex-auto">
|
||||
<span
|
||||
style="font-size: var(--el-font-size-base)"
|
||||
class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]"
|
||||
>
|
||||
已选 {{ selectedNum }} 项
|
||||
</span>
|
||||
<el-button type="primary" text @click="onSelectionCancel">
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('locale:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
type="danger"
|
||||
:disabled="!selectedNum || !hasAuth('locale:btn:delete')"
|
||||
text
|
||||
class="mr-1"
|
||||
>
|
||||
{{ t("buttons:DeleteInBatches") }}</el-button
|
||||
>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
adaptive
|
||||
border
|
||||
stripe
|
||||
:adaptiveConfig="{ offsetBottom: 45 }"
|
||||
align-whole="center"
|
||||
table-layout="auto"
|
||||
:loading="loading"
|
||||
:size="size"
|
||||
:data="dataList"
|
||||
:columns="dynamicColumns"
|
||||
:pagination="pagination"
|
||||
:paginationSmall="size === 'small' ? true : false"
|
||||
:header-cell-style="{
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}"
|
||||
@selection-change="handleSelectionChange"
|
||||
@page-size-change="handleSizeChange"
|
||||
@page-current-change="handleCurrentChange"
|
||||
>
|
||||
<template #operation="{ row }">
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
:disabled="!hasAuth('locale:btn:update')"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
{{ t("buttons:Update") }}
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
:title="`是否确认导出语言名称为 ${row.name} 的这条数据为yaml文件`"
|
||||
@confirm="export_to_yaml(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('i18n:btn:infoList')"
|
||||
:icon="useRenderIcon(Download)"
|
||||
>
|
||||
{{ t("buttons:Export") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm
|
||||
:title="`是否确认删除语言名称为 ${row.name} 的这条数据`"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="danger"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('locale:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "LocaleIndex"
|
||||
});
|
||||
import { ref } from "vue";
|
||||
import { useLocale } from "./utils/hook";
|
||||
import { PureTableBar } from "@/components/RePureTableBar";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Delete from "@iconify-icons/ep/delete";
|
||||
import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
import Download from "@iconify-icons/ri/file-download-line";
|
||||
const { t } = useI18n();
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
/**
|
||||
* 表格Ref
|
||||
*/
|
||||
const tableRef = ref();
|
||||
const {
|
||||
form,
|
||||
formRef,
|
||||
dataList,
|
||||
loading,
|
||||
pagination,
|
||||
columns,
|
||||
selectedNum,
|
||||
onSearch,
|
||||
openDialog,
|
||||
resetForm,
|
||||
export_to_yaml,
|
||||
handleDelete,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
handleSelectionChange,
|
||||
onSelectionCancel,
|
||||
onbatchDel
|
||||
} = useLocale(tableRef);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-dropdown-menu__item i) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.el-button:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 24px 24px 0 !important;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
303
src/views/system/locale/utils/hook.tsx
Normal file
303
src/views/system/locale/utils/hook.tsx
Normal file
@ -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<LanguageInfo[]>([]);
|
||||
/**
|
||||
* 加载状态
|
||||
*/
|
||||
const loading = ref(true);
|
||||
/**
|
||||
* 已选数量
|
||||
*/
|
||||
const selectedNum = ref<number>(0);
|
||||
/**
|
||||
* 分页参数
|
||||
*/
|
||||
const pagination = reactive<PaginationProps>({
|
||||
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);
|
||||
|
||||
// 创建 <a> 元素并触发下载
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `${row.code}.yaml`; // 设置下载文件名
|
||||
document.body.appendChild(link); // 将 <a> 元素添加到 DOM 中
|
||||
link.click(); // 模拟点击下载
|
||||
|
||||
// 清理 URL 对象
|
||||
URL.revokeObjectURL(url);
|
||||
document.body.removeChild(link); // 移除 <a> 元素
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 页面加载执行
|
||||
*/
|
||||
onMounted(async () => {
|
||||
await onSearch();
|
||||
});
|
||||
|
||||
return {
|
||||
form,
|
||||
formRef,
|
||||
dataList,
|
||||
loading,
|
||||
pagination,
|
||||
columns,
|
||||
selectedNum,
|
||||
onSearch,
|
||||
openDialog,
|
||||
resetForm,
|
||||
export_to_yaml,
|
||||
handleDelete,
|
||||
handleSizeChange,
|
||||
handleCurrentChange,
|
||||
handleSelectionChange,
|
||||
onSelectionCancel,
|
||||
onbatchDel
|
||||
};
|
||||
};
|
@ -224,11 +224,14 @@ defineExpose({ getRef });
|
||||
</re-col>
|
||||
|
||||
<re-col :value="12" :xs="24" :sm="24">
|
||||
<el-form-item label="菜单名称" prop="title">
|
||||
<el-form-item
|
||||
:label="newFormInline.menu_type === 3 ? '权限名称' : '菜单名称'"
|
||||
prop="title"
|
||||
>
|
||||
<el-input
|
||||
v-model="newFormInline.title"
|
||||
clearable
|
||||
placeholder="请输入菜单名称"
|
||||
:placeholder="`请输入${newFormInline.menu_type === 3 ? '权限名称' : '菜单名称'}~`"
|
||||
/>
|
||||
</el-form-item>
|
||||
</re-col>
|
||||
@ -287,7 +290,9 @@ defineExpose({ getRef });
|
||||
</re-col>
|
||||
|
||||
<re-col :value="12" :xs="24" :sm="24">
|
||||
<el-form-item label="菜单排序">
|
||||
<el-form-item
|
||||
:label="newFormInline.menu_type === 3 ? '权限排序' : '菜单排序'"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="newFormInline.rank"
|
||||
class="!w-full"
|
||||
|
@ -10,6 +10,7 @@ import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
import { onBeforeRouteUpdate } from "vue-router";
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
const { t } = useI18n();
|
||||
defineOptions({
|
||||
name: "SystemPermission"
|
||||
@ -78,6 +79,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
>
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('permission:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog()"
|
||||
@ -111,6 +113,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('permission:btn:update')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
@ -122,6 +125,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('permission:btn:add')"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog('新增', { parent_id: row.id } as any)"
|
||||
>
|
||||
@ -135,7 +139,8 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
<el-button
|
||||
class="reset-margin"
|
||||
link
|
||||
type="primary"
|
||||
type="danger"
|
||||
:disabled="!hasAuth('permission:btn:delete')"
|
||||
:size="size"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
|
@ -267,7 +267,7 @@ export const usePermission = () => {
|
||||
}
|
||||
}
|
||||
const res = await postAddPermissionAPI(addForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
// 实际开发先调用新增接口,再进行下面操作
|
||||
chores();
|
||||
} else {
|
||||
@ -305,7 +305,7 @@ export const usePermission = () => {
|
||||
}
|
||||
}
|
||||
const res = await putUpdatePermissionAPI(curData.id, updateForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
chores();
|
||||
} else {
|
||||
message(`更新失败!`, { type: "error" });
|
||||
@ -318,7 +318,7 @@ export const usePermission = () => {
|
||||
};
|
||||
const handleDelete = async (row: PermissionInfo) => {
|
||||
const res = await deletePermissionAPI(row.id);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`您删除了权限名称为${transformI18n(row.title)}的这条数据`, {
|
||||
type: "success"
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import type { FormRules } from "element-plus";
|
||||
import { getDepartmentListAPI } from "@/api/system";
|
||||
import type { DepartmentInfo } from "types/system";
|
||||
import { usePublicHooks } from "../../hooks";
|
||||
import { handleTree } from "@pureadmin/utils";
|
||||
|
||||
defineOptions({
|
||||
name: "SystemRoleForm"
|
||||
@ -52,8 +53,10 @@ function getRef() {
|
||||
/**获取部门列表 */
|
||||
const getDepartments = async () => {
|
||||
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||
if (res.code === 200) {
|
||||
departments.value = formatHigherOptions(res.data.result);
|
||||
if (res.success) {
|
||||
departments.value = formatHigherOptions(
|
||||
handleTree(res.data.result, "id", "parent_id")
|
||||
);
|
||||
} else {
|
||||
departments.value = [];
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import Close from "@iconify-icons/ep/close";
|
||||
import Check from "@iconify-icons/ep/check";
|
||||
import { onBeforeRouteUpdate } from "vue-router";
|
||||
const { t } = useI18n();
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
defineOptions({
|
||||
name: "SystemRole"
|
||||
});
|
||||
@ -51,8 +52,8 @@ const {
|
||||
curRow,
|
||||
loading,
|
||||
columns,
|
||||
rowStyle,
|
||||
dataList,
|
||||
selectedNum,
|
||||
treeData,
|
||||
treeProps,
|
||||
isLinkage,
|
||||
@ -61,8 +62,11 @@ const {
|
||||
isSelectAll,
|
||||
treeSearchValue,
|
||||
departments,
|
||||
rowStyle,
|
||||
onSearch,
|
||||
resetForm,
|
||||
onSelectionCancel,
|
||||
onbatchDel,
|
||||
openDialog,
|
||||
handleMenu,
|
||||
handleSave,
|
||||
@ -71,8 +75,9 @@ const {
|
||||
transformI18n,
|
||||
onQueryChanged,
|
||||
handleSizeChange,
|
||||
handleCurrentChange
|
||||
} = useRole(treeRef);
|
||||
handleCurrentChange,
|
||||
handleSelectionChange
|
||||
} = useRole(treeRef, tableRef);
|
||||
onMounted(() => {
|
||||
useResizeObserver(contentRef, async () => {
|
||||
await nextTick();
|
||||
@ -180,6 +185,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
>
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('role:btn:add')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog()"
|
||||
@ -188,8 +194,42 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<div
|
||||
v-if="selectedNum > 0"
|
||||
v-motion-fade
|
||||
class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center"
|
||||
>
|
||||
<div class="flex-auto">
|
||||
<span
|
||||
style="font-size: var(--el-font-size-base)"
|
||||
class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]"
|
||||
>
|
||||
已选 {{ selectedNum }} 项
|
||||
</span>
|
||||
<el-button type="primary" text @click="onSelectionCancel">
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('role:btn:delete')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
type="danger"
|
||||
text
|
||||
class="mr-1"
|
||||
:disabled="selectedNum < 0 || hasAuth('role:btn:delete')"
|
||||
>
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
align-whole="center"
|
||||
showOverflowTooltip
|
||||
table-layout="auto"
|
||||
@ -208,6 +248,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
background: 'var(--el-fill-color-light)',
|
||||
color: 'var(--el-text-color-primary)'
|
||||
}"
|
||||
@selection-change="handleSelectionChange"
|
||||
@page-size-change="handleSizeChange"
|
||||
@page-current-change="handleCurrentChange"
|
||||
>
|
||||
@ -217,6 +258,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('role:btn:update')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
@ -232,6 +274,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="danger"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('role:btn:delete')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
@ -243,6 +286,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('role:btn:permissionInfo')"
|
||||
:icon="useRenderIcon(Menu)"
|
||||
@click="handleMenu(row)"
|
||||
>
|
||||
|
@ -4,6 +4,7 @@ import { message } from "@/utils/message";
|
||||
|
||||
import {
|
||||
deleteRoleAPI,
|
||||
deleteRoleListAPI,
|
||||
getPermissionListAPI,
|
||||
getRoleListAPI,
|
||||
postAddRoleAPI,
|
||||
@ -26,7 +27,7 @@ import type {
|
||||
RolePermissionInfo
|
||||
} from "types/system";
|
||||
|
||||
export const useRole = (treeRef: Ref) => {
|
||||
export const useRole = (treeRef: Ref, tableRef: Ref) => {
|
||||
/**查询表单 */
|
||||
const form = reactive({
|
||||
name: "",
|
||||
@ -47,6 +48,10 @@ export const useRole = (treeRef: Ref) => {
|
||||
* 加载状态
|
||||
*/
|
||||
const loading = ref(true);
|
||||
/**
|
||||
* 已选数量
|
||||
*/
|
||||
const selectedNum = ref<number>(0);
|
||||
/**
|
||||
* 标签样式
|
||||
*/
|
||||
@ -87,6 +92,12 @@ export const useRole = (treeRef: Ref) => {
|
||||
/**是否全选 */
|
||||
const isSelectAll = ref<boolean>(false);
|
||||
const columns: TableColumnList = [
|
||||
{
|
||||
label: "勾选列", // 如果需要表格多选,此处label必须设置
|
||||
type: "selection",
|
||||
fixed: "left",
|
||||
reserveSelection: true // 数据刷新后保留选项
|
||||
},
|
||||
{
|
||||
label: "角色名称",
|
||||
prop: "name",
|
||||
@ -150,7 +161,10 @@ export const useRole = (treeRef: Ref) => {
|
||||
dataList.value = data.data.result;
|
||||
pagination.total = data.data.total;
|
||||
pagination.currentPage = data.data.page;
|
||||
|
||||
pagination.pageSize = data.data.pageSize;
|
||||
message(data.msg, {
|
||||
type: data.success ? "success" : "error"
|
||||
});
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
@ -166,30 +180,69 @@ export const useRole = (treeRef: Ref) => {
|
||||
page: pagination.currentPage,
|
||||
pageSize: val
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
const data = res.data;
|
||||
dataList.value = data.result;
|
||||
pagination.total = data.total;
|
||||
pagination.currentPage = data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
};
|
||||
/**处理每页数量变化 */
|
||||
/**
|
||||
* 处理页码变化
|
||||
* @param val
|
||||
*/
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
loading.value = true;
|
||||
const res = await getRoleListAPI({
|
||||
page: val,
|
||||
pageSize: pagination.pageSize
|
||||
pageSize: pagination.pageSize,
|
||||
...toRaw(form)
|
||||
});
|
||||
if (res.code === 200) {
|
||||
const data = res.data;
|
||||
dataList.value = data.result;
|
||||
pagination.total = data.total;
|
||||
pagination.currentPage = data.page;
|
||||
if (res.success) {
|
||||
dataList.value = res.data.result;
|
||||
pagination.total = res.data.total;
|
||||
pagination.currentPage = res.data.page;
|
||||
pagination.pageSize = res.data.pageSize;
|
||||
}
|
||||
message(res.msg, {
|
||||
type: res.success ? "success" : "error"
|
||||
});
|
||||
loading.value = false;
|
||||
};
|
||||
/** 当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 deleteRoleListAPI(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 handleDelete = async (row: RoleInfo) => {
|
||||
const res = await deleteRoleAPI(row.id);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`您删除了角色名称为${row.name}的这条数据`, { type: "success" });
|
||||
onSearch();
|
||||
} else {
|
||||
@ -237,12 +290,11 @@ export const useRole = (treeRef: Ref) => {
|
||||
}
|
||||
FormRef.validate(async (valid: any) => {
|
||||
if (valid) {
|
||||
console.log("curData", curData);
|
||||
// 表单规则校验通过
|
||||
if (title === "新增") {
|
||||
// 实际开发先调用新增接口,再进行下面操作
|
||||
const res = await postAddRoleAPI(curData);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
chores();
|
||||
} else {
|
||||
message(`添加失败!`, {
|
||||
@ -253,7 +305,7 @@ export const useRole = (treeRef: Ref) => {
|
||||
} else {
|
||||
// 实际开发先调用修改接口,再进行下面操作
|
||||
const res = await putUpdateRoleAPI(curData, row.id);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
chores();
|
||||
} else {
|
||||
message(`修改失败!`, {
|
||||
@ -310,7 +362,7 @@ export const useRole = (treeRef: Ref) => {
|
||||
const res = await putUpdateRolePermissionsAPI(id, {
|
||||
permission_ids: permissions
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`角色名称为${name}的权限修改成功~`, {
|
||||
type: "success"
|
||||
});
|
||||
@ -334,14 +386,16 @@ export const useRole = (treeRef: Ref) => {
|
||||
/**获取部门列表 */
|
||||
const getDepartments = async () => {
|
||||
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||
if (res.code === 200) {
|
||||
departments.value = formatHigherOptions(res.data.result);
|
||||
if (res.success) {
|
||||
departments.value = formatHigherOptions(
|
||||
handleTree(res.data.result, "id", "parent_id")
|
||||
);
|
||||
} else {
|
||||
departments.value = [];
|
||||
}
|
||||
};
|
||||
const formatHigherOptions = treeList => {
|
||||
// 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示
|
||||
const formatHigherOptions = (treeList: any) => {
|
||||
// 根据返回数据的status字段值判断追加是否禁用disabled字段,返回处理后的树结构,用于上级部门级联选择器的展示(实际开发中也是如此,不可能前端需要的每个字段后端都会返回,这时需要前端自行根据后端返回的某些字段做逻辑处理)
|
||||
if (!treeList || !treeList.length) return;
|
||||
const newTreeList = [];
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
@ -379,6 +433,7 @@ export const useRole = (treeRef: Ref) => {
|
||||
loading,
|
||||
columns,
|
||||
dataList,
|
||||
selectedNum,
|
||||
treeData,
|
||||
treeProps,
|
||||
isLinkage,
|
||||
@ -390,6 +445,8 @@ export const useRole = (treeRef: Ref) => {
|
||||
rowStyle,
|
||||
onSearch,
|
||||
resetForm,
|
||||
onSelectionCancel,
|
||||
onbatchDel,
|
||||
openDialog,
|
||||
handleMenu,
|
||||
handleSave,
|
||||
@ -398,6 +455,7 @@ export const useRole = (treeRef: Ref) => {
|
||||
transformI18n,
|
||||
onQueryChanged,
|
||||
handleSizeChange,
|
||||
handleCurrentChange
|
||||
handleCurrentChange,
|
||||
handleSelectionChange
|
||||
};
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ import EditPen from "@iconify-icons/ep/edit-pen";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||
import { onBeforeRouteUpdate } from "vue-router";
|
||||
import { hasAuth } from "@/utils/auth";
|
||||
defineOptions({
|
||||
name: "SystemUser"
|
||||
});
|
||||
@ -117,6 +118,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
<PureTableBar title="用户管理" :columns="columns" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button
|
||||
v-if="hasAuth('user:btn:addUser')"
|
||||
type="primary"
|
||||
:icon="useRenderIcon(AddFill)"
|
||||
@click="openDialog()"
|
||||
@ -141,7 +143,11 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
{{ t("buttons:Deselect") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
|
||||
<el-popconfirm
|
||||
v-if="hasAuth('user:btn:deleteUser')"
|
||||
title="是否确认删除?"
|
||||
@confirm="onbatchDel"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" text class="mr-1">
|
||||
{{ t("buttons:DeleteInBatches") }}
|
||||
@ -178,13 +184,14 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:updateUser')"
|
||||
:icon="useRenderIcon(EditPen)"
|
||||
@click="openDialog('修改', row)"
|
||||
>
|
||||
{{ t("buttons:Update") }}
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
:title="`是否确认删除用户名称为${row.name}的这条数据?`"
|
||||
:title="`是否确认删除用户名称为${row.username}的这条数据?`"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<template #reference>
|
||||
@ -193,6 +200,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="danger"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:deleteUser')"
|
||||
:icon="useRenderIcon(Delete)"
|
||||
>
|
||||
{{ t("buttons:Delete") }}
|
||||
@ -216,6 +224,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:uploadAvatar')"
|
||||
:icon="useRenderIcon(Upload)"
|
||||
@click="handleUpload(row)"
|
||||
>
|
||||
@ -228,6 +237,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:reset_password')"
|
||||
:icon="useRenderIcon(Password)"
|
||||
@click="handleReset(row)"
|
||||
>
|
||||
@ -240,6 +250,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:updateRole')"
|
||||
:icon="useRenderIcon(Role)"
|
||||
@click="handleRole(row)"
|
||||
>
|
||||
@ -252,6 +263,7 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
link
|
||||
type="primary"
|
||||
:size="size"
|
||||
:disabled="!hasAuth('user:btn:permissionList')"
|
||||
:icon="useRenderIcon(Menu)"
|
||||
@click="openPerDialog(row)"
|
||||
>
|
||||
|
@ -105,8 +105,8 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
<el-image
|
||||
fit="cover"
|
||||
preview-teleported={true}
|
||||
src={row.avatar || Avatar}
|
||||
preview-src-list={Array.of(row.avatar || Avatar)}
|
||||
src={`/api/${row.avatar}` || Avatar}
|
||||
preview-src-list={Array.of(`/api/${row.avatar}` || Avatar)}
|
||||
class="w-[24px] h-[24px] rounded-full align-middle"
|
||||
/>
|
||||
)
|
||||
@ -191,7 +191,7 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
*/
|
||||
const handleDelete = async (row: UserInfo) => {
|
||||
const res = await deleteUserAPI(row.id);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`您删除了用户账号为${row.username}的这条数据`, {
|
||||
type: "success"
|
||||
});
|
||||
@ -261,10 +261,10 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
// 返回当前选中的行
|
||||
const curSelected = tableRef.value.getTableRef().getSelectionRows();
|
||||
const res = await deleteUserListAPI({
|
||||
userIds: getKeyList(curSelected, "id")
|
||||
ids: getKeyList(curSelected, "id")
|
||||
});
|
||||
if (res.code === 200) {
|
||||
message(`已删除用户编号为 ${getKeyList(curSelected, "id")} 的数据`, {
|
||||
if (res.success) {
|
||||
message(res.msg, {
|
||||
type: "success"
|
||||
});
|
||||
tableRef.value.getTableRef().clearSelection();
|
||||
@ -404,7 +404,7 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
}
|
||||
}
|
||||
const res = await postAddUserAPI(addForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
// 实际开发先调用新增接口,再进行下面操作
|
||||
chores();
|
||||
} else {
|
||||
@ -430,7 +430,7 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
}
|
||||
}
|
||||
const res = await putUpdateUserAPI(curData.id, updateForm);
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
chores();
|
||||
} else {
|
||||
message(`更新失败!`, { type: "error" });
|
||||
@ -453,14 +453,14 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
contentRenderer: () =>
|
||||
h(croppingUpload, {
|
||||
ref: cropRef,
|
||||
imgSrc: row.avatar || Avatar,
|
||||
imgSrc: `/api/${row.avatar}` || Avatar,
|
||||
onCropper: info => (avatarInfo.value = info)
|
||||
}),
|
||||
beforeSure: async done => {
|
||||
const res = await postUploadAvatarAPI(row.id, {
|
||||
file: avatarInfo.value.blob
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
// 根据实际业务使用avatarInfo.value和row里的某些字段去调用上传头像接口即可
|
||||
message(`更新成功!`, { type: "success" });
|
||||
onSearch(); // 刷新表格数据
|
||||
@ -541,7 +541,7 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
const res = await putUpdateUserPasswordAPI(row.id, {
|
||||
password: pwdForm.newPwd
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
console.log(pwdForm.newPwd);
|
||||
done();
|
||||
message(`已成功重置 ${row.username} 的密码`, {
|
||||
@ -593,7 +593,7 @@ export const useUser = (tableRef: Ref, treeRef: Ref) => {
|
||||
user_id: row.id,
|
||||
role_ids: curData.ids as string[]
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (res.success) {
|
||||
message(`${row.username}--${row.nickname}的角色信息更新成功!`, {
|
||||
type: "success",
|
||||
duration: 5000
|
||||
|
Loading…
x
Reference in New Issue
Block a user