diff --git a/backend/app/api/v1/models/system/menu_model.py b/backend/app/api/v1/models/system/menu_model.py index 6f27e396..40c50aa0 100644 --- a/backend/app/api/v1/models/system/menu_model.py +++ b/backend/app/api/v1/models/system/menu_model.py @@ -39,7 +39,7 @@ class MenuModel(ModelBase): keep_alive = Column(Boolean, default=True, nullable=False, comment="是否缓存(True:是 False:否)") always_show = Column(Boolean, default=False, nullable=False, comment="是否始终显示(True:是 False:否)") title = Column(String(50), nullable=True, comment="菜单标题") - params = Column(String(200), nullable=True, comment="路由参数") + params = Column(Text, nullable=True, comment="路由参数(JSON数组: [{\"key\": \"\", \"value\": \"\"}])") affix = Column(Boolean, default=False, nullable=False, comment="是否固定标签页(True:是 False:否)") # 层级关系 diff --git a/backend/app/api/v1/models/system/operation_log_model.py b/backend/app/api/v1/models/system/operation_log_model.py index 95589481..26b2902a 100644 --- a/backend/app/api/v1/models/system/operation_log_model.py +++ b/backend/app/api/v1/models/system/operation_log_model.py @@ -13,6 +13,7 @@ class OperationLogModel(ModelBase): __table_args__ = ({'comment': '操作日志表'}) id = Column(Integer, primary_key=True, autoincrement=True, comment='主键ID') + type = Column(Integer, nullable=True, comment="日志类型(1登录日志 2操作日志)", index=True) request_path = Column(String(255), nullable=True, comment="请求路径", index=True) request_method = Column(String(10), nullable=True, comment="请求方式", index=True) request_payload = Column(Text, nullable=True, comment="请求体") diff --git a/backend/app/api/v1/params/system/operation_log_param.py b/backend/app/api/v1/params/system/operation_log_param.py index 2d4654d9..6ac667cf 100644 --- a/backend/app/api/v1/params/system/operation_log_param.py +++ b/backend/app/api/v1/params/system/operation_log_param.py @@ -11,6 +11,7 @@ class OperationLogQueryParams: def __init__( self, + type: Optional[int] = Query(None, description="日志类型(1:登录日志, 2:操作日志)"), request_path: Optional[str] = Query(None, description="请求路径"), request_method: Optional[str] = Query(None, description="请求方法"), request_ip: Optional[str] = Query(None, description="请求IP"), @@ -29,6 +30,7 @@ class OperationLogQueryParams: self.request_method = request_method self.request_ip = request_ip self.response_code = response_code + self.type = type # 时间范围查询 if start_time and end_time: diff --git a/backend/app/api/v1/schemas/system/menu_schema.py b/backend/app/api/v1/schemas/system/menu_schema.py index 52634d4f..f237ede4 100644 --- a/backend/app/api/v1/schemas/system/menu_schema.py +++ b/backend/app/api/v1/schemas/system/menu_schema.py @@ -10,7 +10,7 @@ from app.core.base_schema import BaseSchema class MenuCreateSchema(BaseModel): """菜单创建模型""" name: str = Field(..., max_length=50, description="菜单名称") - type: int = Field(..., ge=1, le=3, description="菜单类型(1:目录 2:菜单 3:按钮)") + type: int = Field(..., ge=1, le=4, description="菜单类型(1:目录 2:菜单 3:按钮 4:外链)") icon: Optional[str] = Field(default=None, max_length=100, description="菜单图标") order: int = Field(default=1, ge=0, description="显示顺序") permission: Optional[str] = Field(default=None, max_length=100, description="权限标识") @@ -23,7 +23,7 @@ class MenuCreateSchema(BaseModel): hidden: bool = Field(default=False, description="是否隐藏(True:是 False:否)") always_show: bool = Field(default=False, description="是否始终显示(True:是 False:否)") title: Optional[str] = Field(default=None, max_length=50, description="菜单标题") - params: Optional[str] = Field(default=None, max_length=200, description="路由参数") + params: Optional[list[dict[str, str]]] = Field(default=None, description="路由参数,格式为[{key: string, value: string}]") affix: bool = Field(default=False, description="是否固定标签页(True:是 False:否)") parent_id: Optional[int] = Field(default=None, ge=0, description="父菜单ID") description: Optional[str] = Field(default=None, max_length=500, description="备注说明") diff --git a/backend/app/api/v1/schemas/system/operation_log_schema.py b/backend/app/api/v1/schemas/system/operation_log_schema.py index fd421109..1044278b 100644 --- a/backend/app/api/v1/schemas/system/operation_log_schema.py +++ b/backend/app/api/v1/schemas/system/operation_log_schema.py @@ -8,6 +8,7 @@ from app.core.base_schema import BaseSchema class OperationLogCreateSchema(BaseModel): """日志创建模型""" + type: Optional[int] = Field(default=None, description="日志类型(1登录日志 2操作日志)") request_path: Optional[str] = Field(default=None, description="请求路径") request_method: Optional[str] = Field(default=None, description="请求方法") request_payload: Optional[str] = Field(default=None, description="请求负载") diff --git a/backend/app/api/v1/services/system/operation_log_service.py b/backend/app/api/v1/services/system/operation_log_service.py index e2fc1f7e..a79678f2 100644 --- a/backend/app/api/v1/services/system/operation_log_service.py +++ b/backend/app/api/v1/services/system/operation_log_service.py @@ -65,6 +65,7 @@ class OperationLogService: # 操作日志字段映射 mapping_dict = { 'id': '编号', + 'type': '日志类型', 'request_path': '请求URL', 'request_method': '请求方式', 'request_payload': '请求参数', @@ -87,5 +88,7 @@ class OperationLogService: for item in data: # 处理状态 item['response_code'] = '成功' if item.get('response_code') == 200 else '失败' + # 处理日志类型 + item['type'] = '操作日志' if item.get('type') == 1 else '登录日志' return ExcelUtil.export_list2excel(list_data=operation_log_list, mapping_dict=mapping_dict) diff --git a/backend/app/core/router_class.py b/backend/app/core/router_class.py index 838bcab1..37159b3e 100644 --- a/backend/app/core/router_class.py +++ b/backend/app/core/router_class.py @@ -60,9 +60,11 @@ class OperationLogRoute(APIRoute): process_time = time.time() - start_time # 获取当前用户ID,如果是登录接口则为空 + log_type = 1 # 1:登录日志 2:操作日志 current_user_id = None if "user_id" in request.scope: current_user_id = request.scope.get("user_id") + log_type = 2 request_ip = None x_forwarded_for = request.headers.get('X-Forwarded-For') @@ -81,6 +83,7 @@ class OperationLogRoute(APIRoute): auth = AuthSchema(db=session) await OperationLogService.create_log_service(data=OperationLogCreateSchema( + type = log_type, request_path = request.url.path, request_method = request.method, request_payload = payload, diff --git a/backend/app/scripts/data/system_menu.json b/backend/app/scripts/data/system_menu.json index 1e8f9d7f..d430a47c 100644 --- a/backend/app/scripts/data/system_menu.json +++ b/backend/app/scripts/data/system_menu.json @@ -1500,7 +1500,7 @@ "route_name": null, "route_path": null, "component_path": null, - "parent_id": 62, + "parent_id": 71, "status": true, "keep_alive": false, "hidden": false, @@ -1535,7 +1535,7 @@ { "id": 74, "name": "接口管理", - "type": 2, + "type": 4, "icon": "api", "order": 1, "permission": "common:docs:query", @@ -1556,7 +1556,7 @@ { "id": 75, "name": "文档管理", - "type": 2, + "type": 4, "icon": "el-icon-Document", "order": 2, "permission": "common:redoc:query", diff --git a/backend/dev_sql.db b/backend/dev_sql.db index 987cdf89..d05ed072 100644 Binary files a/backend/dev_sql.db and b/backend/dev_sql.db differ diff --git a/frontend/package.json b/frontend/package.json index 39f2e9a5..98eaf833 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -45,7 +45,6 @@ "@types/node": "^22.16.5", "@types/nprogress": "^0.2.3", "@types/qs": "^6.14.0", - "@vitejs/plugin-vue": "^6.0.0", "eslint": "^9.31.0", "sass": "^1.89.2", "terser": "^5.43.1", @@ -53,6 +52,7 @@ "unocss": "66.2.3", "unplugin-auto-import": "^19.3.0", "unplugin-vue-components": "^28.8.0", + "@vitejs/plugin-vue": "^6.0.0", "vite": "^6.3.5" }, "engines": { diff --git a/frontend/src/api/system/dept.ts b/frontend/src/api/system/dept.ts index 23f07358..98b1285c 100644 --- a/frontend/src/api/system/dept.ts +++ b/frontend/src/api/system/dept.ts @@ -1,7 +1,7 @@ import request from "@/utils/request"; const DeptAPI = { - getDeptList(query: DeptPageQuery) { + getDeptList(query?: DeptPageQuery) { return request>>({ url: `/system/dept/list`, method: "get", diff --git a/frontend/src/api/system/log.ts b/frontend/src/api/system/log.ts index 178f3de1..5da00e5a 100644 --- a/frontend/src/api/system/log.ts +++ b/frontend/src/api/system/log.ts @@ -37,6 +37,7 @@ const LogAPI = { export default LogAPI; export interface LogPageQuery extends PageQuery { + type?: number; request_path?: string; creator_name?: string; /** 开始时间 */ @@ -47,6 +48,7 @@ export interface LogPageQuery extends PageQuery { export interface LogTable { id?: number; + type?: number; // 1 登录日志 2 操作日志 request_path?: string; request_method?: string; request_ip?: string; diff --git a/frontend/src/api/system/menu.ts b/frontend/src/api/system/menu.ts index 2e579865..138546df 100644 --- a/frontend/src/api/system/menu.ts +++ b/frontend/src/api/system/menu.ts @@ -1,7 +1,7 @@ import request from "@/utils/request"; const MenuAPI = { - getMenuList(query: MenuPageQuery) { + getMenuList(query?: MenuPageQuery) { return request>>({ url: `/system/menu/list`, method: "get", @@ -78,7 +78,7 @@ export interface MenuTable { hidden?: boolean; always_show?: boolean; title?: string; - params?: string; + params?: { key: string; value: string; }[]; affix?: boolean; status?: boolean; description?: string; @@ -103,7 +103,7 @@ export interface MenuForm { hidden?: boolean; always_show?: boolean; title?: string; - params?: string; + params?: { key: string; value: string; }[]; affix?: boolean; status?: boolean; description?: string; diff --git a/frontend/src/api/system/role.ts b/frontend/src/api/system/role.ts index 2be6dc6c..4efca3f9 100644 --- a/frontend/src/api/system/role.ts +++ b/frontend/src/api/system/role.ts @@ -106,26 +106,26 @@ export interface RoleForm { } export interface permissionDataType { - role_ids?: RoleTable["id"][]; - menu_ids?: permissionMenuType["id"][]; - data_scope?: number; - dept_ids?: number[]; + role_ids: RoleTable["id"][]; + menu_ids: permissionMenuType["id"][]; + data_scope: number; + dept_ids: permissionDeptType["id"][]; } export interface permissionDeptType { - id?: number; - name?: string; - parent_id?: number; - children?: permissionDeptType[]; + id: number; + name: string; + parent_id: number; + children: permissionDeptType[]; } export interface permissionMenuType { - id?: number; - name?: string; - type?: number; - permission?: string; + id: number; + name: string; + type: number; + permission: string; parent_id?: number; - status?: boolean; + status: boolean; description?: string; children?: permissionMenuType[]; } diff --git a/frontend/src/enums/system/menu.enum.ts b/frontend/src/enums/system/menu.enum.ts index cf246c3e..f561d8fc 100644 --- a/frontend/src/enums/system/menu.enum.ts +++ b/frontend/src/enums/system/menu.enum.ts @@ -1,7 +1,7 @@ // 核心枚举定义 export enum MenuTypeEnum { - CATALOG = 2, // 目录 - MENU = 1, // 菜单 + CATALOG = 1, // 目录 + MENU = 2, // 菜单 BUTTON = 3, // 按钮 EXTLINK = 4, // 外链 } diff --git a/frontend/src/store/modules/notice.store.ts b/frontend/src/store/modules/notice.store.ts index 6f9baf1e..f493d86e 100644 --- a/frontend/src/store/modules/notice.store.ts +++ b/frontend/src/store/modules/notice.store.ts @@ -11,7 +11,6 @@ export const useNoticeStore = defineStore("notice", { actions: { async getNotice() { const response = await NoticeAPI.getNoticeListAvailable(); - console.log('获取我的通知公告', response); this.noticeList = response.data.data.items; this.total = response.data.data.total; this.isNoticeLoaded = true; diff --git a/frontend/src/store/modules/permission.store.ts b/frontend/src/store/modules/permission.store.ts index 5da4561b..dd8967bb 100644 --- a/frontend/src/store/modules/permission.store.ts +++ b/frontend/src/store/modules/permission.store.ts @@ -22,7 +22,7 @@ export interface Meta { /** 排序 */ order?: number; /** 参数 */ - params?: string; + params?: { key: string; value: string; }[]; /** 是否固定路由 */ affix?: boolean; } diff --git a/frontend/src/utils/common.ts b/frontend/src/utils/common.ts index f27ee2a5..ccdd5d73 100644 --- a/frontend/src/utils/common.ts +++ b/frontend/src/utils/common.ts @@ -1,5 +1,3 @@ - - // 问候语:根据当前小时返回不同问候语 export function greetings () { // 当前时间(用于计算问候语) @@ -145,7 +143,7 @@ export function listToTree(list: any[]) { } // 加载部门选项 -export function formatDeptTree(nodes: any[]): any[] { +export function formatTree(nodes: any[]): any[] { return nodes.map(node => { const formattedNode = { value: node.id, @@ -153,7 +151,7 @@ export function formatDeptTree(nodes: any[]): any[] { }; if (node.children && node.children.length > 0) { - Object.assign(formattedNode, { children: formatDeptTree(node.children) }); + Object.assign(formattedNode, { children: formatTree(node.children) }); } return formattedNode; diff --git a/frontend/src/views/monitor/job/index.vue b/frontend/src/views/monitor/job/index.vue index 3b190f6d..e24354aa 100644 --- a/frontend/src/views/monitor/job/index.vue +++ b/frontend/src/views/monitor/job/index.vue @@ -1,280 +1,506 @@ - + + + diff --git a/frontend/src/views/system/dept/index.vue b/frontend/src/views/system/dept/index.vue index 7772b2ed..0a6eb2c1 100644 --- a/frontend/src/views/system/dept/index.vue +++ b/frontend/src/views/system/dept/index.vue @@ -181,7 +181,7 @@ defineOptions({ import DeptAPI, { DeptTable, DeptForm, DeptPageQuery } from "@/api/system/dept"; import { ElMessage, ElMessageBox } from "element-plus"; -import { listToTree, formatDeptTree } from "@/utils/common"; +import { listToTree, formatTree } from "@/utils/common"; const queryFormRef = ref(); const dataFormRef = ref(); @@ -246,13 +246,8 @@ const rules = reactive({ status: [{ required: true, message: "请选择状态", trigger: "blur" }], }); -// 刷新数据(防抖) -const handleRefresh = () => { - refreshTable(); -}; - -// 刷新列表数据 -async function refreshTable() { +// 列表刷新 +async function handleRefresh () { loading.value = true; try { const response = await DeptAPI.getDeptList(queryFormData); @@ -264,7 +259,7 @@ async function refreshTable() { } finally { loading.value = false; } -} +}; // 加载表格数据 async function loadingData() { @@ -275,7 +270,7 @@ async function loadingData() { pageTableData.value = treeData; total.value = response.data.data.total; // 加载部门选项 - deptOptions.value = formatDeptTree(treeData); + deptOptions.value = formatTree(treeData); } catch (error: any) { ElMessage.error(error.message); diff --git a/frontend/src/views/system/dict/components/DataDrawer.vue b/frontend/src/views/system/dict/components/DataDrawer.vue index 14fca18d..ffdf6dc3 100644 --- a/frontend/src/views/system/dict/components/DataDrawer.vue +++ b/frontend/src/views/system/dict/components/DataDrawer.vue @@ -1,6 +1,6 @@ - + + + - + + + diff --git a/frontend/src/views/system/log/index.vue b/frontend/src/views/system/log/index.vue index e48e8a12..c38c1850 100644 --- a/frontend/src/views/system/log/index.vue +++ b/frontend/src/views/system/log/index.vue @@ -10,6 +10,12 @@ + + + + + + @@ -82,7 +88,18 @@ - + + + + + + - + @@ -279,7 +285,7 @@ - + @@ -297,7 +303,7 @@ - + @@ -318,7 +324,7 @@ -
+
添加路由参数 @@ -342,10 +348,27 @@
- + + + - 显示 - 隐藏 + + @@ -382,12 +405,12 @@ - + - - + + @@ -395,8 +418,26 @@ - - + + + + + + + + + + + + + + 启用 + 禁用 + + + + + @@ -424,7 +465,7 @@ import { DeviceEnum } from "@/enums/settings/device.enum"; import MenuAPI, { MenuPageQuery, MenuForm, MenuTable } from "@/api/system/menu"; import { MenuTypeEnum } from "@/enums/system/menu.enum"; -import { listToTree } from "@/utils/common"; +import { formatTree, listToTree } from "@/utils/common"; const appStore = useAppStore(); @@ -459,18 +500,18 @@ const formData = reactive({ name: undefined, type: MenuTypeEnum.MENU, icon: undefined, - order: undefined, + order: 1, permission: '', route_name: '', route_path: '', component_path: '', redirect: '', parent_id: undefined, - keep_alive: undefined, - hidden: undefined, - always_show: undefined, + keep_alive: false, + hidden: false, + always_show: false, title: '', - params: '', + params: [] as { key: string; value: string }[], affix: false, status: true, description: undefined, @@ -508,19 +549,41 @@ const rules = reactive({ // 选择表格的行菜单ID const selectedMenuId = ref(); -// 刷新数据(防抖) -const handleRefresh = useDebounceFn(() => { - loadingData(); - ElMessage.success("刷新成功"); -}, 1000); +// 列表刷新 +async function handleRefresh () { + loading.value = true; + try { + const response = await MenuAPI.getMenuList(queryFormData); + const treeData = listToTree(response.data.data.items); + pageTableData.value = treeData; + total.value = response.data.data.total; + } catch (error: any) { + ElMessage.error(error.message); + } finally { + loading.value = false; + } +}; + +// 修改菜单选项过滤逻辑,添加递归过滤函数 +const filterMenuTypes = (nodes: MenuTable[]) => { + return nodes + .filter(node => node.type === MenuTypeEnum.CATALOG || node.type === MenuTypeEnum.MENU) + .map((node: any): any => ({ + ...node, + children: node.children ? filterMenuTypes(node.children) : [] + })); +}; // 加载表格数据 async function loadingData() { loading.value = true; try { const response = await MenuAPI.getMenuList(queryFormData); - pageTableData.value = listToTree(response.data.data.items); + const treeData = listToTree(response.data.data.items); + pageTableData.value = treeData; total.value = response.data.data.total; + // 加载部门选项,只显示目录、菜单 + menuOptions.value = formatTree(filterMenuTypes(treeData)); } catch (error: any) { ElMessage.error(error.message); @@ -566,10 +629,10 @@ async function handleCloseDialog() { } //打开弹窗 -async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: number) { +async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: number, parentId?: number) { dialogVisible.type = type; if (id) { - const response = await MenuAPI.getMenuDetail({ id }); + const response = await MenuAPI.getMenuDetail(id); if (type === 'detail') { dialogVisible.title = "菜单详情"; Object.assign(detailFormData.value, response.data.data); @@ -580,6 +643,10 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: numbe } else { dialogVisible.title = "新增菜单"; formData.id = undefined; + // 设置父级部门 + if (parentId) { + formData.parent_id = parentId; + } } dialogVisible.visible = true; } @@ -632,48 +699,44 @@ async function handleSubmit() { // 删除、批量删除 async function handleDelete(ids: number[]) { - if (!ids && !selectIds.value.length) { - ElMessageBox.confirm("确认删除该项数据?", "警告", { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - }).then(async () => { - try { - loading.value = true; - await DictAPI.deleteDictType({ ids }); - handleResetQuery(); - } catch (error: any) { - ElMessage.error(error.message); - } finally { - loading.value = false; - } - }).catch(() => { - ElMessage.info('已取消删除'); - }); - } + ElMessageBox.confirm("确认删除该项数据?", "警告", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + }).then(async () => { + try { + loading.value = true; + await MenuAPI.deleteMenu(ids); + handleResetQuery(); + } catch (error: any) { + ElMessage.error(error.message); + } finally { + loading.value = false; + } + }).catch(() => { + ElMessage.info('已取消删除'); + }); } // 批量启用/停用 async function handleMoreClick(status: boolean) { - if (selectIds.value.length) { - ElMessageBox.confirm(`确认${status ? '启用' : '停用'}该项数据?`, "警告", { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - }).then(async () => { - try { - loading.value = true; - await MenuAPI.batchAvailableMenu({ ids: selectIds.value, status }); - handleResetQuery(); - } catch (error: any) { - ElMessage.error(error.message); - } finally { - loading.value = false; - } - }).catch(() => { - ElMessage.info('已取消批量操作'); - }); - } + ElMessageBox.confirm(`确认${status ? '启用' : '停用'}该项数据?`, "警告", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + }).then(async () => { + try { + loading.value = true; + await MenuAPI.batchAvailableMenu({ ids: selectIds.value, status }); + handleResetQuery(); + } catch (error: any) { + ElMessage.error(error.message); + } finally { + loading.value = false; + } + }).catch(() => { + ElMessage.info('已取消批量操作'); + }); } onMounted(() => { diff --git a/frontend/src/views/system/notice/index.vue b/frontend/src/views/system/notice/index.vue index e7a4ba88..ae3b49af 100644 --- a/frontend/src/views/system/notice/index.vue +++ b/frontend/src/views/system/notice/index.vue @@ -107,7 +107,11 @@ - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 将文件拖到此处,或 - 点击上传 -
- -
-
-
-
- - -
@@ -580,129 +509,6 @@ async function handleMoreClick(status: boolean) { } } - -// // 导出 -// function handleExport() { -// const filename = exportsFormData.filename -// ? exportsFormData.filename -// : props.contentConfig.permPrefix || "export"; -// const sheetname = exportsFormData.sheetname ? exportsFormData.sheetname : "sheet"; -// const workbook = new ExcelJS.Workbook(); -// const worksheet = workbook.addWorksheet(sheetname); -// const columns: Partial[] = []; -// cols.value.forEach((col) => { -// if (col.label && col.prop && exportsFormData.fields.includes(col.prop)) { -// columns.push({ header: col.label, key: col.prop }); -// } -// }); -// worksheet.columns = columns; -// if (exportsFormData.origin === ExportsOriginEnum.REMOTE) { -// if (props.contentConfig.exportsAction) { -// props.contentConfig.exportsAction(lastFormData).then((res) => { -// worksheet.addRows(res); -// workbook.xlsx -// .writeBuffer() -// .then((buffer) => { -// saveXlsx(buffer, filename as string); -// }) -// .catch((error) => console.log(error)); -// }); -// } else { -// ElMessage.error("未配置exportsAction"); -// } -// } else { -// worksheet.addRows( -// exportsFormData.origin === ExportsOriginEnum.SELECTED ? selectionData.value : pageData.value -// ); -// workbook.xlsx -// .writeBuffer() -// .then((buffer) => { -// saveXlsx(buffer, filename as string); -// }) -// .catch((error) => console.log(error)); -// } -// } - -// // 下载导入模板 -// function handleDownloadTemplate() { -// const importTemplate = props.contentConfig.importTemplate; -// if (typeof importTemplate === "string") { -// window.open(importTemplate); -// } else if (typeof importTemplate === "function") { -// importTemplate().then((response) => { -// const fileData = response.data; -// const fileName = decodeURI( -// response.headers["content-disposition"].split(";")[1].split("=")[1] -// ); -// saveXlsx(fileData, fileName); -// }); -// } else { -// ElMessage.error("未配置importTemplate"); -// } -// } - -// // 导入 -// function handleImport() { -// const importsAction = props.contentConfig.importsAction; -// if (importsAction === undefined) { -// ElMessage.error("未配置importsAction"); -// return; -// } -// // 获取选择的文件 -// const file = importFormData.files[0].raw as File; -// // 创建Workbook实例 -// const workbook = new ExcelJS.Workbook(); -// // 使用FileReader对象来读取文件内容 -// const fileReader = new FileReader(); -// // 二进制字符串的形式加载文件 -// fileReader.readAsArrayBuffer(file); -// fileReader.onload = (ev) => { -// if (ev.target !== null && ev.target.result !== null) { -// const result = ev.target.result as ArrayBuffer; -// // 从 buffer中加载数据解析 -// workbook.xlsx -// .load(result) -// .then((workbook) => { -// // 解析后的数据 -// const data = []; -// // 获取第一个worksheet内容 -// const worksheet = workbook.getWorksheet(1); -// if (worksheet) { -// // 获取第一行的标题 -// const fields: any[] = []; -// worksheet.getRow(1).eachCell((cell) => { -// fields.push(cell.value); -// }); -// // 遍历工作表的每一行(从第二行开始,因为第一行通常是标题行) -// for (let rowNumber = 2; rowNumber <= worksheet.rowCount; rowNumber++) { -// const rowData: IObject = {}; -// const row = worksheet.getRow(rowNumber); -// // 遍历当前行的每个单元格 -// row.eachCell((cell, colNumber) => { -// // 获取标题对应的键,并将当前单元格的值存储到相应的属性名中 -// rowData[fields[colNumber - 1]] = cell.value; -// }); -// // 将当前行的数据对象添加到数组中 -// data.push(rowData); -// } -// } -// if (data.length === 0) { -// ElMessage.error("未解析到数据"); -// return; -// } -// importsAction(data).then(() => { -// ElMessage.success("导入数据成功"); -// handleCloseImportModal(); -// handleRefresh(true); -// }); -// }) -// .catch((error) => console.log(error)); -// } else { -// ElMessage.error("读取文件失败"); -// } -// }; -// } - onMounted(() => { loadingData(); }); diff --git a/frontend/src/views/system/position/index.vue b/frontend/src/views/system/position/index.vue index a3361e07..de84dff6 100644 --- a/frontend/src/views/system/position/index.vue +++ b/frontend/src/views/system/position/index.vue @@ -95,7 +95,11 @@ - + + + - + + +