diff --git a/src/api/system/orderPro.js b/src/api/system/orderPro.js index 9749c4c..ec1b904 100644 --- a/src/api/system/orderPro.js +++ b/src/api/system/orderPro.js @@ -16,6 +16,23 @@ export function getOrderPro(id) { method: 'get' }) } + +// 获取工艺上传日志 +export function getRouteLog(id) { + return request({ + url: '/system/orderPro/getRouteLog/' + id, + method: 'post' + }) +} + +// 获取BOM上传日志 +export function getBomUploadStatus(projectCode) { + return request({ + url: '/system/details/viewGetBomUploadStatus', + method: 'post', + params: { rooteProdet: projectCode } + }) +} export function processList(params) { return request({ url: '/system/orderPro/processlist', diff --git a/src/views/system/orderPro/index.vue b/src/views/system/orderPro/index.vue index 51fa0cf..444a7b6 100644 --- a/src/views/system/orderPro/index.vue +++ b/src/views/system/orderPro/index.vue @@ -479,6 +479,262 @@ style="margin-top: 20px; text-align: right;" /> + + +
+ 工艺上传日志 +
+ + +
+
+ 成功 + {{ processLogCounts.success }} +
+
+ 重复 + {{ processLogCounts.duplicate }} +
+
+ 失败 + {{ processLogCounts.failed }} +
+
+ + {{ processUploadLog.time }} + 暂无时间信息 +
+
+ + +
+ + 拉取最新日志 + + 清空 +
+ + +
+
+ + + 成功上传({{ processUploadLog.successfulRoutes.length }}) + + 工序行数:{{ successFlatRows.length }} +
+ + + + + + + + + + + + + +
+ + +
+
+ + + 重复({{ processUploadLog.duplicateRoutes.length }}) + +
+
+ + {{ dup }} + +
+
+ + +
+
+ + + 失败({{ processUploadLog.failedRoutes.length }}) + +
+ + + + + + + +
+ + + + +
+ + + +
+ BOM上传日志 +
+ + +
+
+ 成功 + {{ bomLogCounts.success }} +
+
+ 已存在 + {{ bomLogCounts.exists }} +
+
+ 失败 + {{ bomLogCounts.failed }} +
+
+ 总计:{{ bomLogCounts.total }} +
+
+ + +
+ + 拉取最新日志 + + 清空 +
+ + +
+
+ + + 成功上传({{ bomLogCounts.success }}) + +
+ + + + + + + +
+ + +
+
+ + + 已存在且一致({{ bomLogCounts.exists }}) + +
+ + + + + + + +
+ + +
+
+ + + 失败({{ bomLogCounts.failed }}) + +
+ + + + + + + +
+ + + + +
+ { + const base = { + materialCode: item.materialCode || '', + materialName: item.materialName || '' + }; + const details = Array.isArray(item.processRouteDT) ? item.processRouteDT : []; + details.forEach(dt => { + // 兼容两种字段命名: + // 1) 我们的前端命名:processNo / workCenter / processName / activityUnit / processControl / activityDuration / processDescription / processNameDescription + // 2) 后端K3字段命名:FOperNumber / FWorkCenterId.FName / FProcessId.FName / FActivity1UnitID.FName / FOptCtrlCodeId.FName / FActivity1Qty / FOperDescription / FNumber + const processNo = dt.processNo ?? dt.FOperNumber ?? dt['FOperNumber']; + const workCenter = dt.workCenter ?? (dt.FWorkCenterId && dt.FWorkCenterId.FName) ?? dt['FWorkCenterId.FName']; + const processName = dt.processName ?? (dt.FProcessId && dt.FProcessId.FName) ?? dt['FProcessId.FName']; + const activityUnit = dt.activityUnit ?? (dt.FActivity1UnitID && dt.FActivity1UnitID.FName) ?? dt['FActivity1UnitID.FName']; + const processControl = dt.processControl ?? (dt.FOptCtrlCodeId && dt.FOptCtrlCodeId.FName) ?? dt['FOptCtrlCodeId.FName']; + const activityDuration = dt.activityDuration ?? dt.FActivity1Qty ?? dt['FActivity1Qty']; + const processDescription = dt.processDescription ?? dt.FOperDescription ?? dt['FOperDescription']; + const processNameDescription = dt.processNameDescription ?? dt.FNumber ?? dt['FNumber']; + rows.push({ + ...base, + processNo, + workCenter, + processName, + activityUnit, + processControl, + activityDuration, + processDescription, + processNameDescription + }); + }); + }); + return rows; + }, + // 工艺成功项(分页) + successFlatPagedRows() { + const rows = this.successFlatRows; + const start = (this.processSuccessPage.pageNum - 1) * this.processSuccessPage.pageSize; + const end = start + this.processSuccessPage.pageSize; + return rows.slice(start, end); + }, + // 工艺失败项(分页) + processFailedPagedItems() { + const items = Array.isArray(this.processUploadLog?.failedRoutes) ? this.processUploadLog.failedRoutes : []; + const start = (this.processFailedPage.pageNum - 1) * this.processFailedPage.pageSize; + const end = start + this.processFailedPage.pageSize; + return items.slice(start, end); + }, + // BOM上传日志统计 + bomLogCounts() { + const items = Array.isArray(this.bomUploadLog?.items) ? this.bomUploadLog.items : []; + const success = items.filter(item => item.code === '200').length; + const exists = items.filter(item => item.code === '100').length; + const failed = items.filter(item => item.code === '300' || (item.code !== '200' && item.code !== '100')).length; + return { + success, + exists, + failed, + total: items.length + }; + }, + // BOM成功项 + bomSuccessItems() { + const items = Array.isArray(this.bomUploadLog?.items) ? this.bomUploadLog.items : []; + return items.filter(item => item.code === '200'); + }, + // BOM已存在项 + bomExistsItems() { + const items = Array.isArray(this.bomUploadLog?.items) ? this.bomUploadLog.items : []; + return items.filter(item => item.code === '100'); + }, + // BOM失败项 + bomFailedItems() { + const items = Array.isArray(this.bomUploadLog?.items) ? this.bomUploadLog.items : []; + return items.filter(item => item.code === '300' || (item.code !== '200' && item.code !== '100')); + }, + // BOM成功项(分页) + bomSuccessPagedItems() { + const items = this.bomSuccessItems; + const start = (this.bomSuccessPage.pageNum - 1) * this.bomSuccessPage.pageSize; + const end = start + this.bomSuccessPage.pageSize; + return items.slice(start, end); + }, + // BOM已存在项(分页) + bomExistsPagedItems() { + const items = this.bomExistsItems; + const start = (this.bomExistsPage.pageNum - 1) * this.bomExistsPage.pageSize; + const end = start + this.bomExistsPage.pageSize; + return items.slice(start, end); + }, + // BOM失败项(分页) + bomFailedPagedItems() { + const items = this.bomFailedItems; + const start = (this.bomFailedPage.pageNum - 1) * this.bomFailedPage.pageSize; + const end = start + this.bomFailedPage.pageSize; + return items.slice(start, end); + } + }, methods: { + async fetchProcessLog() { + if (!this.productionObj || !this.productionObj.id) { + this.$message.error('请先选择生产令号'); + return; + } + + this.processLogLoading = true; + try { + const res = await getRouteLog(this.productionObj.id); + if (res && (res.code === 200 || res.success)) { + // 后端返回的数据在 msg 字段中(JSON 字符串),如果 msg 为空则尝试 data + const jsonStr = res.msg || res.data || ''; + + // 如果返回的字符串为空,提示无数据 + if (!jsonStr || !jsonStr.trim()) { + this.$message.info('暂无工艺上传日志'); + this.clearProcessLog(); + return; + } + + // 解析 JSON 字符串 + let parsed = null; + try { + parsed = JSON.parse(jsonStr); + } catch (parseError) { + console.error('JSON 解析失败', parseError); + this.$message.error('日志数据格式错误,无法解析'); + this.clearProcessLog(); + return; + } + + // 处理不同的数据格式 + let latest = null; + + // 如果是数组,选择时间最新的一条记录 + if (Array.isArray(parsed)) { + if (parsed.length === 0) { + this.$message.info('暂无工艺上传日志'); + this.clearProcessLog(); + return; + } + latest = parsed.reduce((acc, cur) => { + const accTime = acc && acc.time ? new Date(acc.time).getTime() : 0; + const curTime = cur && cur.time ? new Date(cur.time).getTime() : 0; + return curTime >= accTime ? cur : acc; + }); + } + // 如果是单个对象,直接使用 + else if (parsed && typeof parsed === 'object') { + latest = parsed; + } + else { + this.$message.error('日志数据格式不正确'); + this.clearProcessLog(); + return; + } + + if (!latest) { + this.$message.info('暂无工艺上传日志'); + this.clearProcessLog(); + return; + } + + // 直接使用解析后的数据结构 + // 处理时间:dayjs 支持时间戳(毫秒)和日期字符串 + this.processUploadLog = { + time: latest.time ? dayjs(latest.time).format('YYYY-MM-DD HH:mm:ss') : null, + successfulRoutes: latest.successfulRoutes || [], + duplicateRoutes: latest.duplicateRoutes || [], + failedRoutes: latest.failedRoutes || [] + }; + this.$message.success('已拉取最新日志'); + } else { + this.$message.error(res && res.msg ? res.msg : '获取工艺上传日志失败'); + } + } catch (e) { + console.error('获取工艺上传日志异常', e); + this.$message.error('获取工艺上传日志失败'); + } finally { + this.processLogLoading = false; + } + }, + clearProcessLog() { + this.processUploadLog = { + time: null, + successfulRoutes: [], + duplicateRoutes: [], + failedRoutes: [] + }; + // 重置分页 + this.processSuccessPage = { pageNum: 1, pageSize: 10 }; + this.processFailedPage = { pageNum: 1, pageSize: 10 }; + }, + // 获取BOM上传日志 + async fetchBomLog() { + if (!this.productionObj || !this.productionObj.productionOrderNo) { + this.$message.error('请先选择生产令号'); + return; + } + + this.bomLogLoading = true; + try { + const res = await getBomUploadStatus(this.productionObj.productionOrderNo); + if (res && (res.code === 200 || res.success)) { + // 后端返回的数据在 data 字段中(JSON 字符串),如果 data 为空则尝试 msg + const jsonStr = res.data || res.msg || ''; + + // 如果返回的字符串为空,提示无数据 + if (!jsonStr || !jsonStr.trim()) { + this.$message.info('暂无BOM上传日志'); + this.clearBomLog(); + return; + } + + // 解析 JSON 字符串 + let parsed = null; + try { + parsed = JSON.parse(jsonStr); + } catch (parseError) { + console.error('JSON 解析失败', parseError); + this.$message.error('BOM日志数据格式错误,无法解析'); + this.clearBomLog(); + return; + } + + // 处理数据:如果是数组,直接使用;如果是对象且有 items 属性,使用 items + let items = []; + if (Array.isArray(parsed)) { + items = parsed; + } else if (parsed && typeof parsed === 'object' && Array.isArray(parsed.items)) { + items = parsed.items; + } else { + this.$message.error('BOM日志数据格式不正确'); + this.clearBomLog(); + return; + } + + this.bomUploadLog = { + items: items + }; + this.$message.success('已拉取最新BOM日志'); + } else { + this.$message.error(res && res.msg ? res.msg : '获取BOM上传日志失败'); + } + } catch (e) { + console.error('获取BOM上传日志异常', e); + this.$message.error('获取BOM上传日志失败'); + } finally { + this.bomLogLoading = false; + } + }, + // 清空BOM日志 + clearBomLog() { + this.bomUploadLog = { + items: [] + }; + // 重置分页 + this.bomSuccessPage = { pageNum: 1, pageSize: 10 }; + this.bomExistsPage = { pageNum: 1, pageSize: 10 }; + this.bomFailedPage = { pageNum: 1, pageSize: 10 }; + }, + // 格式化BOM错误信息 + formatBomErrorReason(reason) { + if (!reason) return ''; + // 如果 reason 是 JSON 字符串,尝试解析并格式化 + try { + const parsed = JSON.parse(reason); + if (Array.isArray(parsed)) { + return parsed.map(item => { + const field = item.FieldName || ''; + const message = item.Message || ''; + return field ? `${field}: ${message}` : message; + }).join('; '); + } + return reason; + } catch (e) { + // 如果不是 JSON,直接返回原字符串 + return reason; + } + }, formatFraction(value) { // 如果本身就是分数字符串,直接返回 if (typeof value === 'string' && value.includes('/')) { @@ -932,6 +1499,14 @@ export default { this.drawer = true; // 打开抽屉后加载表格数据 this.loadChainTableData(); + // 自动加载工艺上传日志 + if (row && row.id) { + this.fetchProcessLog(); + } + // 自动加载BOM上传日志 + if (row && row.productionOrderNo) { + this.fetchBomLog(); + } }, /** 获取图纸类型标签 */ getDrawingTypeLabel(value) { @@ -1560,10 +2135,12 @@ export default { return false; } - // 验证文件大小(可选,限制为50MB) - const maxSize = 50 * 1024 * 1024; // 50MB + // 验证文件大小(根据前端阈值,默认 100MB),提示包含所选文件大小 + const limitMB = Number(this.dwgMaxSizeMB) || 100; + const maxSize = limitMB * 1024 * 1024; + const sizeMB = (file.size / (1024 * 1024)).toFixed(2); if (file.size > maxSize) { - this.$message.error('文件大小不能超过50MB'); + this.$message.error(`文件过大(所选 ${sizeMB}MB,限制 ${limitMB}MB)。请压缩后重试或联系管理员调整服务器限制`); return false; } @@ -1585,6 +2162,11 @@ export default { }, handleDwgUploadError(error, file, row) { console.error('图纸上传失败:', error); + const status = (error && (error.status || (error.response && error.response.status))) || 0; + if (status === 413) { + this.$message.error('文件过大(超出服务器限制)。请联系管理员提高上传大小限制或压缩文件后重试'); + return; + } this.$message.error(`图纸上传失败:${file.name}`); }, downloadPDF() {