工序计划。作业人员推送
This commit is contained in:
parent
1a454695ed
commit
4b5ee02ba3
@ -50,3 +50,11 @@ export function cascadeListOperationPlanningMain(query) {
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function updateOperationPlanningMainOperators(data) {
|
||||
return request({
|
||||
url: '/system/operationPlanningMain/updateOperators',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
<div :class="{'hidden':hidden}" class="pagination-container">
|
||||
<el-pagination
|
||||
:background="background"
|
||||
:current-page.sync="currentPage"
|
||||
:page-size.sync="pageSize"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:layout="layout"
|
||||
:page-sizes="pageSizes"
|
||||
:pager-count="pagerCount"
|
||||
@ -85,6 +85,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.pageSize = val
|
||||
if (this.currentPage * val > this.total) {
|
||||
this.currentPage = 1
|
||||
}
|
||||
@ -94,6 +95,7 @@ export default {
|
||||
}
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val
|
||||
this.$emit('pagination', { page: val, limit: this.pageSize })
|
||||
if (this.autoScroll) {
|
||||
scrollTo(0, 800)
|
||||
|
||||
@ -123,15 +123,15 @@
|
||||
<el-tag :type="typeTagType(scope.row)" size="mini" effect="plain">{{ typeText(scope.row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品主数据" min-width="220">
|
||||
<el-table-column label="产品主数据" min-width="320">
|
||||
<template slot-scope="scope">
|
||||
<div class="cell-main">
|
||||
<div class="cell-title">{{ scope.row.productCode }}<span v-if="scope.row.productName"> | {{ scope.row.productName }}</span></div>
|
||||
<div class="cell-title cell-title--wrap">{{ scope.row.productCode }}<span v-if="scope.row.productName"> | {{ scope.row.productName }}</span></div>
|
||||
<div class="cell-sub">{{ scope.row.proSpecification || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产线" min-width="180">
|
||||
<el-table-column label="产线" width="120">
|
||||
<template slot-scope="scope">
|
||||
<div class="cell-main">
|
||||
<div class="cell-title">{{ scope.row.lineText || '-' }}</div>
|
||||
@ -159,26 +159,24 @@
|
||||
<template v-if="!(scope.row.processSteps || []).length">
|
||||
<span class="cell-sub">-</span>
|
||||
</template>
|
||||
<template v-else-if="(scope.row.processSteps || []).length <= 2">
|
||||
<div class="proc-mini">
|
||||
<div v-for="(p, idx) in scope.row.processSteps" :key="idx" class="proc-mini-item" @click="openProcessDetail(scope.row, p)">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="p.percent"
|
||||
:width="30"
|
||||
:stroke-width="4"
|
||||
:color="p.done ? '#16c784' : '#dcdfe6'"
|
||||
/>
|
||||
<div class="proc-mini-name">{{ p.processName || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="proc-steps">
|
||||
<div v-for="(p, idx) in scope.row.processSteps" :key="idx" class="proc-step">
|
||||
<div class="proc-step-top">
|
||||
<span class="proc-node" :class="{ done: p.done, clickable: !!p.raw }" @click="openProcessDetail(scope.row, p)">
|
||||
<i v-if="p.done" class="el-icon-check"></i>
|
||||
<span class="proc-circle" :class="{ clickable: !!p.raw, ellipsis: !p.raw && p.processName === '…' }" @click="openProcessDetail(scope.row, p)">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="p.done ? 100 : p.percent"
|
||||
:width="32"
|
||||
:stroke-width="4"
|
||||
:show-text="false"
|
||||
:color="p.done ? '#16c784' : '#00b4ad'"
|
||||
/>
|
||||
<span class="proc-circle__text" :class="{ done: p.done }">
|
||||
<i v-if="p.done" class="el-icon-check"></i>
|
||||
<span v-else-if="p.raw">{{ Math.max(0, Math.min(99, Number(p.percent) || 0)) }}%</span>
|
||||
<span v-else>…</span>
|
||||
</span>
|
||||
</span>
|
||||
<span v-if="idx < scope.row.processSteps.length - 1" class="proc-line" :class="{ done: p.done }"></span>
|
||||
</div>
|
||||
@ -230,18 +228,46 @@
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<el-dialog :title="processDialogTitle" :visible.sync="processDialogOpen" width="1200px" top="6vh" append-to-body>
|
||||
<div v-if="processDialogMeta" class="cell-sub" style="margin-bottom: 10px;">
|
||||
{{ processDialogMeta }}
|
||||
<el-drawer
|
||||
class="process-drawer"
|
||||
:title="processDialogTitle"
|
||||
:visible.sync="processDialogOpen"
|
||||
direction="btt"
|
||||
size="70%"
|
||||
append-to-body
|
||||
>
|
||||
<template slot="title">
|
||||
<div class="process-drawer__title-line">
|
||||
<span class="process-drawer__title-main">工序详情</span>
|
||||
<span v-if="processDialogBillNo" class="process-drawer__title-kv">工序单号:{{ processDialogBillNo }}</span>
|
||||
<span v-if="processDialogBatchNo" class="process-drawer__title-kv">生产号:{{ processDialogBatchNo }}</span>
|
||||
<span v-if="processDialogProduct" class="process-drawer__title-kv process-drawer__title-product">产品:{{ processDialogProduct }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="process-drawer__toolbar">
|
||||
<div class="process-drawer__toolbar-left">
|
||||
<span v-if="processDialogDirtyCount" class="process-drawer__dirty">已修改{{ processDialogDirtyCount }}项</span>
|
||||
</div>
|
||||
<div class="process-drawer__toolbar-right">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
:loading="processDialogSaving"
|
||||
:disabled="!processDialogDirtyCount"
|
||||
@click="submitOperatorUpdates"
|
||||
>保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
ref="processTable"
|
||||
:data="processDialogList"
|
||||
size="mini"
|
||||
border
|
||||
highlight-current-row
|
||||
:row-key="p => p.entityEntryId || p.operNo"
|
||||
>
|
||||
<div class="process-drawer__table">
|
||||
<el-table
|
||||
ref="processTable"
|
||||
:data="processDialogList"
|
||||
size="mini"
|
||||
border
|
||||
highlight-current-row
|
||||
height="100%"
|
||||
:row-key="p => p.entityEntryId || p.operNo"
|
||||
>
|
||||
<el-table-column label="工序号" prop="operNo" width="80" align="center" />
|
||||
<el-table-column label="工序名称" prop="processName" min-width="140" />
|
||||
<el-table-column label="工作中心" prop="workCenter" min-width="120" />
|
||||
@ -249,20 +275,52 @@
|
||||
<el-table-column label="转入数量" prop="inQty" width="90" align="center" />
|
||||
<el-table-column label="合格数量" prop="okQty" width="90" align="center" />
|
||||
<el-table-column label="废品数量" prop="ngQty" width="90" align="center" />
|
||||
<el-table-column label="状态" prop="status" width="100" align="center" />
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" effect="plain" :class="processStatusClass(scope.row)">{{ processStatusText(scope.row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="转出数量" prop="transOutQty" width="90" align="center" />
|
||||
<el-table-column label="损耗数量" prop="wastageQty" width="90" align="center" />
|
||||
<el-table-column label="加工车间" prop="department" min-width="120" />
|
||||
<el-table-column label="作业人员" prop="operator" min-width="100" />
|
||||
<el-table-column label="计划开始" prop="seqPlanStartTime" width="160" />
|
||||
<el-table-column label="计划完成" prop="seqPlanFinishTime" width="160" />
|
||||
<el-table-column label="作业人员" min-width="220">
|
||||
<template slot-scope="scope">
|
||||
<div class="operator-cell">
|
||||
<el-input
|
||||
v-model="scope.row.__operatorDraft"
|
||||
size="mini"
|
||||
clearable
|
||||
placeholder="填写作业人员"
|
||||
@input="markOperatorDirty(scope.row)"
|
||||
/>
|
||||
<el-button
|
||||
v-if="scope.row.__operatorDirty"
|
||||
type="text"
|
||||
size="mini"
|
||||
:disabled="scope.row.__operatorSaving"
|
||||
@click="resetOperatorDraft(scope.row)"
|
||||
>取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="计划开始" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getProcessPlanStartTime(scope.row) || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="计划完成" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ getProcessPlanFinishTime(scope.row) || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="控制码" prop="optCtrlCode" min-width="120" />
|
||||
<el-table-column label="关键工序" prop="keyOper" width="90" align="center" />
|
||||
<el-table-column label="活动一" prop="activity1Name" min-width="120" />
|
||||
<el-table-column label="工序说明" prop="operDescription" min-width="140" />
|
||||
<el-table-column label="单据体内码" prop="entityEntryId" width="120" align="center" />
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 添加或修改工序计划主对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
@ -314,7 +372,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listOperationPlanningMain, cascadeListOperationPlanningMain, getOperationPlanningMain, delOperationPlanningMain, addOperationPlanningMain, updateOperationPlanningMain } from "@/api/system/operationPlanningMain";
|
||||
import { listOperationPlanningMain, cascadeListOperationPlanningMain, getOperationPlanningMain, delOperationPlanningMain, addOperationPlanningMain, updateOperationPlanningMain, updateOperationPlanningMainOperators } from "@/api/system/operationPlanningMain";
|
||||
|
||||
export default {
|
||||
name: "OperationPlanningMain",
|
||||
@ -331,6 +389,8 @@ export default {
|
||||
processDialogTitle: "工序详情",
|
||||
processDialogMeta: "",
|
||||
processDialogList: [],
|
||||
processDialogOrder: null,
|
||||
processDialogSaving: false,
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
@ -399,6 +459,23 @@ export default {
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
computed: {
|
||||
processDialogBillNo() {
|
||||
const o = this.processDialogOrder || {};
|
||||
return o.billNo || o.moNumber || '';
|
||||
},
|
||||
processDialogBatchNo() {
|
||||
const o = this.processDialogOrder || {};
|
||||
return o.batchNo || o.hbytSclh || '';
|
||||
},
|
||||
processDialogProduct() {
|
||||
const o = this.processDialogOrder || {};
|
||||
return [o.productCode, o.productName].filter(Boolean).join(' | ');
|
||||
},
|
||||
processDialogDirtyCount() {
|
||||
return (this.processDialogList || []).filter(p => p && p.__operatorDirty).length;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 查询工序计划主列表 */
|
||||
getList() {
|
||||
@ -470,8 +547,12 @@ export default {
|
||||
const processSteps = processList.map(p => {
|
||||
const planQty = this.normalizeNumber(p.planQty || overallPlanQty);
|
||||
const okQty = this.normalizeNumber(p.okQty);
|
||||
const percent = planQty > 0 ? Math.min(100, Math.round((okQty / planQty) * 100)) : 0;
|
||||
const done = this.isProcessDone(p, planQty, okQty);
|
||||
const inQty = this.normalizeNumber(p.inQty);
|
||||
const backendProgress = this.normalizePercent(p.progress);
|
||||
const baseQty = p.inQty != null ? inQty : okQty;
|
||||
const fallbackProgress = planQty > 0 ? (baseQty / planQty) * 100 : 0;
|
||||
const percent = backendProgress != null ? backendProgress : this.normalizePercent(fallbackProgress) || 0;
|
||||
const done = this.isProcessDone(p, planQty, okQty, inQty, percent);
|
||||
|
||||
return {
|
||||
operNo: p.operNo,
|
||||
@ -499,12 +580,25 @@ export default {
|
||||
lineText
|
||||
};
|
||||
},
|
||||
isProcessDone(process, planQty, okQty) {
|
||||
isProcessDone(process, planQty, okQty, inQty, percent) {
|
||||
const derived = this.calcProcessStatus(process);
|
||||
if (derived === '工序完成' || derived === '已关闭') return true;
|
||||
|
||||
const status = (process && process.status) || '';
|
||||
if (String(status).includes('完工')) return true;
|
||||
if (percent != null && Number(percent) >= 100) return true;
|
||||
if (planQty > 0 && okQty >= planQty) return true;
|
||||
if (planQty > 0 && inQty >= planQty) return true;
|
||||
return false;
|
||||
},
|
||||
normalizePercent(val) {
|
||||
if (val == null || val === '') return null;
|
||||
const n = Number(val);
|
||||
if (!Number.isFinite(n)) return null;
|
||||
if (n < 0) return 0;
|
||||
if (n > 100) return 100;
|
||||
return n;
|
||||
},
|
||||
buildLineText(processList) {
|
||||
const p0 = Array.isArray(processList) && processList.length ? processList[0] : undefined;
|
||||
if (p0 && p0.workCenter) return p0.workCenter;
|
||||
@ -538,14 +632,76 @@ export default {
|
||||
},
|
||||
statusText(row) {
|
||||
if (!row) return '-';
|
||||
if (row.overallProgress >= 100) return '完工';
|
||||
if (row.overallProgress > 0) return '已开工';
|
||||
return '备料中';
|
||||
return this.calcOrderStatus(row) || '-';
|
||||
},
|
||||
statusTagClass(row) {
|
||||
const text = this.statusText(row);
|
||||
if (text === '完工' || text === '已开工') return 'tag-purple';
|
||||
return 'tag-green';
|
||||
if (text === '未开始') return 'tag-gray';
|
||||
if (text === '进行中') return 'tag-green';
|
||||
if (text === '预警') return 'tag-orange';
|
||||
if (text === '延期') return 'tag-red';
|
||||
if (text === '已完成') return 'tag-blue';
|
||||
return 'tag-gray';
|
||||
},
|
||||
calcOrderStatus(row) {
|
||||
if (!row) return '';
|
||||
const overallProgress = Number(row.overallProgress) || 0;
|
||||
if (overallProgress >= 100) return '已完成';
|
||||
|
||||
const risk = this.calcOrderRisk(row);
|
||||
if (risk) return risk;
|
||||
|
||||
if (overallProgress > 0) return '进行中';
|
||||
return '未开始';
|
||||
},
|
||||
calcOrderRisk(row) {
|
||||
if (!row) return '';
|
||||
if (Number(row.overallProgress) >= 100) return '';
|
||||
|
||||
const warnDays = 1;
|
||||
const now = Date.now();
|
||||
const orderDue = this.toTimestamp(row.planFinishTime);
|
||||
const orderRisk = this.calcRiskByDue(orderDue, now, warnDays);
|
||||
|
||||
let processRisk = '';
|
||||
const list = Array.isArray(row.processList) ? row.processList : [];
|
||||
for (const p of list) {
|
||||
const base = this.calcProcessStatus(p);
|
||||
if (base === '工序完成' || base === '已转出' || base === '已关闭') continue;
|
||||
const due = this.toTimestamp(this.getProcessPlanFinishTime(p));
|
||||
const r = this.calcRiskByDue(due, now, warnDays);
|
||||
if (r === '延期') {
|
||||
processRisk = '延期';
|
||||
break;
|
||||
}
|
||||
if (r === '预警') processRisk = '预警';
|
||||
}
|
||||
|
||||
if (orderRisk === '延期' || processRisk === '延期') return '延期';
|
||||
if (orderRisk === '预警' || processRisk === '预警') return '预警';
|
||||
return '';
|
||||
},
|
||||
calcRiskByDue(dueTs, nowTs, warnDays) {
|
||||
if (!dueTs) return '';
|
||||
const diffDays = (dueTs - nowTs) / 86400000;
|
||||
if (diffDays < 0) return '延期';
|
||||
if (diffDays <= warnDays) return '预警';
|
||||
return '';
|
||||
},
|
||||
toTimestamp(val) {
|
||||
if (val == null || val === '') return null;
|
||||
if (typeof val === 'number' && Number.isFinite(val)) return val;
|
||||
const s = String(val);
|
||||
const ts = new Date(s.replace(/-/g, '/')).getTime();
|
||||
return Number.isFinite(ts) ? ts : null;
|
||||
},
|
||||
getProcessPlanStartTime(process) {
|
||||
if (!process) return '';
|
||||
return process.operPlanStartTime || process.fOperPlanStartTime || process.seqPlanStartTime || process.fSeqPlanStartTime || '';
|
||||
},
|
||||
getProcessPlanFinishTime(process) {
|
||||
if (!process) return '';
|
||||
return process.operPlanFinishTime || process.fOperPlanFinishTime || process.seqPlanFinishTime || process.fSeqPlanFinishTime || '';
|
||||
},
|
||||
typeText(row) {
|
||||
return (row && row.typeText) || '正常';
|
||||
@ -617,16 +773,149 @@ export default {
|
||||
|
||||
this.processDialogTitle = code ? `工序详情 - ${code}` : '工序详情';
|
||||
this.processDialogMeta = batchNo ? `生产令号:${batchNo}` : '';
|
||||
this.processDialogList = list;
|
||||
this.processDialogOrder = orderRow || null;
|
||||
this.processDialogList = this.prepareProcessDialogList(list);
|
||||
this.processDialogOpen = true;
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (!this.$refs.processTable || !step || !step.raw) return;
|
||||
const target = this.processDialogList.find(p => p.entityEntryId === step.raw.entityEntryId)
|
||||
|| this.processDialogList.find(p => p.operNo === step.operNo);
|
||||
const entryId = step.raw.entityEntryId != null ? String(step.raw.entityEntryId) : '';
|
||||
const operNo = step.operNo != null ? String(step.operNo) : '';
|
||||
const target = this.processDialogList.find(p => p.entityEntryId != null && String(p.entityEntryId) === entryId)
|
||||
|| this.processDialogList.find(p => p.operNo != null && String(p.operNo) === operNo);
|
||||
if (target) this.$refs.processTable.setCurrentRow(target);
|
||||
});
|
||||
},
|
||||
prepareProcessDialogList(list) {
|
||||
const safeList = Array.isArray(list) ? list : [];
|
||||
return safeList.map(p => {
|
||||
const operator = p && p.operator != null ? String(p.operator) : '';
|
||||
return {
|
||||
...p,
|
||||
__operatorDraft: operator,
|
||||
__operatorDirty: false,
|
||||
__operatorSaving: false
|
||||
};
|
||||
});
|
||||
},
|
||||
processStatusText(process) {
|
||||
return this.calcProcessDisplayStatus(process) || '-';
|
||||
},
|
||||
processStatusClass(process) {
|
||||
const text = this.calcProcessDisplayStatus(process);
|
||||
if (text === '未开工') return 'tag-gray';
|
||||
if (text === '生产中') return 'tag-green';
|
||||
if (text === '质检中') return 'tag-blue';
|
||||
if (text === '预警') return 'tag-orange';
|
||||
if (text === '延期') return 'tag-red';
|
||||
if (text === '工序完成' || text === '已转出') return 'tag-blue';
|
||||
if (text === '已关闭') return 'tag-gray';
|
||||
return 'tag-gray';
|
||||
},
|
||||
calcProcessDisplayStatus(process) {
|
||||
const base = this.calcProcessStatus(process);
|
||||
if (base === '工序完成' || base === '已转出' || base === '已关闭') return base;
|
||||
|
||||
const warnDays = 1;
|
||||
const now = Date.now();
|
||||
const due = this.toTimestamp(this.getProcessPlanFinishTime(process));
|
||||
const risk = this.calcRiskByDue(due, now, warnDays);
|
||||
if (risk) return risk;
|
||||
|
||||
if (base === '未开工' || base === '生产中' || base === '质检中') return base;
|
||||
return base || '';
|
||||
},
|
||||
calcProcessStatus(process) {
|
||||
if (!process) return '';
|
||||
|
||||
const rawK3 = process.k3Status ?? process.operStatus ?? process.k3OperStatus;
|
||||
const k3 = rawK3 == null || rawK3 === '' ? 0 : Number(rawK3);
|
||||
if (k3 === 5 || k3 === 6) return '已关闭';
|
||||
|
||||
const inQty = this.normalizeNumber(process.inQty);
|
||||
const okQty = this.normalizeNumber(process.okQty);
|
||||
const ngQty = this.normalizeNumber(process.ngQty);
|
||||
const transOutQty = this.normalizeNumber(process.transOutQty);
|
||||
|
||||
if (inQty === 0) return '未开工';
|
||||
if (transOutQty > 0) return '已转出';
|
||||
if (okQty + ngQty >= inQty) return '工序完成';
|
||||
if (okQty + ngQty > 0) return '质检中';
|
||||
return '生产中';
|
||||
},
|
||||
markOperatorDirty(row) {
|
||||
if (!row) return;
|
||||
const origin = row.operator != null ? String(row.operator) : '';
|
||||
const draft = row.__operatorDraft != null ? String(row.__operatorDraft) : '';
|
||||
row.__operatorDirty = origin !== draft;
|
||||
},
|
||||
resetOperatorDraft(row) {
|
||||
if (!row) return;
|
||||
row.__operatorDraft = row.operator != null ? String(row.operator) : '';
|
||||
row.__operatorDirty = false;
|
||||
},
|
||||
buildOperatorUpdatePayload(rows) {
|
||||
const order = this.processDialogOrder || {};
|
||||
const list = Array.isArray(rows) ? rows : [];
|
||||
|
||||
return {
|
||||
orderId: order.id ?? null,
|
||||
fid: order.fid ?? null,
|
||||
billNo: order.billNo ?? null,
|
||||
moNumber: order.moNumber ?? null,
|
||||
batchNo: (order.batchNo || order.hbytSclh) ?? null,
|
||||
updates: list.map(p => ({
|
||||
k3DetailId: p.k3DetailId ?? null,
|
||||
entityEntryId: p.entityEntryId ?? null,
|
||||
operNo: p.operNo ?? null,
|
||||
processName: p.processName ?? null,
|
||||
operator: p.__operatorDraft != null ? String(p.__operatorDraft).trim() : ''
|
||||
}))
|
||||
};
|
||||
},
|
||||
submitOperatorUpdates(targetRows) {
|
||||
if (this.processDialogSaving) return;
|
||||
const rows = Array.isArray(targetRows)
|
||||
? targetRows
|
||||
: (this.processDialogList || []).filter(p => p && p.__operatorDirty);
|
||||
|
||||
const realRows = rows.filter(r => {
|
||||
const origin = r && r.operator != null ? String(r.operator) : '';
|
||||
const draft = r && r.__operatorDraft != null ? String(r.__operatorDraft).trim() : '';
|
||||
return origin !== draft;
|
||||
});
|
||||
|
||||
if (!realRows.length) return;
|
||||
|
||||
this.processDialogSaving = true;
|
||||
realRows.forEach(r => {
|
||||
r.__operatorSaving = true;
|
||||
});
|
||||
|
||||
const payload = this.buildOperatorUpdatePayload(realRows);
|
||||
updateOperationPlanningMainOperators(payload)
|
||||
.then(() => {
|
||||
realRows.forEach(r => {
|
||||
const next = r.__operatorDraft != null ? String(r.__operatorDraft).trim() : '';
|
||||
r.operator = next;
|
||||
r.__operatorDraft = next;
|
||||
r.__operatorDirty = false;
|
||||
});
|
||||
this.$modal.msgSuccess('保存成功');
|
||||
})
|
||||
.finally(() => {
|
||||
realRows.forEach(r => {
|
||||
r.__operatorSaving = false;
|
||||
});
|
||||
this.processDialogSaving = false;
|
||||
});
|
||||
},
|
||||
saveOperator(row) {
|
||||
if (!row || row.__operatorSaving) return;
|
||||
this.markOperatorDirty(row);
|
||||
if (!row.__operatorDirty) return;
|
||||
this.$modal.msgWarning('已暂存,点击上方“保存”统一提交');
|
||||
},
|
||||
formatProcessText(row) {
|
||||
const list = (row && Array.isArray(row.processList) ? row.processList : []).map(p => {
|
||||
const operNo = p.operNo != null ? String(p.operNo) : '-';
|
||||
@ -742,6 +1031,30 @@ export default {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tag-gray {
|
||||
background: #909399;
|
||||
border-color: #909399;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tag-orange {
|
||||
background: #f59e0b;
|
||||
border-color: #f59e0b;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tag-red {
|
||||
background: #ef4444;
|
||||
border-color: #ef4444;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tag-blue {
|
||||
background: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cell-main {
|
||||
line-height: 18px;
|
||||
}
|
||||
@ -754,6 +1067,14 @@ export default {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cell-title--wrap {
|
||||
white-space: normal;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.cell-sub {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
@ -768,36 +1089,6 @@ export default {
|
||||
min-height: 46px;
|
||||
}
|
||||
|
||||
.proc-mini {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.proc-mini-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 56px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::v-deep .proc-mini .el-progress-circle__text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.proc-mini-name {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 56px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.proc-steps {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@ -814,33 +1105,46 @@ export default {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.proc-node {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #dcdfe6;
|
||||
|
||||
.proc-circle {
|
||||
position: relative;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.proc-node.done {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-color: #16c784;
|
||||
color: #16c784;
|
||||
}
|
||||
|
||||
.proc-node.clickable {
|
||||
.proc-circle.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.proc-node.done i {
|
||||
.proc-circle__text {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #00b4ad;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.proc-circle__text.done {
|
||||
color: #16c784;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.proc-circle.ellipsis .proc-circle__text {
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.proc-line {
|
||||
width: 26px;
|
||||
height: 2px;
|
||||
@ -883,4 +1187,62 @@ export default {
|
||||
.is-row-checked td {
|
||||
background: #e8faf8 !important;
|
||||
}
|
||||
|
||||
.process-drawer ::v-deep .el-drawer__body {
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.process-drawer__toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.process-drawer__title-main {
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.process-drawer__title-line {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 14px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.process-drawer__title-kv {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.process-drawer__title-product {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.process-drawer__dirty {
|
||||
color: #606266;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.process-drawer__table {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.operator-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user