From 212b79be567363e2e5441bb1d0f4008e67e3bcba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Wed, 8 Jul 2026 16:49:22 +0800 Subject: [PATCH 1/8] =?UTF-8?q?feat(qc):=20=E6=96=B0=E5=A2=9E=E6=A3=80?= =?UTF-8?q?=E5=8C=96=E9=AA=8C=E7=94=B3=E8=AF=B7=E5=8D=95=E7=9B=B8=E5=85=B3?= =?UTF-8?q?API=EF=BC=8C=E4=BC=98=E5=8C=96=E6=A3=80=E9=AA=8C=E9=A1=B9?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=8E=A5=E5=8F=A3=E5=B9=B6=E6=B8=85=E7=90=86?= =?UTF-8?q?=E5=86=97=E4=BD=99=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 将检验项模板查询接口从POST改为GET请求 2. 新增检化验申请单的增删改查、批量保存检验数据API 3. 删除多个冗余的质检历史、检验项、检验任务页面 --- .../WmsInspectionItemTemplateController.java | 2 +- klp-ui/src/api/mes/qc/approval.js | 64 + .../src/api/mes/qc/inspectionItemTemplate.js | 2 +- klp-ui/src/views/mes/qc/approval/index.vue | 1573 +++++++++++++++++ klp-ui/src/views/mes/qc/history/index.vue | 229 --- klp-ui/src/views/mes/qc/inspection/item.vue | 402 ----- klp-ui/src/views/mes/qc/inspection/task.vue | 1010 ----------- .../views/mes/qc/inspectionSample/index.vue | 123 +- klp-ui/src/views/mes/qc/item/index.vue | 299 ---- klp-ui/src/views/mes/qc/task/index.vue | 405 ----- .../src/views/mes/qc/task/pages/auxiliary.vue | 467 ----- klp-ui/src/views/mes/qc/task/pages/lab.vue | 443 ----- klp-ui/src/views/mes/qc/task/pages/raw.vue | 493 ------ .../src/views/mes/qc/task/pages/section.vue | 451 ----- 14 files changed, 1685 insertions(+), 4278 deletions(-) create mode 100644 klp-ui/src/api/mes/qc/approval.js create mode 100644 klp-ui/src/views/mes/qc/approval/index.vue delete mode 100644 klp-ui/src/views/mes/qc/history/index.vue delete mode 100644 klp-ui/src/views/mes/qc/inspection/item.vue delete mode 100644 klp-ui/src/views/mes/qc/inspection/task.vue delete mode 100644 klp-ui/src/views/mes/qc/item/index.vue delete mode 100644 klp-ui/src/views/mes/qc/task/index.vue delete mode 100644 klp-ui/src/views/mes/qc/task/pages/auxiliary.vue delete mode 100644 klp-ui/src/views/mes/qc/task/pages/lab.vue delete mode 100644 klp-ui/src/views/mes/qc/task/pages/raw.vue delete mode 100644 klp-ui/src/views/mes/qc/task/pages/section.vue diff --git a/klp-mes/src/main/java/com/klp/mes/qc/controller/WmsInspectionItemTemplateController.java b/klp-mes/src/main/java/com/klp/mes/qc/controller/WmsInspectionItemTemplateController.java index 226bcf5b4..938e6a442 100644 --- a/klp-mes/src/main/java/com/klp/mes/qc/controller/WmsInspectionItemTemplateController.java +++ b/klp-mes/src/main/java/com/klp/mes/qc/controller/WmsInspectionItemTemplateController.java @@ -99,7 +99,7 @@ public class WmsInspectionItemTemplateController extends BaseController { } // 根据待检项查询详细信息 - @PostMapping("/getInfoByInspectionItem") + @GetMapping("/getInfoByInspectionItem") public R> getInfoByInspectionItem(@RequestParam String inspectionItemIds) { return R.ok(iWmsInspectionItemTemplateService.getInfoByInspectionItem(inspectionItemIds)); } diff --git a/klp-ui/src/api/mes/qc/approval.js b/klp-ui/src/api/mes/qc/approval.js new file mode 100644 index 000000000..9b720ad8a --- /dev/null +++ b/klp-ui/src/api/mes/qc/approval.js @@ -0,0 +1,64 @@ +import request from '@/utils/request' + +// 查询检化验申请单列表 +export function listInspectionApplication(query) { + return request({ + url: '/wms/inspectionApplication/list', + method: 'get', + params: query + }) +} + +// 查询检化验申请单详细 +export function getInspectionApplication(applicationId) { + return request({ + url: '/wms/inspectionApplication/' + applicationId, + method: 'get' + }) +} + +// 新增检化验申请单 +export function addInspectionApplication(data) { + return request({ + url: '/wms/inspectionApplication', + method: 'post', + data: data + }) +} + +// 修改检化验申请单 +export function updateInspectionApplication(data) { + return request({ + url: '/wms/inspectionApplication', + method: 'put', + data: data + }) +} + +// 删除检化验申请单 +export function delInspectionApplication(applicationIds) { + return request({ + url: '/wms/inspectionApplication/' + applicationIds, + method: 'delete' + }) +} + +// ====== 批量保存检验数据(审批通过后填写) ====== + +// 批量保存物理检验数据 +export function batchSavePhysicalData(data) { + return request({ + url: '/wms/inspectionApplication/batchSavePhysical', + method: 'post', + data: data + }) +} + +// 批量保存化学检验数据 +export function batchSaveChemicalData(data) { + return request({ + url: '/wms/inspectionApplication/batchSaveChemical', + method: 'post', + data: data + }) +} diff --git a/klp-ui/src/api/mes/qc/inspectionItemTemplate.js b/klp-ui/src/api/mes/qc/inspectionItemTemplate.js index 00ec091af..122971cc9 100644 --- a/klp-ui/src/api/mes/qc/inspectionItemTemplate.js +++ b/klp-ui/src/api/mes/qc/inspectionItemTemplate.js @@ -47,7 +47,7 @@ export function delInspectionItemTemplate(templateId) { export function getInfoByInspectionItem(inspectionItemIds) { return request({ url: '/qc/inspectionItemTemplate/getInfoByInspectionItem', - method: 'post', + method: 'get', params: { inspectionItemIds } diff --git a/klp-ui/src/views/mes/qc/approval/index.vue b/klp-ui/src/views/mes/qc/approval/index.vue new file mode 100644 index 000000000..741057ff9 --- /dev/null +++ b/klp-ui/src/views/mes/qc/approval/index.vue @@ -0,0 +1,1573 @@ + + + + + diff --git a/klp-ui/src/views/mes/qc/history/index.vue b/klp-ui/src/views/mes/qc/history/index.vue deleted file mode 100644 index de04f7319..000000000 --- a/klp-ui/src/views/mes/qc/history/index.vue +++ /dev/null @@ -1,229 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/inspection/item.vue b/klp-ui/src/views/mes/qc/inspection/item.vue deleted file mode 100644 index 4d04cd584..000000000 --- a/klp-ui/src/views/mes/qc/inspection/item.vue +++ /dev/null @@ -1,402 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/inspection/task.vue b/klp-ui/src/views/mes/qc/inspection/task.vue deleted file mode 100644 index 6a45f0311..000000000 --- a/klp-ui/src/views/mes/qc/inspection/task.vue +++ /dev/null @@ -1,1010 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/inspectionSample/index.vue b/klp-ui/src/views/mes/qc/inspectionSample/index.vue index 8f90eb489..4e24aaa4d 100644 --- a/klp-ui/src/views/mes/qc/inspectionSample/index.vue +++ b/klp-ui/src/views/mes/qc/inspectionSample/index.vue @@ -3,14 +3,14 @@
所属单位: - + 全部 {{ company }}
方案名称: - + 全部 {{ scheme }} @@ -42,6 +42,9 @@ + @@ -151,7 +130,6 @@ export default { return { filterLoading: false, mainLoading: false, - addMainDialogVisible: false, templateList: [], cascadeData: {}, companyOptions: [], @@ -166,14 +144,7 @@ export default { pageNum: 1, pageSize: 1000 }, - dateRange: [], - addMainFormData: { - sampleName: '', - sampleNo: '', - batchNo: '', - inspectionDate: '', - remark: '' - } + dateRange: [] } }, created() { @@ -247,6 +218,7 @@ export default { }, handleCompanyChange() { + if (this.mainLoading) return this.selectedScheme = '' if (this.selectedCompany) { this.schemeOptions = this.cascadeData[this.selectedCompany] || [] @@ -262,6 +234,7 @@ export default { }, handleSchemeChange() { + if (this.mainLoading) return if (!this.selectedScheme) { this.currentTemplate = null this.mainList = [] @@ -365,31 +338,39 @@ export default { }, handleAddMain() { - this.addMainFormData = { + const itemMap = {} + if (this.checkItems.length > 0) { + this.checkItems.forEach(item => { + itemMap[item.itemName] = { + detailId: undefined, + mainId: undefined, + itemName: item.itemName, + itemValue: '', + itemUnit: item.unit, + upperLimit: item.targetUpper, + lowerLimit: item.targetLower, + rangeDesc: '' + } + }) + } + const newRow = { + _isNew: true, + _items: itemMap, + _originalItems: JSON.parse(JSON.stringify(itemMap)), + inspectionDate: '', sampleName: '', sampleNo: '', batchNo: '', - inspectionDate: '', remark: '' } - this.addMainDialogVisible = true - }, - - submitAddMain() { - const data = { - ...this.addMainFormData, - templateId: this.currentTemplate.templateId - } - addInspectionMain(data).then(() => { - this.$message.success('新增成功') - this.addMainDialogVisible = false - this.getMainList() - }).catch(() => { - this.$message.error('新增失败') - }) + this.mainList.unshift(newRow) }, handleSaveMain(row) { + if (!row.inspectionDate) { + this.$message.warning('请选择检验日期') + return + } row._saving = true const detailList = this.checkItems.map(checkItem => { const itemData = row._items[checkItem.itemName] @@ -405,38 +386,20 @@ export default { rangeDesc: itemData.rangeDesc || '' } }).filter(Boolean) - updateInspectionMain({ - mainId: row.mainId, + const requestData = { sampleName: row.sampleName, sampleNo: row.sampleNo, batchNo: row.batchNo, inspectionDate: row.inspectionDate, remark: row.remark, + templateId: this.currentTemplate.templateId, detailList: detailList - }).then(() => { + } + const isNew = row._isNew || !row.mainId + const apiCall = isNew ? addInspectionMain(requestData) : updateInspectionMain({ ...requestData, mainId: row.mainId }) + apiCall.then(() => { this.$message.success('保存成功') - return listInspectionDetail({ mainId: row.mainId, pageNum: 1, pageSize: 9999 }) - }).then(response => { - const details = response.rows || [] - if (this.checkItems.length > 0) { - this.checkItems.forEach(item => { - const found = details.find(d => d.itemName === item.itemName) - if (found) { - row._items[item.itemName] = { - detailId: found.detailId, - mainId: found.mainId, - itemName: found.itemName, - itemValue: found.itemValue || '', - itemUnit: found.itemUnit || item.unit, - upperLimit: found.upperLimit, - lowerLimit: found.lowerLimit, - rangeDesc: found.rangeDesc - } - } - }) - } - row._originalItems = JSON.parse(JSON.stringify(row._items)) - row._saving = false + this.getMainList() }).catch(() => { this.$message.error('保存失败') row._saving = false @@ -515,4 +478,10 @@ export default { ::v-deep .dynamic-table .el-table__body-wrapper { overflow-x: auto; } + +.required-mark::before { + content: '*'; + color: #f56c6c; + margin-right: 4px; +} diff --git a/klp-ui/src/views/mes/qc/item/index.vue b/klp-ui/src/views/mes/qc/item/index.vue deleted file mode 100644 index 31c6fc83a..000000000 --- a/klp-ui/src/views/mes/qc/item/index.vue +++ /dev/null @@ -1,299 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/task/index.vue b/klp-ui/src/views/mes/qc/task/index.vue deleted file mode 100644 index 674d67e5f..000000000 --- a/klp-ui/src/views/mes/qc/task/index.vue +++ /dev/null @@ -1,405 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/task/pages/auxiliary.vue b/klp-ui/src/views/mes/qc/task/pages/auxiliary.vue deleted file mode 100644 index c66232d35..000000000 --- a/klp-ui/src/views/mes/qc/task/pages/auxiliary.vue +++ /dev/null @@ -1,467 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/task/pages/lab.vue b/klp-ui/src/views/mes/qc/task/pages/lab.vue deleted file mode 100644 index bf55ca316..000000000 --- a/klp-ui/src/views/mes/qc/task/pages/lab.vue +++ /dev/null @@ -1,443 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/task/pages/raw.vue b/klp-ui/src/views/mes/qc/task/pages/raw.vue deleted file mode 100644 index e9c4d0366..000000000 --- a/klp-ui/src/views/mes/qc/task/pages/raw.vue +++ /dev/null @@ -1,493 +0,0 @@ - - - diff --git a/klp-ui/src/views/mes/qc/task/pages/section.vue b/klp-ui/src/views/mes/qc/task/pages/section.vue deleted file mode 100644 index 513de3a91..000000000 --- a/klp-ui/src/views/mes/qc/task/pages/section.vue +++ /dev/null @@ -1,451 +0,0 @@ - - - From d0a85c6d6571525f4d9780f7ecc1a8e6c7a1f1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Wed, 8 Jul 2026 16:49:58 +0800 Subject: [PATCH 2/8] =?UTF-8?q?feat(wms/coil/stock,=20wms/post/aps):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BF=AB=E6=8D=B7=E7=AD=9B=E9=80=89=E5=92=8C?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=86=85=E7=8A=B6=E6=80=81=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 为卷材库存页面添加快捷品质筛选按钮,支持全选、AB/CD/O/CDO模式快速筛选 2. 为排产页面添加表格内快捷修改排产状态功能,支持行内编辑并加载状态提示 3. 新增排产状态4"已排产"的枚举值和对应样式 4. 禁用排产编辑弹窗的工序类型选择框,优化表单交互 --- klp-ui/src/views/wms/coil/stock/index.vue | 27 +++++++++++++++++ klp-ui/src/views/wms/post/aps/schedule.vue | 34 +++++++++++++++++----- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/klp-ui/src/views/wms/coil/stock/index.vue b/klp-ui/src/views/wms/coil/stock/index.vue index 3b4928174..e77037745 100644 --- a/klp-ui/src/views/wms/coil/stock/index.vue +++ b/klp-ui/src/views/wms/coil/stock/index.vue @@ -23,6 +23,11 @@ 查询 重置 + 全选模式 + AB模式 + CD模式 + O模式 + CDO模式 @@ -627,6 +632,28 @@ export default { this.queryParams = { warehouseIds: Object.keys(this.warehouseMap), qualityStatusCsv: 'A+,A,A-,B+,B,B-' }; this.getList(); }, + + // 快捷品质筛选 + quickQualityAll() { + this.queryParams.qualityStatusCsv = ''; + this.getList(); + }, + quickQualityAB() { + this.queryParams.qualityStatusCsv = 'A+,A,A-,B+,B,B-'; + this.getList(); + }, + quickQualityCD() { + this.queryParams.qualityStatusCsv = 'C+,C,C-,D+,D,D-'; + this.getList(); + }, + quickQualityO() { + this.queryParams.qualityStatusCsv = 'O'; + this.getList(); + }, + quickQualityCDO() { + this.queryParams.qualityStatusCsv = 'C+,C,C-,D+,D,D-,O'; + this.getList(); + }, }, }; diff --git a/klp-ui/src/views/wms/post/aps/schedule.vue b/klp-ui/src/views/wms/post/aps/schedule.vue index 837b1a64c..cdc8fb3f8 100644 --- a/klp-ui/src/views/wms/post/aps/schedule.vue +++ b/klp-ui/src/views/wms/post/aps/schedule.vue @@ -296,9 +296,17 @@ - + @@ -404,7 +412,7 @@ - + @@ -660,7 +668,7 @@ export default { // 待审核 pendingScheduleList: [], summaryText: '', - statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回' }, + statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回', 4: '已排产' }, processOptions: PROCESSES, // 已接收 @@ -943,12 +951,21 @@ export default { }) }, + // 表格内快捷修改排产状态 + handleInlineStatusChange(row, val) { + this.$set(row, '_statusLoading', true) + updateScheduleItem({ scheduleId: row.scheduleId, scheduleStatus: val }).then(() => { + this.$modal.msgSuccess('状态已更新') + }).catch(() => { + this.$modal.msgError('状态更新失败') + this.queryScheduled() + }).finally(() => { + this.$set(row, '_statusLoading', false) + }) + }, + handleEditScheduled(row) { this.editForm = { ...this.getEmptyEditForm(), ...row } - // 确保 actionId 为数字类型以匹配下拉选项 - if (this.editForm.actionId != null && typeof this.editForm.actionId !== 'number') { - this.editForm.actionId = Number(this.editForm.actionId) - } // 确保 scheduleStatus 为数字类型以匹配下拉选项 if (this.editForm.scheduleStatus != null && typeof this.editForm.scheduleStatus !== 'number') { this.editForm.scheduleStatus = Number(this.editForm.scheduleStatus) @@ -1229,6 +1246,7 @@ export default { &.status-1 { background: #fff3e0; color: #e67e22; } &.status-2 { background: #e8f5e9; color: #388e3c; } &.status-3 { background: #fdecea; color: #e74c3c; } + &.status-4 { background: #e3f2fd; color: #1976d2; } } // 产需单信息表 From 49bb8e116f38a0a7c2d0834bb814daf78ab29848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Wed, 8 Jul 2026 17:16:58 +0800 Subject: [PATCH 3/8] =?UTF-8?q?feat(wms/menu):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=92=A2=E5=8D=B7=E5=AF=BC=E5=87=BA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E8=8F=9C=E5=8D=95=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增单行/多行异常钢卷导出按钮,带权限控制 2. 优化菜单导出Excel,新增路由地址和完整路由地址列 --- klp-ui/src/views/system/menu/index.vue | 38 +++++++++++++++++------ klp-ui/src/views/wms/coil/panels/base.vue | 26 ++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/klp-ui/src/views/system/menu/index.vue b/klp-ui/src/views/system/menu/index.vue index 92e302b3e..61eac578b 100644 --- a/klp-ui/src/views/system/menu/index.vue +++ b/klp-ui/src/views/system/menu/index.vue @@ -617,12 +617,30 @@ export default { }; // 递归展平为一维数组,缩进体现层级 - const flattenTree = (nodes, level = 0, result = []) => { + const flattenTree = (nodes, level = 0, parentPath = '', result = []) => { nodes.forEach(node => { const prefix = '\u3000'.repeat(level); // 全角空格缩进 + const ownPath = node.path || ''; + // 计算完整路由地址(仅菜单类型 C 有效) + let fullPath = ''; + if (node.menuType === 'C') { + if (node.isFrame === '0') { + // 外链:完整路由就是自身路径 + fullPath = ownPath; + } else { + // 内部路由:父路径 + 自身路径 + const parent = parentPath ? (parentPath.endsWith('/') ? parentPath : parentPath + '/') : ''; + fullPath = '/' + parent + ownPath; + } + } + // 目录(M)的路径作为子节点的父路径 + const currentParentPath = node.menuType === 'M' ? ownPath : parentPath; + result.push({ menuName: prefix + node.menuName, menuType: menuTypeMap[node.menuType] || node.menuType, + path: ownPath, + fullPath: fullPath, icon: node.icon || '', orderNum: node.orderNum, perms: node.perms || '', @@ -631,7 +649,7 @@ export default { createTime: node.createTime || '' }); if (node.children && node.children.length > 0) { - flattenTree(node.children, level + 1, result); + flattenTree(node.children, level + 1, currentParentPath, result); } }); return result; @@ -647,19 +665,21 @@ export default { // 构建 Excel 数据 const wsData = [ - ['菜单名称', '菜单类型', '图标', '排序', '权限标识', '组件路径', '状态', '创建时间'], + ['菜单名称', '菜单类型', '路由地址', '完整路由地址', '图标', '排序', '权限标识', '组件路径', '状态', '创建时间'], ...flatData.map(item => [ - item.menuName, item.menuType, item.icon, - item.orderNum, item.perms, item.component, - item.status, item.createTime + item.menuName, item.menuType, item.path, + item.fullPath, item.icon, item.orderNum, + item.perms, item.component, item.status, + item.createTime ]) ]; const ws = XLSX.utils.aoa_to_sheet(wsData); ws['!cols'] = [ - { wch: 30 }, { wch: 10 }, { wch: 12 }, - { wch: 8 }, { wch: 25 }, { wch: 30 }, - { wch: 8 }, { wch: 20 } + { wch: 30 }, { wch: 10 }, { wch: 22 }, + { wch: 30 }, { wch: 12 }, { wch: 8 }, + { wch: 25 }, { wch: 30 }, { wch: 8 }, + { wch: 20 } ]; const wb = XLSX.utils.book_new(); diff --git a/klp-ui/src/views/wms/coil/panels/base.vue b/klp-ui/src/views/wms/coil/panels/base.vue index 4a9f4d876..b3bdc664a 100644 --- a/klp-ui/src/views/wms/coil/panels/base.vue +++ b/klp-ui/src/views/wms/coil/panels/base.vue @@ -135,6 +135,14 @@ 导出全部 + + 单行异常导出 + + + + 多行异常导出 + + 按实际库区排序 @@ -2336,6 +2344,24 @@ export default { }, 'coil.xlsx') } }, + /** 单行异常导出 — 每个钢卷一行,附带异常信息 */ + handleAbnormalExportSingle() { + const { orderBy, ...query } = this.queryParams; + query.selectType = query.itemType; + this.download('wms/materialCoil/exportAbnormal', { + ...query, + abnormalExportCount: 1, + }, `abnormalCoil_${new Date().getTime()}.xlsx`) + }, + /** 多行异常导出 — 每个异常记录一行,附带异常信息 */ + handleAbnormalExportMulti() { + const { orderBy, ...query } = this.queryParams; + query.selectType = query.itemType; + this.download('wms/materialCoil/exportAbnormal', { + ...query, + abnormalExportCount: 0, + }, `abnormalCoil_${new Date().getTime()}.xlsx`) + }, async handleNewExportProps(row) { this.loading = true let coilIds = '' From 451c7afcfd2941a58e6e57a32aaba3de0b0f76f2 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Thu, 9 Jul 2026 11:44:04 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat(performance):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=88=86=E7=BB=84=E7=BB=A9=E6=95=88=E7=BB=9F=E8=AE=A1=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在性能监控页面添加菜单分类总览模块,显示各模块操作量对比 - 实现菜单分组柱状图可视化,支持点击筛选功能 - 添加分类模块明细折叠面板,展示具体模块统计数据 - 集成后端菜单分组绩效接口,支持按一级菜单路径过滤 - 添加当前分类筛选标签显示,增强用户体验 - 优化图表渲染逻辑,增加空数据情况下的图表清理 - 完善响应式布局,适配不同屏幕尺寸调整 --- .../monitor/OperPerformanceController.java | 10 + .../domain/bo/OperPerformanceQuery.java | 5 + .../klp/system/domain/vo/OperMenuGroupVO.java | 44 +++ .../system/domain/vo/OperModuleStatVO.java | 5 + .../klp/system/mapper/SysOperLogMapper.java | 5 + .../system/service/ISysOperLogService.java | 6 + .../service/impl/SysOperLogServiceImpl.java | 81 ++++++ .../mapper/system/SysOperLogMapper.xml | 60 +++++ klp-ui/src/api/monitor/performance.js | 9 + .../src/views/monitor/performance/index.vue | 253 +++++++++++++++++- 10 files changed, 469 insertions(+), 9 deletions(-) create mode 100644 klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java diff --git a/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java b/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java index 7416f808d..4052a05fb 100644 --- a/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java +++ b/klp-admin/src/main/java/com/klp/web/controller/monitor/OperPerformanceController.java @@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import com.klp.common.core.controller.BaseController; import com.klp.common.core.domain.R; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -55,4 +56,13 @@ public class OperPerformanceController extends BaseController { public R> module(OperPerformanceQuery query) { return R.ok(operLogService.selectModuleRanking(query)); } + + /** + * 按菜单分组绩效统计(oper_page 匹配一级菜单 path) + */ + @SaCheckPermission("monitor:performance:list") + @GetMapping("/menuGroup") + public R> menuGroup(OperPerformanceQuery query) { + return R.ok(operLogService.selectMenuGroupPerformance(query)); + } } diff --git a/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java b/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java index e75f0e93b..7787e103f 100644 --- a/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java +++ b/klp-system/src/main/java/com/klp/system/domain/bo/OperPerformanceQuery.java @@ -40,4 +40,9 @@ public class OperPerformanceQuery implements Serializable { * 模块标题 */ private String title; + + /** + * oper_page 路径前缀(用于按一级菜单过滤,如 /wip) + */ + private String operPagePrefix; } diff --git a/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java b/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java new file mode 100644 index 000000000..237c833e2 --- /dev/null +++ b/klp-system/src/main/java/com/klp/system/domain/vo/OperMenuGroupVO.java @@ -0,0 +1,44 @@ +package com.klp.system.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单分组绩效统计 VO(按一级菜单 oper_page 归类) + * + * @author Reasonix + */ +@Data +@NoArgsConstructor +public class OperMenuGroupVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 菜单名称(驾驶舱、生产管控……) */ + private String menuName; + + /** 菜单路由路径前缀(post、wip……) */ + private String menuPath; + + /** 该分类操作总次数 */ + private Long totalCount; + + /** 成功次数 */ + private Long successCount; + + /** 失败次数 */ + private Long failCount; + + /** 成功率 (%) */ + private Double successRate; + + /** 使用人数 */ + private Long personCount; + + /** 该分类下的模块明细列表 */ + private List modules = new ArrayList<>(); +} diff --git a/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java b/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java index e9c26ee3e..96af83072 100644 --- a/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java +++ b/klp-system/src/main/java/com/klp/system/domain/vo/OperModuleStatVO.java @@ -16,6 +16,11 @@ public class OperModuleStatVO implements Serializable { private static final long serialVersionUID = 1L; + /** + * 所属菜单分组(菜单名称,如"驾驶舱") + */ + private String menuGroup; + /** * 模块标题 */ diff --git a/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java b/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java index 2dfc22d48..c134129b0 100644 --- a/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java +++ b/klp-system/src/main/java/com/klp/system/mapper/SysOperLogMapper.java @@ -35,4 +35,9 @@ public interface SysOperLogMapper extends BaseMapperPlus selectMenuGroupDetail(OperPerformanceQuery query); } diff --git a/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java b/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java index 9f11aeeeb..f5c8db56d 100644 --- a/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java +++ b/klp-system/src/main/java/com/klp/system/service/ISysOperLogService.java @@ -4,6 +4,7 @@ import com.klp.common.core.domain.PageQuery; import com.klp.common.core.page.TableDataInfo; import com.klp.system.domain.SysOperLog; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -69,4 +70,9 @@ public interface ISysOperLogService { * 模块使用排行 */ List selectModuleRanking(OperPerformanceQuery query); + + /** + * 按菜单分组绩效统计(oper_page 匹配一级菜单 path) + */ + List selectMenuGroupPerformance(OperPerformanceQuery query); } diff --git a/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java b/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java index 9a5a36d30..d6977eebc 100644 --- a/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java +++ b/klp-system/src/main/java/com/klp/system/service/impl/SysOperLogServiceImpl.java @@ -11,6 +11,7 @@ import com.klp.common.utils.StringUtils; import com.klp.common.utils.ip.AddressUtils; import com.klp.system.domain.SysOperLog; import com.klp.system.domain.bo.OperPerformanceQuery; +import com.klp.system.domain.vo.OperMenuGroupVO; import com.klp.system.domain.vo.OperModuleStatVO; import com.klp.system.domain.vo.OperPersonVO; import com.klp.system.domain.vo.OperSummaryVO; @@ -151,6 +152,86 @@ public class SysOperLogServiceImpl implements ISysOperLogService { return baseMapper.selectModuleSummary(query); } + @Override + public List selectMenuGroupPerformance(OperPerformanceQuery query) { + // 1. 查询原始数据(按 menu_group + title 双维度聚合) + List rawList = baseMapper.selectMenuGroupDetail(query); + if (rawList == null || rawList.isEmpty()) { + return Collections.emptyList(); + } + + // 2. 按 menuGroup 分组 + Map> groupMap = rawList.stream() + .collect(Collectors.groupingBy( + m -> m.getMenuGroup() != null ? m.getMenuGroup() : "其他", + LinkedHashMap::new, + Collectors.toList() + )); + + // 3. 固定顺序 + List orderNames = java.util.Arrays.asList( + "驾驶舱", "生产管控", "数字仓储", "质量管理", + "销售中心", "生产辅助", "科学排产", "文件夹", "其他" + ); + // path 前缀映射 + Map nameToPath = new LinkedHashMap<>(); + nameToPath.put("驾驶舱", "post"); + nameToPath.put("生产管控", "wip"); + nameToPath.put("数字仓储", "stock"); + nameToPath.put("质量管理", "quality"); + nameToPath.put("销售中心", "crm"); + nameToPath.put("生产辅助", "helper"); + nameToPath.put("科学排产", "aps"); + nameToPath.put("文件夹", "file"); + nameToPath.put("其他", ""); + + // 4. 构建 VO 列表 + List result = new ArrayList<>(); + for (String name : orderNames) { + List modules = groupMap.get(name); + if (modules == null || modules.isEmpty()) { + continue; // 没有数据的分类不展示 + } + + OperMenuGroupVO vo = new OperMenuGroupVO(); + vo.setMenuName(name); + vo.setMenuPath(nameToPath.getOrDefault(name, "")); + + // 汇总该分类的总量 + long total = modules.stream().mapToLong(m -> m.getTotalCount() != null ? m.getTotalCount() : 0).sum(); + long success = modules.stream() + .mapToLong(m -> Math.round((m.getTotalCount() != null ? m.getTotalCount() : 0) + * (m.getSuccessRate() != null ? m.getSuccessRate() : 0) / 100.0)) + .sum(); + long fail = total - success; + long persons = modules.stream() + .mapToLong(m -> m.getPersonCount() != null ? m.getPersonCount() : 0).sum(); + // 去重人数更合理:取各模块人数最大值作为估算(无法精确去重) + long distinctPersons = modules.stream() + .mapToLong(m -> m.getPersonCount() != null ? m.getPersonCount() : 0) + .max().orElse(0); + // 用 distinct 人数更合理,取模块中最大人数(保守估计) + // 实际跨模块可能有重复,这里用最大模块人数作为下限 + vo.setTotalCount(total); + vo.setSuccessCount(success); + vo.setFailCount(fail); + vo.setSuccessRate(total > 0 ? Math.round(success * 10000.0 / total) / 100.0 : 0.0); + vo.setPersonCount(distinctPersons); + + // 模块明细按 totalCount 降序排列 + modules.sort((a, b) -> { + long ta = a.getTotalCount() != null ? a.getTotalCount() : 0; + long tb = b.getTotalCount() != null ? b.getTotalCount() : 0; + return Long.compare(tb, ta); + }); + vo.setModules(modules); + + result.add(vo); + } + + return result; + } + @Override public List selectPersonPerformance(OperPerformanceQuery query) { // 1. 查询人员汇总 diff --git a/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml index c1a6f309b..66a15573d 100644 --- a/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml +++ b/klp-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -40,6 +40,7 @@ + @@ -90,6 +91,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.title ORDER BY total_count DESC @@ -126,6 +130,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.oper_name, l.dept_name ORDER BY total_count DESC @@ -159,6 +166,9 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + GROUP BY l.oper_name, l.title ORDER BY l.oper_name, total_count DESC @@ -190,7 +200,57 @@ AND l.title LIKE CONCAT('%', #{title}, '%') + + AND l.oper_page LIKE CONCAT(#{operPagePrefix}, '%') + + + + diff --git a/klp-ui/src/api/monitor/performance.js b/klp-ui/src/api/monitor/performance.js index a79abc42e..f8ad1bd24 100644 --- a/klp-ui/src/api/monitor/performance.js +++ b/klp-ui/src/api/monitor/performance.js @@ -26,3 +26,12 @@ export function getModuleRanking(params) { params: params }) } + +// 按菜单分组绩效统计(oper_page 匹配一级菜单) +export function getMenuGroup(params) { + return request({ + url: '/monitor/performance/menuGroup', + method: 'get', + params: params + }) +} diff --git a/klp-ui/src/views/monitor/performance/index.vue b/klp-ui/src/views/monitor/performance/index.vue index 92de84554..552e029ea 100644 --- a/klp-ui/src/views/monitor/performance/index.vue +++ b/klp-ui/src/views/monitor/performance/index.vue @@ -77,6 +77,70 @@
+ +
+ + +
+
+ 各模块操作量对比 + 点击柱子可按分类筛选下方图表 +
+
+
+ + + + +
+
分类模块明细
+
+ + + + + + + + + + + + + + + +
+
+
+ + +
+ + + {{ selectedMenuGroup.menuName }} + + — 以下图表仅显示该分类数据 +
+
@@ -176,16 +240,30 @@