refactor: 重构工艺工序相关命名与数据模型

1.  全局替换"工序"为"工艺"统一术语,包括页面文案、枚举、注释
2.  重构工单与工件工艺数据模型:
    - 新增工艺组合表flow_material作为备料/齐套唯一源头
    - 新增工位状态表station_state支持自主停单/恢复接单
    - 移除station_process派工表,改用工单工艺组合作为路线唯一源头
    - 替换processCode为flowId作为工艺关联标识
    - 重构工件当前进度字段为currentStationNo
3.  删除冗余的静态备份资源文件
4.  调整物料选择组件默认启用仅显示激活物料
5.  优化工单创建/编辑逻辑,新增工艺组合校验与保存
This commit is contained in:
SunYF
2026-09-22 11:32:29 +08:00
parent 932700ca65
commit d609ff8a9e
185 changed files with 8623 additions and 4501 deletions
+13 -6
View File
@@ -10,13 +10,13 @@ export const getConfig = () => request.get('/api/config')
export const getTaskCurrent = (stationNo) =>
request.get('/api/task/current', { params: { stationNo } })
// 装机绑定面板(代理 MES):sn+processCode → 应绑/已绑清单
// 装机绑定面板(代理 MES):sn+flowId → 应绑/已绑清单
export const getBindPanel = (params) => request.get('/api/bind/panel', { params })
// 装机绑定一条(代理 MES):{sn, processCode, stationNo, items:[{materialCode, bindValue}]}
// 装机绑定一条(代理 MES):{sn, flowId, stationNo, items:[{materialCode, bindValue}]}
export const bindRecord = (data) => request.post('/api/bind/record', data)
// 撤销一条绑定(代理 MES):{sn, processCode, materialCode, bindValue}
// 撤销一条绑定(代理 MES):{sn, flowId, materialCode, bindValue}
export const bindRemove = (data) => request.post('/api/bind/remove', data)
// 我的工作量(代理 MES,按当前登录人查询)
@@ -29,7 +29,7 @@ export const getTighteningList = (params) => request.get('/api/tightening/list',
// {sn, workOrderNo, stepId, stepName, screwNo, torque, angle, result, operator}
export const submitTorque = (data) => request.post('/api/tightening/record', data)
// 工完成上报
// 工完成上报
export const reportProcessDone = (data) => request.post('/api/report/process-done', data)
// 暂存退库上报
@@ -109,11 +109,18 @@ export const getBom = (params) => request.get('/api/bom', { params })
// 工单查询(选工单带出产品编码/名称):{orderNo}
export const queryOrder = (params) => request.get('/api/order/query', { params })
// 工件追溯(下线完工扫SN展示状态/工时间线/拧紧):{sn}
// 工件追溯(下线完工扫SN展示状态/工时间线/拧紧):{sn}
export const getTrace = (params) => request.get('/api/trace', { params })
// 上线建档:{sn, orderNo, workOrderId, processSeq, operator}
export const onlineRegister = (data) => request.post('/api/workpiece/online', data)
// 下线完工入库:{sn, batchItems, serialItems, operator}
export const offlineFinish = (data) => request.post('/api/workpiece/done', data)
export const offlineFinish = (data) => request.post('/api/workpiece/done', data)
// ---------- 工位停单 / 恢复接单(代理 MES 内部 API ----------
// 停单/恢复:{stationNo, paused, reason}paused=true 停止接单,false 恢复)
export const pauseStation = (data) => request.post('/api/station/pause', data)
// 当天停单状态:?date=yyyy-MM-dd(缺省当天)→ [{stationNo,paused,reason,operator}]
export const getStationState = (params) => request.get('/api/station/state', { params })
+19 -19
View File
@@ -5,14 +5,14 @@
export const helpWorkstation = {
title: '工位终端 使用说明',
overview:
'工位终端运行在 DOCK01~21 各工工位的触屏设备上,是产线最一线的执行入口。\n\n标准流程:①确认本工位号 → ②扫描工件 SN → ③照工艺图纸用拧紧枪打螺丝 → ④看拧紧结果是否全部 OK → ⑤点「工序完成上报」→ 工件流转到下一工。\n\n数据链路:下发任务(MES) → 扫码(MES工位任务) → 拧紧结果(丹尼科尔拧紧枪采集,本地SQLite缓存) → 工完成上报(MES) → 拧紧/追溯数据回到 MES 管理后台。',
'工位终端运行在 DOCK01~21 各工工位的触屏设备上,是产线最一线的执行入口。\n\n标准流程:①确认本工位号 → ②扫描工件 SN → ③照工艺图纸用拧紧枪打螺丝 → ④看拧紧结果是否全部 OK → ⑤点「报工完成」→ 工件流转到下一工。\n\n数据链路:下发任务(MES) → 扫码(MES工位任务) → 拧紧结果(丹尼科尔拧紧枪采集,本地SQLite缓存) → 工完成上报(MES) → 拧紧/追溯数据回到 MES 管理后台。',
sections: [
{
title: '顶部与工位',
overview: '顶部显示当前工位号、登录人、离线同步状态。',
fields: [
{ name: '工位号', source: '下拉选择/固定。数据来自本机配置或固定的 DOCK01~21。', purpose: '当前所在工位,决定读取哪道工的任务', fill: '固定工位由配置锁定不可改;否则选与实际工位一致编号' },
{ name: '待同步 N 条', source: '系统统计。数据来自本地 SQLite 中尚未上传的记录数。', purpose: '标记有拧紧/工数据没上报 MES(离线缓存)', fill: '点「重试同步」立即补传;消红为正常' },
{ name: '工位号', source: '下拉选择/固定。数据来自本机配置或固定的 DOCK01~21。', purpose: '当前所在工位,决定读取哪道工的任务', fill: '固定工位由配置锁定不可改;否则选与实际工位一致编号' },
{ name: '待同步 N 条', source: '系统统计。数据来自本地 SQLite 中尚未上传的记录数。', purpose: '标记有拧紧/工数据没上报 MES(离线缓存)', fill: '点「重试同步」立即补传;消红为正常' },
{ name: '登录人', source: '登录账号。来自工位终端登录时输入。', purpose: '当前操作员,上报记录会带此名字溯源', fill: '开机登入本人账号,勿共用' }
]
},
@@ -25,13 +25,13 @@ export const helpWorkstation = {
]
},
{
title: '当前工单与工',
overview: '左栏显示本工位当前装配任务的工单号、产品型号、整件进度和工序清单。',
title: '当前工单与工',
overview: '左栏显示本工位当前装配任务的工单号、产品型号、整件进度和工艺步骤。',
fields: [
{ name: '工单号', source: 'MES 派发。数据来自 MES 下发给本工位的当前任务。', purpose: '正在装配的生产工单,工序/工艺都按它来', fill: '不可改,随任务自动带出' },
{ name: '工序清单', source: 'MES 工艺配置。数据来自工单的工序组合(MES下发)。', purpose: '12 道工序任务,✔=已完成,高亮=当前应做工序', fill: '照高亮工序执行,不用手工勾选' },
{ name: '工艺图纸', source: 'MES 下发 PDF。工单配置的工艺文件。', purpose: '当前工序的工艺图/拧紧点位,指导怎么打螺丝', fill: '点「放大查看」全屏看图,照图示点位顺序拧' },
{ name: '查看本步骤图纸', source: 'MES 工艺配置。每道工步骤绑定的图纸附件(MES 下发)。', purpose: '按当前步骤精准调出对应图纸,避免看错工序的图', fill: '在对应步骤上点「查看本步骤图纸」弹窗查看,照图施工' }
{ name: '工单号', source: 'MES 派发。数据来自 MES 下发给本工位的当前任务。', purpose: '正在装配的生产工单,工艺路线都按它来', fill: '不可改,随任务自动带出' },
{ name: '工艺步骤', source: 'MES 工艺配置。数据来自工位绑定工艺+工单工艺组合(MES下发)。', purpose: '工艺步骤任务,✔=已完成,高亮=当前应做步骤', fill: '照高亮步骤执行,不用手工勾选' },
{ name: '工艺图纸', source: 'MES 下发 PDF。工单配置的工艺文件。', purpose: '当前工艺的图纸/拧紧点位,指导怎么打螺丝', fill: '点「放大查看」全屏看图,照图示点位顺序拧' },
{ name: '查看本步骤图纸', source: 'MES 工艺配置。每道工步骤绑定的图纸附件(MES 下发)。', purpose: '按当前步骤精准调出对应图纸,避免看错步骤的图', fill: '在对应步骤上点「查看本步骤图纸」弹窗查看,照图施工' }
]
},
{
@@ -39,7 +39,7 @@ export const helpWorkstation = {
overview: '作业页 SN 卡片下方列出当前工位正在加工/等待的工件,点击可快速切换继续填报。',
fields: [
{ name: '在制品列表', source: 'MES 实时查询。数据来自 MES「在制工件」接口按本工位号过滤。', purpose: '看清本工位还有哪些工件在做/待做,防止漏件', fill: '点列表中某一行即把该 SN 带入扫码框,继续未完成步骤的填报' },
{ name: '进度 N/M', source: 'MES 统计。已完成步骤数 / 该工总步骤数。', purpose: '一眼看出每件在制品做到第几步', fill: '只读展示,随填报自动更新' }
{ name: '进度 N/M', source: 'MES 统计。已完成步骤数 / 该工总步骤数。', purpose: '一眼看出每件在制品做到第几步', fill: '只读展示,随填报自动更新' }
]
},
{
@@ -54,25 +54,25 @@ export const helpWorkstation = {
{
title: '底部三大按钮',
fields: [
{ name: '工序完成上报', source: '按钮操作 + 确认框。数据上报到 MES。', purpose: '本工位这道工做完,通知 MES 流转到下一工', fill: '点后输入当前工序号(如 OP10)确认;联网失败自动离线缓存' },
{ name: '暂存退库', source: '按钮操作 + 确认框。数据上报到 MES(记录已完成工)。', purpose: '工件本工不做完,退回库房暂存', fill: '点击并二次确认;系统记录已完成工,重上线从下一工继续' },
{ name: '报工完成', source: '按钮操作 + 确认框。数据上报到 MES。', purpose: '本工位这道工做完,通知 MES 流转到下一工', fill: '点「报工完成」二次确认;联网失败自动离线缓存' },
{ name: '暂存退库', source: '按钮操作 + 确认框。数据上报到 MES(记录已完成工)。', purpose: '工件本工不做完,退回库房暂存', fill: '点击并二次确认;系统记录已完成工,重上线从下一工继续' },
{ name: '重试同步', source: '按钮操作。数据从本地 SQLite 补传到 MES。', purpose: '把离线缓存的数据立即补传给 MES', fill: '看到「待同步」非 0 时点一下即可' }
]
}
]
}
// 工艺文件页(按工步骤展示图纸,5.1
// 工艺文件页(按工步骤展示图纸,5.1
export const helpPdf = {
title: '工艺文件 使用说明',
overview:
'工艺文件页把本工的每一道步骤对应的图纸附件按顺序列出,左侧步骤列表、右侧图纸预览。\n\n当前应做步骤会自动高亮并定位到对应图纸,也支持整流程工艺 PDF 兜底查看。',
'工艺文件页把本工的每一道步骤对应的图纸附件按顺序列出,左侧步骤列表、右侧图纸预览。\n\n当前应做步骤会自动高亮并定位到对应图纸,也支持整流程工艺 PDF 兜底查看。',
sections: [
{
title: '步骤图纸',
overview: '每道工步骤绑定的图纸附件由 MES 工艺配置下发。',
overview: '每道工步骤绑定的图纸附件由 MES 工艺配置下发。',
fields: [
{ name: '步骤列表', source: 'MES 工艺配置。工步骤 + 每步骤绑定的图纸附件。', purpose: '按工序顺序逐步骤查看对应图纸,照图施工', fill: '点左侧任一步骤即在右侧预览该步骤图纸;当前步骤自动高亮' },
{ name: '步骤列表', source: 'MES 工艺配置。工步骤 + 每步骤绑定的图纸附件。', purpose: '按步骤顺序逐步骤查看对应图纸,照图施工', fill: '点左侧任一步骤即在右侧预览该步骤图纸;当前步骤自动高亮' },
{ name: '图纸预览', source: 'MES 文件服务。工位终端代理拉取并本地缓存。', purpose: '查看当前步骤的装配图/拧紧点位图', fill: '右侧自动加载,无需操作;网络异常时稍候自动重试' },
{ name: '整流程 PDF', source: 'MES 下发。工单配置的整份工艺文件。', purpose: '当步骤无单独图纸时,兜底查看整份工艺 PDF', fill: '无步骤图纸时自动展示整流程 PDF' }
]
@@ -106,7 +106,7 @@ export const helpOnline = {
title: '工件 SN 与建档提交',
overview: 'SN 是成品唯一编号,进线登记即系统发号,全程可追溯。',
fields: [
{ name: '工件 SN', source: '扫码枪扫描 / 系统自动生成。', purpose: '唯一识别本台成品,拧紧/工/追溯都挂在此 SN 下', fill: '用扫码枪扫条码,或点「自动生成」由系统发号' },
{ name: '工件 SN', source: '扫码枪扫描 / 系统自动生成。', purpose: '唯一识别本台成品,拧紧/工/追溯都挂在此 SN 下', fill: '用扫码枪扫条码,或点「自动生成」由系统发号' },
{ name: '上线位在制品', source: 'MES 实时查询。工位号 0 的在制工件。', purpose: '看清已建档待流转的工件,防止重复建档', fill: '只读展示,点「刷新」更新' },
{ name: '确认建档上线', source: '按钮操作 + 确认框。数据上报到 MES。', purpose: '正式建档上线,工件进入产线待第 1 工位加工', fill: '满足工单/SN/领料核对后点击并二次确认;MES 不可达时自动离线缓存重传' }
]
@@ -118,14 +118,14 @@ export const helpOnline = {
export const helpOffline = {
title: '下线完工 使用说明',
overview:
'下线完工运行在产线出料口(工位号 13)。工件走完全部装配工后在此核对完工状态、终检结果,确认合格后入库并回流 WMS 成品库存。\n\n标准流程:①扫描工件 SN → ②查看完工状态/工时间线/拧紧结果/步骤不合格项 → ③确认合格后点「确认完工入库(回流 WMS)」。\n\n数据链路:追溯/拧紧/工(MES) → 完工确认(MES 置 DONE) → 成品库存回流(WMS)。',
'下线完工运行在产线出料口(工位号 13)。工件走完全部装配工后在此核对完工状态、终检结果,确认合格后入库并回流 WMS 成品库存。\n\n标准流程:①扫描工件 SN → ②查看完工状态/工时间线/拧紧结果/步骤不合格项 → ③确认合格后点「确认完工入库(回流 WMS)」。\n\n数据链路:追溯/拧紧/工(MES) → 完工确认(MES 置 DONE) → 成品库存回流(WMS)。',
sections: [
{
title: '完工状态核对',
overview: '扫描 SN 后汇总展示该工件的全流程完工情况,作为入库判定依据。',
fields: [
{ name: '工件状态', source: 'MES 查询。工件当前流转状态。', purpose: '确认工件是否已完工,避免重复入库', fill: '只读;显示「已完工」则无需再操作' },
{ name: '已完成工', source: 'MES 工时间线。', purpose: '核对是否走完全部应做工', fill: '只读;工数应与工艺路线一致' },
{ name: '已完成工', source: 'MES 工时间线。', purpose: '核对是否走完全部应做工', fill: '只读;工数应与工艺路线一致' },
{ name: '拧紧 N/M 合格', source: 'MES 拧紧记录汇总。', purpose: '确认全部螺丝拧紧合格', fill: '只读;有不合格需先返修复检再入库' },
{ name: '步骤不合格 N 项', source: 'MES 步骤采集数据。', purpose: '提示过程检中是否存在不合格步骤', fill: '只读;大于 0 时须确认已处理再入库' }
]
@@ -1,18 +1,20 @@
// 工位终端全局状态(模块级单例)
// 终端一个工位一个进程:工位号由服务端配置固定,前端不可修改。
// 状态集中在这里,作业/物料/移料/工艺各面板共享,避免多份轮询与状态不一致。
import { computed, reactive } from 'vue'
import { computed, reactive, watch } from 'vue'
import {
getBindPanel,
getConfig,
getLineMoves,
getLinePoints,
getStationState,
getSyncStats,
getTaskCurrent,
getTighteningList,
getWip,
issueLineMove,
occupyLinePoint,
pauseStation,
submitTorque
} from '../api'
import { getUser } from '../utils/request'
@@ -32,6 +34,8 @@ export const state = reactive({
stepChecks: {},
bindInputs: {},
startedAt: '',
paused: false,
pauseReason: '',
lastError: ''
})
@@ -54,6 +58,9 @@ export const tightRows = computed(() => state.tightRows)
export const wip = computed(() => state.wip)
// 进工位(上料)时刻——作业时长起点(P0-3),报工时随载荷上传 MES
export const startedAt = computed(() => state.startedAt)
// 停单状态(当天):工人可停止/恢复接单,停单期间阻止新的报工提交
export const paused = computed(() => state.paused)
export const pauseReason = computed(() => state.pauseReason)
// 当前步骤(5.1 工艺文件高亮):第一个尚未录入的手填步骤;全部录入后回退到首个步骤
export const currentStep = computed(() => {
@@ -85,6 +92,8 @@ export const missingTorqueSteps = computed(
export const orderNos = computed(() => (Array.isArray(state.task?.orderNos) ? state.task.orderNos : []))
export const flowName = computed(() => state.task?.flow?.name || '-')
export const flowActive = computed(() => !!state.task?.flowActive)
// 本工位绑定的工艺 IDstation.flowId,随任务下发):装机绑定/报工一律按 flowId 查询与上报
export const flowId = computed(() => Number(state.task?.flowId || 0))
// 本工位的产线点位台账(唯一事实源:本工位当前是否有工件)
export const myPoint = computed(() =>
@@ -133,7 +142,7 @@ export const missingSteps = computed(() =>
return v === null || v === undefined || v === ''
})
)
// 绑定是否齐套(本工未配置需绑物料时不拦截)
// 绑定是否齐套(本工未配置需绑物料时不拦截)
export const bindBlocking = computed(
() => !!(state.bindPanel && state.bindPanel.enabled && !state.bindPanel.complete)
)
@@ -141,6 +150,8 @@ export const canReport = computed(
() =>
!!state.currentSn &&
!!state.orderNo &&
flowId.value > 0 &&
!state.paused &&
!bindBlocking.value &&
missingSteps.value.length === 0 &&
missingChecks.value.length === 0 &&
@@ -259,13 +270,13 @@ export async function submitTorqueStep(step, torque, angle) {
}
export async function loadBind() {
const code = Number(state.stationNo)
if (!state.currentSn || !code) {
const fid = flowId.value
if (!state.currentSn || !fid) {
state.bindPanel = null
return
}
try {
const p = await getBindPanel({ sn: state.currentSn, processCode: code })
const p = await getBindPanel({ sn: state.currentSn, flowId: fid })
state.bindPanel = p
;(p?.required || []).forEach((r) => {
if (state.bindInputs[r.materialCode] === undefined) state.bindInputs[r.materialCode] = ''
@@ -294,7 +305,35 @@ export async function loadWip(atStation) {
}
export function refreshAll() {
return Promise.all([loadTask(), loadTight(), loadStats(), loadPoints(), loadWip()])
return Promise.all([loadTask(), loadTight(), loadStats(), loadPoints(), loadWip(), loadStationState()])
}
// loadStationState 拉取本工位当天的停单状态(MES /api/internal/station/state),刷新横幅与按钮。
// 拉取失败保持现状,避免网络抖动误清停单横幅。
export async function loadStationState() {
if (!state.stationNo) return
try {
const list = await getStationState()
const rows = Array.isArray(list) ? list : (list?.list || [])
const mine = rows.find((s) => Number(s.stationNo) === Number(state.stationNo))
if (mine) {
state.paused = !!mine.paused
state.pauseReason = mine.reason || ''
}
} catch { /* 静默 */ }
}
// setPaused 停止接单/恢复接单:调 MES /api/internal/station/pause,成功后同步本地状态。
// 恢复不要求原因(物料是否齐套由工人自行判断,系统不拦截恢复)。
export async function setPaused(next, reason) {
await pauseStation({
stationNo: Number(state.stationNo),
paused: !!next,
reason: next ? (reason || '') : '',
operator: operatorName()
})
state.paused = !!next
state.pauseReason = next ? (reason || '') : ''
}
// 切换工件:清空步骤录入与绑定缓存,重新加载拧紧/绑定
@@ -347,6 +386,11 @@ export async function moveOut(sn, toPoint) {
export const operatorName = () => user.name || user.username || ''
// flowId 随任务到达后再触发一次绑定加载(上线位/首次拉到任务时 flowId 才有值)
watch(flowId, (v) => {
if (v > 0 && state.currentSn && !state.bindPanel) loadBind()
})
// markStationArrival 记录「进工位 / 上料到本工位」时刻(作业时长起点,P0-3)。
// 仅在尚未记录时写入,同一工件重复扫码/确认不会重置起点。
export function markStationArrival() {
@@ -27,6 +27,13 @@
<el-button size="large" type="danger" plain @click="logout">退出</el-button>
</header>
<!-- 停单横幅醒目置顶已停止接单 + 原因恢复接单即关闭 -->
<transition name="fade">
<div v-if="paused" class="pause-banner">
已停止接单{{ pauseReason ? '' + pauseReason : '' }}本工位暂停新的报工提交作业信息不受影响
</div>
</transition>
<!-- 不合格告警横幅 -->
<transition name="fade">
<div v-if="hasNg" class="alert-banner"> 存在不合格请复检</div>
@@ -40,7 +47,7 @@
<OfflinePanel />
</el-tab-pane>
<el-tab-pane v-if="!isVirtual" label="作业" name="work">
<WorkPanel ref="workRef" />
<WorkPanel ref="workRef" @call-material="tab = 'material'" />
</el-tab-pane>
<el-tab-pane label="物料 / 叫料" name="material">
<MaterialPanel />
@@ -93,10 +100,13 @@ import {
loadMoves,
loadPoints,
loadStats,
loadStationState,
loadTight,
loadTask,
loadWip,
orderNo,
paused,
pauseReason,
pendingTotal,
refreshAll,
sn,
@@ -172,6 +182,7 @@ onMounted(async () => {
loadPoints() // 点位台账 10 秒
loadMoves()
loadWip() // 在制品 10 秒
loadStationState() // 停单状态 10 秒
}, 10000)
})
@@ -233,6 +244,15 @@ onBeforeUnmount(() => {
font-size: 18px;
font-weight: 700;
}
.pause-banner {
background: #f56c6c;
color: #fff;
text-align: center;
padding: 12px;
font-size: 20px;
font-weight: 700;
letter-spacing: 1px;
}
.main-tabs {
margin: 12px;
min-height: calc(100vh - 140px);
@@ -114,8 +114,8 @@
<el-table :data="pending" border size="large" class="call-table" v-loading="pendingLoading">
<el-table-column label="图号" prop="materialCode" min-width="130" />
<el-table-column label="物料名称" prop="materialName" min-width="150" show-overflow-tooltip />
<el-table-column label="工" width="80" align="center">
<template #default="{ row }">{{ row.processCode || '-' }}</template>
<el-table-column label="工" width="80" align="center">
<template #default="{ row }">{{ row.flowId || row.processCode || '-' }}</template>
</el-table-column>
<el-table-column label="接驳台" prop="targetDock" width="110" align="center" />
<el-table-column label="需求" width="100" align="center">
@@ -148,6 +148,7 @@ import { ElMessage } from 'element-plus'
import { bindRecord, bindRemove, callLineMaterial, getMaterialRequests, receiveMaterialRequest } from '../../api'
import {
bindInputs,
flowId,
loadBind,
myDocks,
operatorName,
@@ -257,7 +258,7 @@ async function doBind(r) {
await bindRecord({
sn: sn.value,
orderNo: orderNo.value || '',
processCode: Number(stationNo.value),
flowId: flowId.value,
stationNo: stationNo.value,
items: [{ materialCode: r.materialCode, bindValue: v }]
})
@@ -272,7 +273,7 @@ async function removeBind(r, b) {
try {
await bindRemove({
sn: sn.value,
processCode: Number(stationNo.value),
flowId: flowId.value,
materialCode: r.materialCode,
bindValue: b
})
@@ -29,7 +29,7 @@
<b>{{ workpiece.orderNo || '-' }}</b>
</div>
<div class="stat">
<span class="k">已完成工</span>
<span class="k">已完成工</span>
<b>{{ doneProcessCount }} </b>
</div>
<div class="stat">
@@ -53,10 +53,10 @@
title="存在不合格项,请确认已完成返修/复检后再入库。" style="margin:10px 0"
/>
<div class="sub-title">时间线</div>
<div class="sub-title">时间线</div>
<el-table :data="processTimeline" border size="large" max-height="260">
<el-table-column label="工" min-width="120">
<template #default="{ row }">{{ row.processName || ('工' + row.processCode) }}</template>
<el-table-column label="工" min-width="120">
<template #default="{ row }">{{ row.processName || ('工' + (row.flowId || row.processCode || '')) }}</template>
</el-table-column>
<el-table-column label="结果" width="100" align="center">
<template #default="{ row }">
@@ -2,7 +2,7 @@
<div class="pdf-panel">
<section class="card">
<div class="card-title">
工艺文件按工步骤
工艺文件按工步骤
<el-tag v-if="flowName && flowName !== '-'" type="success" size="large" effect="dark">{{ flowName }}</el-tag>
<span class="tip">点击左侧步骤查看本步骤图纸当前步骤高亮</span>
</div>
@@ -1,5 +1,21 @@
<template>
<div class="work-panel">
<!-- 头部操作区停止接单/恢复接单停单仅阻止新报工不隐藏作业信息 + 叫料 -->
<header class="ops-bar">
<span class="ops-lab">接单状态</span>
<el-tag :type="paused ? 'danger' : 'success'" effect="dark" size="large">
{{ paused ? '已停止接单' : '接单中' }}
</el-tag>
<el-button
size="large"
:type="paused ? 'success' : 'danger'"
:loading="pauseBusy"
@click="onTogglePause"
>{{ paused ? '恢复接单' : '停止接单' }}</el-button>
<el-button size="large" type="primary" plain @click="emit('call-material')">叫料</el-button>
<span v-if="paused && state.pauseReason" class="ops-reason">原因{{ state.pauseReason }}</span>
</header>
<!-- 工件区扫码上料 / 取料 -->
<section class="card sn-card">
<div class="card-title">当前工件</div>
@@ -196,6 +212,7 @@ import {
canReport,
criterionOk,
flowActive,
flowId,
flowName,
hasNg,
loadBind,
@@ -215,7 +232,9 @@ import {
operatorName,
orderNos,
orderNo,
paused,
setCurrentSn,
setPaused,
sn,
startedAt,
state,
@@ -232,9 +251,56 @@ import {
wip
} from '../../store/station'
const emit = defineEmits(['call-material'])
const scanRef = ref()
const scanInput = ref('')
const taking = ref(false)
const pauseBusy = ref(false)
// 停止接单/恢复接单:停单时可填原因(可空),恢复不需要原因
async function onTogglePause() {
if (!paused.value) {
let reason = ''
try {
const { value } = await ElMessageBox.prompt(
'停止接单后本工位暂停新的报工提交,可随时恢复;作业信息不受影响。',
'停止接单',
{
confirmButtonText: '停止接单',
cancelButtonText: '取消',
inputPlaceholder: '停止原因(可空)',
type: 'warning'
}
)
reason = (value || '').trim()
} catch {
return
}
pauseBusy.value = true
try {
await setPaused(true, reason)
ElMessage.warning('已停止接单' + (reason ? '' + reason : ''))
} catch { /* 统一错误提示 */ }
pauseBusy.value = false
} else {
try {
await ElMessageBox.confirm('确认恢复本工位接单?', '恢复接单', {
confirmButtonText: '恢复接单',
cancelButtonText: '取消',
type: 'success'
})
} catch {
return
}
pauseBusy.value = true
try {
await setPaused(false, '')
ElMessage.success('已恢复接单')
} catch { /* 统一错误提示 */ }
pauseBusy.value = false
}
}
const myPointLabel = computed(() => (myPoint.value ? myPoint.value.label || myPoint.value.pointNo : '工位' + stationNo.value))
@@ -246,8 +312,10 @@ const stepSummaryText = computed(() => {
const stepSummaryType = computed(() => (missingSteps.value.length ? 'warning' : 'success'))
const blockTip = computed(() => {
if (paused.value) return '已停止接单' + (state.pauseReason ? '' + state.pauseReason : '') + ',恢复接单后才能报工'
if (!sn.value) return '请先扫描工件 SN'
if (!orderNo.value) return '请选择工单号'
if (!flowId.value) return '本工位未绑定工艺流程,无法报工'
if (bindBlocking.value) return '装配物料未绑齐:' + (state.bindPanel?.missing || '缺料')
if (missingSteps.value.length) return '还有步骤未录入:' + (missingSteps.value[0].name || '未命名步骤')
if (missingChecks.value.length) return '还有步骤未做检测确认:' + (missingChecks.value[0].name || '未命名步骤')
@@ -459,7 +527,7 @@ async function onProcessDone() {
const data = await reportProcessDone({
sn: sn.value,
orderNo: orderNo.value,
processCode: Number(stationNo.value),
flowId: flowId.value,
stationNo: stationNo.value,
steps: buildStepsPayload(),
operator: operatorName(),
@@ -494,7 +562,7 @@ async function onTempStore() {
sn: sn.value,
orderNo: orderNo.value || '',
stationNo: stationNo.value,
processCode: Number(stationNo.value),
flowId: flowId.value,
operator: operatorName()
})
ElMessage.success(data?.queued ? 'MES 暂不可达,已离线缓存' : '暂存退库已上报')
@@ -560,6 +628,28 @@ defineExpose({ focusScan })
padding: 14px 16px;
box-shadow: 0 1px 6px rgba(0, 21, 41, 0.08);
}
.ops-bar {
grid-column: 1 / -1;
display: flex;
align-items: center;
gap: 12px;
background: #fff;
border-radius: 10px;
padding: 10px 16px;
box-shadow: 0 1px 6px rgba(0, 21, 41, 0.08);
}
.ops-bar .ops-lab {
color: #909399;
font-size: 15px;
}
.ops-bar .ops-reason {
color: #f56c6c;
font-size: 15px;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-title {
font-size: 18px;
font-weight: 600;
@@ -28,7 +28,7 @@
<el-table :data="rows" border size="large" height="420">
<el-table-column prop="date" label="日期" width="130" />
<el-table-column prop="stationNo" label="工位" width="90" />
<el-table-column prop="processName" label="工" min-width="160" />
<el-table-column prop="processName" label="工" min-width="160" />
<el-table-column prop="operator" label="操作人" width="120" />
<el-table-column prop="doneCount" label="完成" width="90" />
<el-table-column prop="okCount" label="合格" width="90" />