feat: 新增盘库管理全流程功能模块
1. 新增批量新增盘库差异记录API 2. 新增盘库Excel对比工具函数 3. 新增盘库申请页面与库区明细组件 4. 优化流程图页面,新增流程图下载功能 5. 重构盘库主页面流程状态与操作逻辑 6. 新增多组件拆分与页面模块化改造
This commit is contained in:
@@ -13,6 +13,19 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flow-toolbar">
|
||||
<el-dropdown trigger="click" @command="handleDownload">
|
||||
<el-button size="small" type="primary" plain>
|
||||
<i class="el-icon-download"></i> 下载流程图
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="svg">下载 SVG</el-dropdown-item>
|
||||
<el-dropdown-item command="png">下载 PNG</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading" class="flow-content">
|
||||
<div ref="diagram" class="flow-diagram" v-html="currentSvg" @click="onNodeClick"></div>
|
||||
</div>
|
||||
@@ -110,80 +123,105 @@ graph TD
|
||||
|
||||
inventoryCheck: `
|
||||
graph TD
|
||||
A["<b>创建盘库单</b><br/>填写盘库单基本信息<br/>添加盘库计划"]:::c1
|
||||
A["<b>创建盘库计划</b><br/>填写基本信息"]:::c1
|
||||
|
||||
A --> B["<b>盘库计划</b><br/>设定起止时间<br/>选择库区类型"]:::c2
|
||||
B --> C{"<b>库区类型?</b>"}:::cdec
|
||||
A --> B["<b>创建计划明细</b><br/>可创建多个明细"]:::c2
|
||||
|
||||
C -->|逻辑库| D["<b>获取库存快照</b><br/>记录当前时间节点<br/>库存情况"]:::c3
|
||||
C -->|物理库| E["<b>获取库存快照</b><br/>记录当前时间节点<br/>库存情况"]:::c3
|
||||
E --> F["<b>记录吞吐记录</b><br/>额外记录物理库<br/>出入库流水明细"]:::c4
|
||||
B --> C["<b>选择库区</b><br/>逻辑库 / 实际库<br/>至少选一个"]:::c3
|
||||
C --> D["<b>生成系统库存快照</b>"]:::c4
|
||||
D --> E["<b>上传实盘库存Excel</b>"]:::c5
|
||||
E --> F["<b>执行对比</b><br/>快照 vs 实盘<br/>自动计算差异"]:::c6
|
||||
|
||||
D --> G["<b>人工实地盘库</b><br/>按盘库计划执行<br/>录入实际库存数据"]:::c5
|
||||
F --> G
|
||||
F --> G["<b>查看差异明细</b><br/>保存差异并填写处理方式"]:::c7
|
||||
G --> H["<b>提交送审</b>"]:::c8
|
||||
|
||||
G --> H["<b>系统自动对照</b><br/>快照库存 vs 实际库存<br/>逐项比对查找差异"]:::c6
|
||||
H --> I{"审批"}:::dec
|
||||
I -->|不通过| J["<b>退回修改</b>"]:::c7
|
||||
J --> G
|
||||
I -->|通过| K["<b>开始处理差异</b><br/>逐项执行处理方式"]:::c9
|
||||
|
||||
H --> I["<b>盘亏明细</b><br/>系统有 实际无<br/>库存缺失项"]:::loss
|
||||
H --> J["<b>盘盈明细</b><br/>实际有 系统无<br/>库存多出项"]:::gain
|
||||
H --> K["<b>明细差异</b><br/>数据不一致<br/>数量/规格偏差"]:::diff
|
||||
|
||||
I --> L["<b>生成盘库差异报告</b><br/>汇总盘亏/盘盈/差异<br/>存储差异记录"]:::c7
|
||||
J --> L
|
||||
K --> L
|
||||
|
||||
L --> M(["<b>盘库单封存</b><br/>流程结束"]):::cend
|
||||
K --> L{"所有差异<br/>处理完成?"}:::dec
|
||||
L -->|否| K
|
||||
L -->|是| M(["<b>完结流程</b><br/>盘库结束"]):::cend
|
||||
|
||||
classDef c1 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
|
||||
classDef c2 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
|
||||
classDef cdec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
|
||||
classDef c3 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef c4 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
|
||||
classDef c3 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
|
||||
classDef c4 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef c5 fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
|
||||
classDef c6 fill:#fffbe6,stroke:#fadb14,color:#303133,stroke-width:2px
|
||||
classDef loss fill:#fff1f0,stroke:#f5222d,color:#303133,stroke-width:2px
|
||||
classDef gain fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
|
||||
classDef diff fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
|
||||
classDef c6 fill:#fffbe6,stroke:#fadb14,color:#606266,stroke-width:2px
|
||||
classDef c7 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef c8 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
|
||||
classDef c9 fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
|
||||
classDef dec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
|
||||
classDef cend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
|
||||
linkStyle default stroke:#bfbfbf,stroke-width:2px
|
||||
`,
|
||||
|
||||
productionSchedule: `
|
||||
stateDiagram-v2
|
||||
[*] --> 创建排产单: 填写基本信息
|
||||
创建排产单 --> 关联合同获取需求: 选择合同
|
||||
关联合同获取需求 --> 选择需求合并明细: 选取需求<br/>合并相同条目
|
||||
选择需求合并明细 --> 提交审批
|
||||
graph TD
|
||||
A["<b>创建需求单</b><br/>填写基本信息"]:::p1
|
||||
|
||||
提交审批 --> 审批驳回: 审批不通过
|
||||
提交审批 --> 审批通过: 审批通过
|
||||
A --> B["<b>选择合同</b><br/>可选一个或多个合同"]:::p2
|
||||
B --> C["<b>自动获取需求明细</b><br/>从所选合同提取"]:::p3
|
||||
C --> D["<b>调整需求明细</b><br/>可编辑/修改/补充"]:::p4
|
||||
|
||||
审批驳回 --> 选择需求合并明细: 退回修改后重新提交
|
||||
D --> E["<b>提交审批</b>"]:::p5
|
||||
E --> F{"审批"}:::dec
|
||||
F -->|不通过| G["<b>退回修改</b>"]:::p4
|
||||
G --> D
|
||||
F -->|通过| H["<b>转化为排产单</b>"]:::p6
|
||||
|
||||
审批通过 --> 车间接收执行单: 转为执行单推送车间
|
||||
H --> I["<b>排产单</b><br/>可再次编辑"]:::p7
|
||||
I --> J["<b>再次提交审批</b>"]:::p5
|
||||
J --> K{"审批"}:::dec
|
||||
K -->|不通过| L["<b>退回修改</b>"]:::p7
|
||||
L --> I
|
||||
K -->|通过| M["<b>提交给车间</b>"]:::p8
|
||||
|
||||
车间接收执行单 --> 执行生产: 车间接收
|
||||
车间接收执行单 --> 审批驳回: 车间打回拒绝
|
||||
M --> N["<b>车间绑定钢卷</b><br/>每个排产计划<br/>绑定一个或多个钢卷"]:::p9
|
||||
N --> O["<b>执行生产</b>"]:::p10
|
||||
O --> P(["<b>排产完结</b>"]):::pend
|
||||
|
||||
执行生产 --> [*]: 排产完结
|
||||
classDef p1 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
|
||||
classDef p2 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
|
||||
classDef p3 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
|
||||
classDef p4 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef p5 fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
|
||||
classDef p6 fill:#fffbe6,stroke:#fadb14,color:#606266,stroke-width:2px
|
||||
classDef p7 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
|
||||
classDef p8 fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
|
||||
classDef p9 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef p10 fill:#fffbe6,stroke:#fadb14,color:#303133,stroke-width:2px
|
||||
classDef dec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
|
||||
classDef pend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
|
||||
linkStyle default stroke:#bfbfbf,stroke-width:2px
|
||||
`,
|
||||
|
||||
equipmentRepair: `
|
||||
stateDiagram-v2
|
||||
[*] --> 创建维修计划: 点选异常巡检记录<br/>绑定记录与异常设备
|
||||
创建维修计划 --> 审批维修计划
|
||||
graph TD
|
||||
A["<b>创建维修计划</b>"]:::e1
|
||||
A1["点选异常巡检记录<br/>绑定记录与异常设备"]:::e1sub
|
||||
A --> A1
|
||||
|
||||
审批维修计划 --> 审批驳回: 审批不通过
|
||||
审批维修计划 --> 审批通过: 审批通过
|
||||
A1 --> B["<b>提交审批</b>"]:::e2
|
||||
B --> C{"审批"}:::edec
|
||||
C -->|不通过| D["<b>退回修改</b>"]:::e1
|
||||
D --> A1
|
||||
C -->|通过| E["<b>逐设备维修记录</b><br/>逐一执行设备维修<br/>记录维修过程与结果"]:::e3
|
||||
|
||||
审批驳回 --> 创建维修计划: 退回修改后重新提交
|
||||
E --> F{"全部设备<br/>维修完成?"}:::edec
|
||||
F -->|否| E
|
||||
F -->|是| G(["<b>流程结束</b>"]):::eend
|
||||
|
||||
审批通过 --> 逐设备维修记录: 逐一执行设备维修<br/>记录维修过程与结果
|
||||
|
||||
逐设备维修记录 --> 逐设备维修记录: 存在未维修设备
|
||||
逐设备维修记录 --> [*]: 全部设备维修完成<br/>流程结束
|
||||
`
|
||||
classDef e1 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
|
||||
classDef e1sub fill:#e6fffa,stroke:#13c2c2,color:#606266,stroke-width:1px,stroke-dasharray:3 3
|
||||
classDef e2 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
|
||||
classDef e3 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
|
||||
classDef edec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
|
||||
classDef eend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
|
||||
linkStyle default stroke:#bfbfbf,stroke-width:2px
|
||||
`,
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -201,6 +239,7 @@ export default {
|
||||
],
|
||||
svgCache: {},
|
||||
selectedNode: null,
|
||||
downloadLoading: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -226,6 +265,76 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleDownload(format) {
|
||||
if (format === 'svg') {
|
||||
this.downloadSvg()
|
||||
} else if (format === 'png') {
|
||||
this.downloadPng()
|
||||
}
|
||||
},
|
||||
downloadSvg() {
|
||||
const svgEl = this.$refs.diagram?.querySelector('svg')
|
||||
if (!svgEl) {
|
||||
this.$message.warning('流程图尚未渲染完成')
|
||||
return
|
||||
}
|
||||
const clone = svgEl.cloneNode(true)
|
||||
const serializer = new XMLSerializer()
|
||||
const source = serializer.serializeToString(clone)
|
||||
const blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' })
|
||||
this.triggerDownload(URL.createObjectURL(blob), `${this.activeTab}.svg`)
|
||||
this.$message.success('SVG 已下载')
|
||||
},
|
||||
downloadPng() {
|
||||
const svgEl = this.$refs.diagram?.querySelector('svg')
|
||||
if (!svgEl) {
|
||||
this.$message.warning('流程图尚未渲染完成')
|
||||
return
|
||||
}
|
||||
this.downloadLoading = true
|
||||
|
||||
const clone = svgEl.cloneNode(true)
|
||||
const serializer = new XMLSerializer()
|
||||
let source = serializer.serializeToString(clone)
|
||||
source = source.replace(/<\/?foreignObject[^>]*>/gi, '').replace(/<\/?style[^>]*>/gi, '')
|
||||
|
||||
const svgBlob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' })
|
||||
const url = URL.createObjectURL(svgBlob)
|
||||
|
||||
const img = new Image()
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas')
|
||||
const rect = svgEl.getBoundingClientRect()
|
||||
const scale = 2
|
||||
canvas.width = rect.width * scale
|
||||
canvas.height = rect.height * scale
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.scale(scale, scale)
|
||||
ctx.drawImage(img, 0, 0, rect.width, rect.height)
|
||||
URL.revokeObjectURL(url)
|
||||
canvas.toBlob(blob => {
|
||||
this.downloadLoading = false
|
||||
if (blob) {
|
||||
this.triggerDownload(URL.createObjectURL(blob), `${this.activeTab}.png`)
|
||||
this.$message.success('PNG 已下载')
|
||||
}
|
||||
}, 'image/png')
|
||||
}
|
||||
img.onerror = () => {
|
||||
this.downloadLoading = false
|
||||
this.$message.error('PNG 导出失败')
|
||||
}
|
||||
img.src = url
|
||||
},
|
||||
triggerDownload(url, filename) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = filename
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
},
|
||||
switchTab(key) {
|
||||
this.activeTab = key
|
||||
this.selectedNode = null
|
||||
@@ -331,4 +440,12 @@ export default {
|
||||
.flow-diagram :deep(svg g:hover) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.flow-toolbar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 6px 12px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user