lxr 2 місяців тому
батько
коміт
97531a8c6f

+ 57 - 7
src/api/modules/accountRoleManagement.ts

@@ -51,6 +51,16 @@ export interface CreateRoleDto {
   status?: string;
   status?: string;
 }
 }
 
 
+// 更新角色请求参数
+export interface UpdateRoleDto {
+  roleId: number;
+  roleName: string;
+  menuIds?: number[];
+  storeId?: number;
+  description?: string;
+  remark?: string;
+}
+
 // 通用响应接口
 // 通用响应接口
 export interface ApiResponse {
 export interface ApiResponse {
   code: number;
   code: number;
@@ -91,7 +101,7 @@ export const createRole = (createRoleDto: CreateRoleDto): Promise<ResultData<Api
   return http.post<ApiResponse>(PORT_NONE + `/platform/role/createRole`, createRoleDto, { loading: false });
   return http.post<ApiResponse>(PORT_NONE + `/platform/role/createRole`, createRoleDto, { loading: false });
 };
 };
 // 编辑角色
 // 编辑角色
-export const updateRole = (updateRoleDto: updateRoleDto): Promise<ResultData<ApiResponse>> => {
+export const updateRole = (updateRoleDto: UpdateRoleDto): Promise<ResultData<ApiResponse>> => {
   return http.post<ApiResponse>(PORT_NONE + `/platform/role/updateRole`, updateRoleDto, { loading: false });
   return http.post<ApiResponse>(PORT_NONE + `/platform/role/updateRole`, updateRoleDto, { loading: false });
 };
 };
 
 
@@ -134,7 +144,7 @@ export const querySubAccounts = (
 export const deleteRoleWithCheck = (roleId: number): Promise<ResultData<ApiResponse>> => {
 export const deleteRoleWithCheck = (roleId: number): Promise<ResultData<ApiResponse>> => {
   return http.delete<ApiResponse>(PORT_NONE + `/platform/role/deleteRoleWithCheck`, { roleId }, { loading: false });
   return http.delete<ApiResponse>(PORT_NONE + `/platform/role/deleteRoleWithCheck`, { roleId }, { loading: false });
 };
 };
-// 分页查询操作记录
+// 分页查询操作记录(已废弃,请使用 operationLog)
 export const uoperationLogPage = ({
 export const uoperationLogPage = ({
   page,
   page,
   size,
   size,
@@ -145,10 +155,10 @@ export const uoperationLogPage = ({
 }: {
 }: {
   page: number;
   page: number;
   size: number;
   size: number;
-  operationType: string;
-  operationName: string;
-  operationTime: string;
-  operationContent: string;
+  account?: string;
+  endTime?: string;
+  module?: string;
+  startTime?: string;
 }): Promise<ResultData<ApiResponse>> => {
 }): Promise<ResultData<ApiResponse>> => {
   return http.post<ApiResponse>(
   return http.post<ApiResponse>(
     PORT_NONE + `/platform/operationLog/page`,
     PORT_NONE + `/platform/operationLog/page`,
@@ -170,10 +180,50 @@ export const removeRole = (roleId: number, storeId: number, userId: number): Pro
   return http.get<ApiResponse>(PORT_NONE + `/platform/user-role/removeRole`, { roleId, storeId, userId }, { loading: false });
   return http.get<ApiResponse>(PORT_NONE + `/platform/user-role/removeRole`, { roleId, storeId, userId }, { loading: false });
 };
 };
 // 批量删除子账号 userIds数组 storeId商家id
 // 批量删除子账号 userIds数组 storeId商家id
-export const batchDeleteSubAccounts = ({ storeId, userIds }): Promise<ResultData<ApiResponse>> => {
+export const batchDeleteSubAccounts = (storeId: number, userIds: number[]): Promise<ResultData<ApiResponse>> => {
   return http.post<ApiResponse>(
   return http.post<ApiResponse>(
     PORT_NONE + `/platform/user-role/batchDeleteSubAccounts`,
     PORT_NONE + `/platform/user-role/batchDeleteSubAccounts`,
     { storeId, userIds },
     { storeId, userIds },
     { loading: false }
     { loading: false }
   );
   );
 };
 };
+
+// 操作记录项接口
+export interface OperationLogItem {
+  id: number;
+  operationModule: string;
+  operationType: string;
+  operationContent: string;
+  operationParams?: string;
+  operatorId?: string;
+  operatorAccount?: string;
+  operatorName?: string;
+  userType?: string;
+  requestMethod?: string;
+  requestPath?: string;
+  ipAddress?: string;
+  operationTime: string;
+}
+
+// 操作记录分页响应
+export interface OperationLogPageResponse {
+  records: OperationLogItem[];
+  total: number;
+  size: number;
+  current: number;
+  orders: any[];
+  searchCount: boolean;
+  pages: number;
+}
+
+// 历史记录列表
+export const operationLog = (params: {
+  page: number;
+  size: number;
+  account?: string;
+  endTime?: string;
+  module?: string;
+  startTime?: string;
+}): Promise<ResultData<OperationLogPageResponse>> => {
+  return http.get<OperationLogPageResponse>(PORT_NONE + `/platform/operationLog/page`, params, { loading: false });
+};

+ 14 - 0
src/assets/json/authMenuList.json

@@ -935,6 +935,20 @@
             "isAffix": false,
             "isAffix": false,
             "isKeepAlive": false
             "isKeepAlive": false
           }
           }
+        },
+        {
+          "path": "/accountRoleManagement/subAccountManagement/operationLog",
+          "name": "subAccountManagementOperationLog",
+          "component": "/accountRoleManagement/subAccountManagement/operationLog",
+          "meta": {
+            "icon": "Menu",
+            "title": "历史操作记录",
+            "isLink": "",
+            "isHide": true,
+            "isFull": false,
+            "isAffix": false,
+            "isKeepAlive": false
+          }
         }
         }
       ]
       ]
     }
     }

