refactor: 重构产线工位与备料流程,移除冗余字段
1. 移除工单、工件、日排产中的冗余工位组合/接驳台字段 2. 新增工位接驳台编码字段与唯一约束,关联WMS接驳台主数据 3. 重构日排产为工位产量分配模式,替代原接驳台列表 4. 新增备料单工位级字段与分批出库支持 5. 移除定时同步可生产数量,改为WMS实时拉取接口 6. 过滤操作日志,排除登录/退出相关日志 7. 调整仪表盘工序展示逻辑为今日派工路线 8. 新增接驳台维护菜单与基础数据
This commit is contained in:
@@ -77,6 +77,12 @@ export const occupyLinePoint = (data) => request.post('/api/line/occupy', data)
|
||||
// 工位叫料:{stationNo, dock, orderNo, items:[{materialCode, materialName, unit, manageMode, qty}]}
|
||||
export const callLineMaterial = (data) => request.post('/api/line/call-material', data)
|
||||
|
||||
// 待接料列表(本工位):{stationNo, status, orderNo, planDate} → MES 备料单(待接料行)
|
||||
export const getMaterialRequests = (params) => request.get('/api/material-requests', { params })
|
||||
|
||||
// 接料确认(主入口:扫码接料):{requestNo, qty?} → MES 累加 sentQty
|
||||
export const receiveMaterialRequest = (data) => request.post('/api/material-request/receive', data)
|
||||
|
||||
// ---------- 工位终端巡检 / 应急 / 数量不符 / 退料(代理 MES 内部 API) ----------
|
||||
// 巡检提交:{category(CHECKIN/POINT/PROCESS/DONE/ALARM), stationNo, orderNo, sn, shift, result, items, photo, remark, processCode, stepId, stepName, measuredValue}
|
||||
export const submitInspection = (data) => request.post('/api/inspection/submit', data)
|
||||
|
||||
@@ -93,13 +93,59 @@
|
||||
<el-button type="primary" size="large" class="big-btn" :loading="calling" @click="doCall">提交叫料</el-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ③ 待接料(扫码接料主入口;班组长补录见 MES 备料页) -->
|
||||
<section class="card">
|
||||
<div class="card-title">待接料(本工位)</div>
|
||||
<div class="call-row">
|
||||
<span class="lab">扫备料单号</span>
|
||||
<el-input
|
||||
v-model.trim="scanVal"
|
||||
size="large"
|
||||
class="dock-el"
|
||||
placeholder="扫描备料单号接料"
|
||||
clearable
|
||||
@keyup.enter="doScanReceive"
|
||||
/>
|
||||
<el-button size="large" :loading="receiving" @click="doScanReceive">接料确认</el-button>
|
||||
<el-button size="large" @click="loadPending">刷新</el-button>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<el-table-column label="接驳台" prop="targetDock" width="110" align="center" />
|
||||
<el-table-column label="需求" width="100" align="center">
|
||||
<template #default="{ row }">{{ fmtQty(row.reqQty) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已接" width="100" align="center">
|
||||
<template #default="{ row }">{{ fmtQty(row.sentQty) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="批次" prop="batchNo" width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="110" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="success"
|
||||
size="large"
|
||||
:loading="receiving && receivingNo === row.requestNo"
|
||||
:disabled="row.status === 'DONE'"
|
||||
@click="doReceive(row)"
|
||||
>{{ row.status === 'DONE' ? '已完结' : '已接料' }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-if="!pendingLoading && !pending.length" description="本工位暂无待接料" :image-size="60" />
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { bindRecord, bindRemove, callLineMaterial } from '../../api'
|
||||
import { bindRecord, bindRemove, callLineMaterial, getMaterialRequests, receiveMaterialRequest } from '../../api'
|
||||
import {
|
||||
bindInputs,
|
||||
loadBind,
|
||||
@@ -118,6 +164,62 @@ const calling = ref(false)
|
||||
const dock = ref('')
|
||||
const items = ref([])
|
||||
|
||||
// ③ 待接料
|
||||
const scanVal = ref('')
|
||||
const pending = ref([])
|
||||
const pendingLoading = ref(false)
|
||||
const receiving = ref(false)
|
||||
const receivingNo = ref('')
|
||||
|
||||
function fmtQty(v) {
|
||||
const n = Number(v || 0)
|
||||
return Number.isInteger(n) ? String(n) : n.toFixed(2)
|
||||
}
|
||||
|
||||
async function loadPending() {
|
||||
pendingLoading.value = true
|
||||
try {
|
||||
const res = await getMaterialRequests({ stationNo: stationNo.value, status: 'PENDING' })
|
||||
const list = res?.data?.data || res?.data || []
|
||||
// 仅展示未完结行(DONE 已送达)
|
||||
pending.value = (Array.isArray(list) ? list : []).filter((r) => r.status !== 'DONE')
|
||||
} catch (e) {
|
||||
pending.value = []
|
||||
}
|
||||
pendingLoading.value = false
|
||||
}
|
||||
|
||||
async function doScanReceive() {
|
||||
const no = scanVal.value.trim()
|
||||
if (!no) {
|
||||
ElMessage.warning('请扫描备料单号')
|
||||
return
|
||||
}
|
||||
await doReceive({ requestNo: no })
|
||||
scanVal.value = ''
|
||||
}
|
||||
|
||||
async function doReceive(row) {
|
||||
if (!row?.requestNo) {
|
||||
ElMessage.warning('缺少备料单号')
|
||||
return
|
||||
}
|
||||
receiving.value = true
|
||||
receivingNo.value = row.requestNo
|
||||
try {
|
||||
await receiveMaterialRequest({ requestNo: row.requestNo, operator: operatorName() })
|
||||
ElMessage.success('接料确认成功:' + row.requestNo)
|
||||
loadPending()
|
||||
} catch (e) {
|
||||
/* 统一错误提示 */
|
||||
}
|
||||
receiving.value = false
|
||||
receivingNo.value = ''
|
||||
}
|
||||
|
||||
onMounted(loadPending)
|
||||
|
||||
|
||||
function addRow() {
|
||||
items.value.push({ materialCode: '', materialName: '', unit: '个', manageMode: '1', qty: 1 })
|
||||
}
|
||||
|
||||
@@ -155,3 +155,47 @@ func lineCallMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
mesJSON(w, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
// materialRequestsHandler GET /api/material-requests 代理 MES /api/internal/material-requests
|
||||
// 工位终端按当前登录工位过滤「待接料」行(stationNo 由前端带入)。
|
||||
func materialRequestsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
q := url.Values{}
|
||||
for _, k := range []string{"stationNo", "status", "orderNo", "planDate", "materialCode", "targetDock"} {
|
||||
if v := strings.TrimSpace(r.URL.Query().Get(k)); v != "" {
|
||||
q.Set(k, v)
|
||||
}
|
||||
}
|
||||
body, _, err := ctx.Mes.Get("/api/internal/material-requests", q)
|
||||
mesJSON(w, body, err)
|
||||
}
|
||||
}
|
||||
|
||||
// materialReceiveHandler POST /api/material-request/receive 代理 MES /api/internal/station/receive-material
|
||||
// 主入口:工人扫码接料(扫描备料单号确认)。operator 由本服务补当前登录人。
|
||||
func materialReceiveHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fail(w, http.StatusBadRequest, "请求体读取失败")
|
||||
return
|
||||
}
|
||||
var req map[string]any
|
||||
if err := json.Unmarshal(payload, &req); err != nil {
|
||||
fail(w, http.StatusBadRequest, "请求体解析失败")
|
||||
return
|
||||
}
|
||||
if req["requestNo"] == nil || req["requestNo"] == "" {
|
||||
fail(w, http.StatusBadRequest, "缺少备料单号")
|
||||
return
|
||||
}
|
||||
if req["operator"] == nil || req["operator"] == "" {
|
||||
if u := currentUsername(r); u != "" {
|
||||
req["operator"] = u
|
||||
}
|
||||
}
|
||||
body, _ := json.Marshal(req)
|
||||
resp, _, err := ctx.Mes.Post("/api/internal/station/receive-material", json.RawMessage(body))
|
||||
mesJSON(w, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ func RegisterHandlers(server *rest.Server, ctx *svc.ServiceContext) {
|
||||
{Method: http.MethodPost, Path: "/api/line/move/ack", Handler: lineAckHandler(ctx)},
|
||||
{Method: http.MethodPost, Path: "/api/line/occupy", Handler: lineOccupyHandler(ctx)},
|
||||
{Method: http.MethodPost, Path: "/api/line/call-material", Handler: lineCallMaterialHandler(ctx)},
|
||||
{Method: http.MethodGet, Path: "/api/material-requests", Handler: materialRequestsHandler(ctx)},
|
||||
{Method: http.MethodPost, Path: "/api/material-request/receive", Handler: materialReceiveHandler(ctx)},
|
||||
|
||||
// 巡检 / 应急呼叫 / 数量不符 / 退料(代理 MES 内部 API)
|
||||
{Method: http.MethodPost, Path: "/api/inspection/submit", Handler: inspectionSubmitHandler(ctx)},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>工位终端</title>
|
||||
<!-- 系统图标:工位终端屏(内联 SVG,避免依赖外部文件) -->
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%231668dc'/><rect x='6' y='7' width='20' height='14' rx='2' fill='none' stroke='%23fff' stroke-width='2'/><path d='M12 25h8M16 21v4' stroke='%23fff' stroke-width='2' stroke-linecap='round'/></svg>">
|
||||
<script type="module" crossorigin src="/assets/index-CETtbp9K.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CREZyc19.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Dz4RGjfJ.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.login-page[data-v-f09d9792]{height:100vh;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#0f2b4c,#14385f 60%,#1a4a7a)}.login-card[data-v-f09d9792]{width:480px;padding:48px 56px;background:#fff;border-radius:16px;box-shadow:0 12px 48px #00000059}.title[data-v-f09d9792]{margin:0 0 8px;font-size:34px;text-align:center;color:#16324f}.subtitle[data-v-f09d9792]{margin:0 0 32px;text-align:center;font-size:16px;color:#7a8aa0}.field[data-v-f09d9792]{display:flex;align-items:center;gap:16px;margin-bottom:22px}.lab[data-v-f09d9792]{width:64px;font-size:20px;font-weight:700;color:#16324f;text-align:right}.field[data-v-f09d9792] .el-input__inner{height:52px;font-size:20px}.station-el[data-v-f09d9792]{flex:1}.station-el[data-v-f09d9792] .el-input__inner{height:52px;font-size:20px;font-weight:700;color:#16324f}.station-fixed[data-v-f09d9792]{flex:1;font-size:22px;font-weight:700;color:#16324f;line-height:52px;background:#f2f6fb;border-radius:8px;padding:0 16px}.btn-login[data-v-f09d9792]{width:calc(100% - 80px);margin-left:80px;height:54px;font-size:24px;letter-spacing:12px}.hint[data-v-f09d9792]{margin-top:26px;text-align:center;font-size:14px;color:#9aa7b8}
|
||||
@@ -0,0 +1 @@
|
||||
import{o as _,c as w,a as e,b as d,w as m,t as y,d as b,r as n,e as v,u as V,f as x,g as N,E as p,s as k}from"./index-CETtbp9K.js";import{_ as C,g as E,l as M}from"./_plugin-vue_export-helper-CbexiMW6.js";const z={class:"login-page"},B={class:"login-card"},K={class:"field"},S={class:"field"},L={class:"field"},T={class:"station-fixed"},U={__name:"Login",setup(A){const f=V(),o=n(""),l=n(""),t=n(0),i=n(!1);_(async()=>{try{const a=await E();(a==null?void 0:a.stationNo)>0&&(t.value=a.stationNo)}catch{}});async function u(){if(!o.value||!l.value){p.warning("请输入账号和密码");return}if(!t.value){p.warning("工位配置未加载,请检查服务端配置文件后重启");return}i.value=!0;try{const a=await M({username:o.value,password:l.value,stationNo:t.value});k(a.accessToken,a.user),p.success("登录成功"),f.push("/main")}catch{}finally{i.value=!1}}return(a,s)=>{const c=v("el-input"),g=v("el-button");return x(),w("div",z,[e("div",B,[s[6]||(s[6]=e("h1",{class:"title"},"工位终端",-1)),s[7]||(s[7]=e("p",{class:"subtitle"},"产线触屏终端(端口 8892)",-1)),e("div",K,[s[2]||(s[2]=e("span",{class:"lab"},"账号",-1)),d(c,{modelValue:o.value,"onUpdate:modelValue":s[0]||(s[0]=r=>o.value=r),modelModifiers:{trim:!0},size:"large",placeholder:"请输入账号",clearable:"",onKeyup:m(u,["enter"])},null,8,["modelValue"])]),e("div",S,[s[3]||(s[3]=e("span",{class:"lab"},"密码",-1)),d(c,{modelValue:l.value,"onUpdate:modelValue":s[1]||(s[1]=r=>l.value=r),size:"large",type:"password","show-password":"",placeholder:"请输入密码",onKeyup:m(u,["enter"])},null,8,["modelValue"])]),e("div",L,[s[4]||(s[4]=e("span",{class:"lab"},"工位",-1)),e("span",T,y(t.value?"工位 "+t.value:"工位加载中…"),1)]),d(g,{class:"btn-login",type:"primary",size:"large",loading:i.value,onClick:u},{default:b(()=>[...s[5]||(s[5]=[N(" 登 录 ",-1)])]),_:1},8,["loading"]),s[8]||(s[8]=e("p",{class:"hint"},"账号由 MES 统一管理",-1))])])}}},R=C(U,[["__scopeId","data-v-f09d9792"]]);export{R as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
import{z as s}from"./index-CETtbp9K.js";const p=t=>s.post("/api/auth/login",t),c=()=>s.get("/api/config"),r=t=>s.get("/api/task/current",{params:{stationNo:t}}),l=t=>s.get("/api/bind/panel",{params:t}),g=t=>s.post("/api/bind/record",t),m=t=>s.post("/api/bind/remove",t),u=t=>s.get("/api/workload",{params:t}),d=t=>s.get("/api/tightening/list",{params:t}),v=t=>s.post("/api/tightening/record",t),f=t=>s.post("/api/report/process-done",t),y=t=>s.post("/api/report/temp-store",t),b=()=>s.post("/api/sync/flush"),h=t=>s.post("/api/station/logout",t),k=()=>s.get("/api/sync/stats"),L=t=>"/pdfview?name="+encodeURIComponent(t),q=t=>{if(!t)return"";const e=String(t),o=e.indexOf("/api/v1/files/");return o>=0?e.slice(o+14):e},w=()=>s.get("/api/line/points"),M=t=>s.get("/api/line/moves",{params:t}),C=t=>s.post("/api/line/move",t),P=t=>s.post("/api/line/move/arrive",t),R=t=>s.post("/api/line/move/ack",t),T=t=>s.post("/api/line/occupy",t),_=t=>s.post("/api/line/call-material",t),x=t=>s.post("/api/inspection/submit",t),F=t=>s.post("/api/inspection/upload",t),O=t=>s.post("/api/emergency/call",t),S=t=>s.post("/api/qty-report",t),B=t=>s.post("/api/return-material",t),I=t=>s.get("/api/wip",{params:t}),U=t=>s.get("/api/bom",{params:t}),z=t=>s.get("/api/order/query",{params:t}),D=t=>s.get("/api/trace",{params:t}),W=t=>s.post("/api/workpiece/online",t),j=t=>s.post("/api/workpiece/done",t),A=(t,e)=>{const o=t.__vccOpts||t;for(const[n,i]of e)o[n]=i;return o};export{z as A,U as B,W as C,D,j as E,u as F,b as G,h as H,A as _,M as a,r as b,d as c,k as d,w as e,I as f,c as g,l as h,C as i,P as j,y as k,p as l,q as m,m as n,T as o,L as p,g as q,f as r,v as s,_ as t,R as u,F as v,x as w,O as x,S as y,B as z};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>工位终端</title>
|
||||
<!-- 系统图标:工位终端屏(内联 SVG,避免依赖外部文件) -->
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%231668dc'/><rect x='6' y='7' width='20' height='14' rx='2' fill='none' stroke='%23fff' stroke-width='2'/><path d='M12 25h8M16 21v4' stroke='%23fff' stroke-width='2' stroke-linecap='round'/></svg>">
|
||||
<script type="module" crossorigin src="/assets/index-CETtbp9K.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Dz4RGjfJ.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user