+ 0 - 1
src/views/accountRoleManagement/subAccountManagement/create.vue

@@ -398,7 +398,6 @@ const handleSave = async () => {
         ElMessage.error(res.msg || "创建失败");
         ElMessage.error(res.msg || "创建失败");
       }
       }
     } catch (error) {
     } catch (error) {
-      ElMessage.error(isEdit.value ? "编辑失败,请重试" : "创建失败,请重试");
     } finally {
     } finally {
       saveLoading.value = false;
       saveLoading.value = false;
     }
     }

+ 43 - 9
src/views/accountRoleManagement/subAccountManagement/index.vue

@@ -16,7 +16,7 @@
         </div>
         </div>
       </template>
       </template>
       <template #tableHeaderRight>
       <template #tableHeaderRight>
-        <el-link type="primary" :underline="false"> 历史操作记录 </el-link>
+        <el-link type="primary" :underline="false" @click="handleOperationLog"> 历史操作记录 </el-link>
       </template>
       </template>
       <!-- 可操作权限列 -->
       <!-- 可操作权限列 -->
       <template #permissionCount="scope">
       <template #permissionCount="scope">
@@ -54,7 +54,13 @@ import { ElMessage } from "element-plus";
 import { Plus, Delete } from "@element-plus/icons-vue";
 import { Plus, Delete } from "@element-plus/icons-vue";
 import ProTable from "@/components/ProTable/index.vue";
 import ProTable from "@/components/ProTable/index.vue";
 import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
 import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
-import { querySubAccounts, getAllNormalRoles, type RoleItem } from "@/api/modules/accountRoleManagement";
+import {
+  querySubAccounts,
+  getAllNormalRoles,
+  type RoleItem,
+  removeRole,
+  batchDeleteSubAccounts
+} from "@/api/modules/accountRoleManagement";
 import { localGet } from "@/utils";
 import { localGet } from "@/utils";
 
 
 // 子账号数据类型
 // 子账号数据类型
@@ -254,16 +260,26 @@ const handleBatchDelete = () => {
 const handleConfirmDelete = async () => {
 const handleConfirmDelete = async () => {
   deleteLoading.value = true;
   deleteLoading.value = true;
   try {
   try {
-    // TODO: 调用删除接口
-    // 模拟接口调用
-    await new Promise(resolve => setTimeout(resolve, 500));
-
     if (deleteType.value === "single" && currentAccount.value) {
     if (deleteType.value === "single" && currentAccount.value) {
-      // 单个删除
-      ElMessage.success("删除成功");
+      const res = await removeRole(currentAccount.value.roleId, getStoreId(), currentAccount.value.userId);
+      const code = typeof res.code === "string" ? parseInt(res.code) : res.code;
+      if (code === 200) {
+        ElMessage.success("删除成功");
+      } else {
+        ElMessage.error("删除失败,请重试");
+      }
     } else {
     } else {
       // 批量删除
       // 批量删除
-      ElMessage.success(`成功删除 ${selectedAccounts.value.length} 个子账号`);
+      const res = await batchDeleteSubAccounts(
+        getStoreId(),
+        selectedAccounts.value.map(item => item.userId)
+      );
+      const code = typeof res.code === "string" ? parseInt(res.code) : res.code;
+      if (code === 200) {
+        ElMessage.success("删除成功");
+      } else {
+        ElMessage.error("删除失败,请重试");
+      }
     }
     }
 
 
     // 刷新表格
     // 刷新表格
@@ -278,6 +294,11 @@ const handleConfirmDelete = async () => {
   }
   }
 };
 };
 
 
+// 跳转到历史操作记录
+const handleOperationLog = () => {
+  router.push("/accountRoleManagement/subAccountManagement/operationLog");
+};
+
 // 初始化
 // 初始化
 onMounted(() => {
 onMounted(() => {
   loadRoleList();
   loadRoleList();
@@ -318,4 +339,17 @@ onMounted(() => {
   gap: 12px;
   gap: 12px;
   justify-content: flex-end;
   justify-content: flex-end;
 }
 }
+
+// 修复表格为空时没有高度的问题
+:deep(.el-table) {
+  min-height: 400px;
+  .el-table__empty-block {
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    min-height: 400px;
+  }
+}
 </style>
 </style>

+ 161 - 0
src/views/accountRoleManagement/subAccountManagement/operationLog.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="operation-log-container">
+    <!-- 返回按钮和标题 -->
+    <div class="header-section">
+      <el-button :icon="ArrowLeft" @click="handleBack"> 返回 </el-button>
+    </div>
+
+    <!-- 标签页 -->
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="operation-tabs">
+      <el-tab-pane label="账号操作记录" name="ACCOUNT" />
+      <el-tab-pane label="角色操作记录" name="ROLE" />
+    </el-tabs>
+
+    <!-- 表格 -->
+    <ProTable
+      ref="proTable"
+      :columns="columns"
+      :request-api="getTableList"
+      :init-param="initParam"
+      :data-callback="dataCallback"
+      row-key="id"
+      :pagination="true"
+    />
+  </div>
+</template>
+
+<script setup lang="tsx" name="operationLog">
+import { ref, reactive, computed, watch } from "vue";
+import { useRouter } from "vue-router";
+import { ArrowLeft } from "@element-plus/icons-vue";
+import ProTable from "@/components/ProTable/index.vue";
+import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
+import { operationLog, type OperationLogItem } from "@/api/modules/accountRoleManagement";
+
+// 路由
+const router = useRouter();
+
+// ProTable 实例
+const proTable = ref<ProTableInstance>();
+
+// 当前激活的标签页
+const activeTab = ref<"ACCOUNT" | "ROLE">("ACCOUNT");
+
+// 初始化参数
+const initParam = reactive({
+  page: 1,
+  size: 10,
+  module: activeTab.value
+});
+
+// 数据回调处理
+const dataCallback = (data: any) => {
+  // 如果返回的是分页对象
+  if (data.records) {
+    return {
+      list: data.records || [],
+      total: data.total || 0
+    };
+  }
+  // 默认返回
+  return {
+    list: [],
+    total: 0
+  };
+};
+
+// 请求接口
+const getTableList = (params: any) => {
+  return operationLog({
+    page: params.pageNum || params.page || 1,
+    size: params.pageSize || params.size || 10,
+    account: params.account || "",
+    endTime: params.endTime || "",
+    module: activeTab.value,
+    startTime: params.startTime || ""
+  });
+};
+
+// 表格列配置
+const columns = reactive<ColumnProps<OperationLogItem>[]>([
+  {
+    prop: "operationType",
+    label: "操作记录",
+    minWidth: 150
+  },
+  {
+    prop: "operationTime",
+    label: "操作时间",
+    minWidth: 180
+  },
+  {
+    prop: "operatorAccount",
+    label: "操作账号",
+    minWidth: 150,
+    render: (scope: { row: OperationLogItem }) => {
+      return scope.row.operatorAccount || "--";
+    }
+  },
+  {
+    prop: "operationContent",
+    label: "操作记录详情",
+    minWidth: 300
+  }
+]);
+
+// 标签页切换
+const handleTabChange = (tabName: string) => {
+  activeTab.value = tabName as "ACCOUNT" | "ROLE";
+  // 更新初始化参数
+  initParam.module = activeTab.value;
+  // 刷新表格
+  proTable.value?.reset();
+  proTable.value?.getTableList();
+};
+
+// 返回
+const handleBack = () => {
+  router.back();
+};
+
+// 监听标签页变化,更新初始化参数
+watch(
+  () => activeTab.value,
+  newTab => {
+    initParam.module = newTab;
+  }
+);
+</script>
+
+<style lang="scss" scoped>
+.operation-log-container {
+  min-height: calc(100vh - 84px);
+  padding: 20px;
+  background: #ffffff;
+}
+.header-section {
+  display: flex;
+  gap: 16px;
+  align-items: center;
+  margin-bottom: 20px;
+  .page-title {
+    margin: 0;
+    font-size: 20px;
+    font-weight: 500;
+    color: var(--el-text-color-primary);
+  }
+}
+.operation-tabs {
+  margin-bottom: 20px;
+  :deep(.el-tabs__header) {
+    margin-bottom: 0;
+  }
+  :deep(.el-tabs__item.is-active) {
+    font-weight: 500;
+    color: var(--el-color-primary);
+  }
+  :deep(.el-tabs__active-bar) {
+    background-color: var(--el-color-primary);
+  }
+}
+</style>