feat(wpm): improve bx handover details

This commit is contained in:
caoqianming 2026-08-07 17:53:07 +08:00
parent b7580a0fd6
commit ddff19e7ec
5 changed files with 238 additions and 175 deletions

View File

@ -45,12 +45,12 @@
/* ============================================================ /* ============================================================
* 工作流表单结构化样式 * 工作流表单结构化样式
* 抽屉内打开的所有 *_form.vue 流程表单统一布局规范 * 仅对显式声明 workflow-form-drawer 的流程抽屉生效避免影响普通业务抽屉
* - 主区: el-main > el-form 内容卡片化分组分区 * - 主区: el-main > el-form 内容卡片化分组分区
* - 底部: 操作按钮 sticky 底栏 * - 底部: 操作按钮 sticky 底栏
* - 侧栏: 提升与正文的视觉区分 * - 侧栏: 提升与正文的视觉区分
* ============================================================ */ * ============================================================ */
.el-drawer__body { .workflow-form-drawer .el-drawer__body {
.el-container { .el-container {
height: 100%; height: 100%;
background: var(--el-fill-color-light); background: var(--el-fill-color-light);

View File

@ -64,7 +64,7 @@
{{ item.name }} {{ item.name }}
</el-card> </el-card>
</el-dialog> </el-dialog>
<el-drawer v-model="drawer" size="90%" :show-close="false"> <el-drawer v-model="drawer" size="90%" :show-close="false" class="workflow-form-drawer">
<template #header="{ close, titleId, titleClass }"> <template #header="{ close, titleId, titleClass }">
<h4 :id="titleId" :class="titleClass">{{drawerName}}</h4> <h4 :id="titleId" :class="titleClass">{{drawerName}}</h4>
<el-button type="danger" @click="close">关闭</el-button> <el-button type="danger" @click="close">关闭</el-button>

View File

@ -132,7 +132,7 @@
</el-table-column> </el-table-column>
</scTable> </scTable>
</el-main> </el-main>
<el-drawer v-model="drawer" size="90%" :show-close="false"> <el-drawer v-model="drawer" size="90%" :show-close="false" class="workflow-form-drawer">
<template #header="{ close, titleId, titleClass }"> <template #header="{ close, titleId, titleClass }">
<h4 :id="titleId" :class="titleClass">{{drawerName}}</h4> <h4 :id="titleId" :class="titleClass">{{drawerName}}</h4>
<el-button type="danger" @click="close">关闭</el-button> <el-button type="danger" @click="close">关闭</el-button>

View File

@ -68,30 +68,32 @@
width="50" width="50"
></el-table-column> ></el-table-column>
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="props"> <template #default="props">
<div style="padding-left: 50px"> <div class="handover-detail">
<div v-if="props.row.new_batch&&props.row.new_batch!= null" style="font-size: 14px;"> <div v-if="props.row.new_batch" class="handover-detail__batch">
新批次号{{ props.row.new_batch }}<span v-if="props.row.material_changed!==null">({{ props.row.material_changed_fname }})</span> 新批次号{{ props.row.new_batch }}
</div> <span v-if="props.row.material_changed_fname">{{ props.row.material_changed_fname }}</span>
<template v-for="item in props.row.handoverb" :key="item.id">
<el-descriptions :column="3" style="margin-top: 10px;">
<el-descriptions-item label="批次">
{{item.batch}}
</el-descriptions-item>
<el-descriptions-item label="数量">
{{item.count}}
</el-descriptions-item>
<el-descriptions-item label="不合格标记" v-if="item.defect_name!==null">
{{item.defect_name}}
</el-descriptions-item>
</el-descriptions>
<div v-if="item.handoverbw&&item.handoverbw.length>0" style="margin-top: -10px;">
板段号:<span v-for="bwItem in item.handoverbw" :key="bwItem.id">{{ bwItem.number }}</span>
</div>
</template>
</div> </div>
</template> <div class="handover-detail__row handover-detail__header">
</el-table-column> <span>批次</span>
<span>数量</span>
<span>不合格标记</span>
<span>板段号</span>
</div>
<div v-for="item in props.row.handoverb" :key="item.id" class="handover-detail__row">
<span>{{ item.batch || '-' }}</span>
<span>{{ item.count }}</span>
<span>{{ item.defect_name || item.notok_sign_name || '-' }}</span>
<span class="handover-detail__numbers">
<template v-if="item.handoverbw && item.handoverbw.length">
{{ item.handoverbw.map(bw => bw.number).filter(Boolean).join('、') || '-' }}
</template>
<template v-else>-</template>
</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column <el-table-column
label="物料" label="物料"
prop="material_name" prop="material_name"
@ -365,19 +367,19 @@ export default {
}); });
}, },
// //
table_edit(row) { async table_edit(row) {
this.type=row.type; this.type=row.type;
this.dialog.save = true; this.dialog.save = true;
this.$nextTick(() => { await this.$nextTick();
this.$refs.saveDialog.open("edit").setData(row); this.$refs.saveDialog.open("edit", "", row.mtype);
}); await this.$refs.saveDialog.loadData(row.id);
}, },
table_show(row){ async table_show(row){
this.type=row.type; this.type=row.type;
this.dialog.save = true; this.dialog.save = true;
this.$nextTick(() => { await this.$nextTick();
this.$refs.saveDialog.open("show").setData(row); this.$refs.saveDialog.open("show", "", row.mtype);
}); await this.$refs.saveDialog.loadData(row.id);
}, },
// //
async table_del(row) { async table_del(row) {
@ -508,4 +510,32 @@ export default {
border: 1px solid #dcdfe6; border: 1px solid #dcdfe6;
margin-bottom: 10px; margin-bottom: 10px;
} }
.handover-detail {
padding: 8px 24px 8px 50px;
font-size: 13px;
color: var(--el-text-color-regular);
}
.handover-detail__batch {
margin-bottom: 6px;
line-height: 24px;
color: var(--el-text-color-primary);
}
.handover-detail__row {
display: grid;
grid-template-columns: minmax(180px, 1.5fr) 90px minmax(130px, 1fr) minmax(260px, 2fr);
align-items: center;
min-height: 30px;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.handover-detail__row > span {
padding: 4px 12px;
}
.handover-detail__header {
font-weight: 600;
background: var(--el-fill-color-light);
}
.handover-detail__numbers {
line-height: 20px;
word-break: break-all;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<el-dialog <el-dialog
:title="titleMap[mode+type]" :title="dialogTitle"
v-model="visible" v-model="visible"
width="1000px" width="1000px"
:size="1000" :size="1000"
@ -12,7 +12,68 @@
:model="form" :model="form"
:rules="rules" :rules="rules"
label-width="80px" label-width="80px"
v-loading="loading"
> >
<template v-if="mode === 'show'">
<div class="form-section-title">基本信息</div>
<el-descriptions :column="3" border class="handover-summary">
<el-descriptions-item label="交接类别">{{ form.type_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="操作类型">{{ form.mtype_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="交送日期">{{ form.send_date || '-' }}</el-descriptions-item>
<el-descriptions-item label="物料">{{ form.material_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="交接数量">{{ totalCount }}</el-descriptions-item>
<el-descriptions-item label="记录状态">
<el-tag :type="form.submit_time ? 'success' : 'info'" size="small">
{{ form.submit_time ? '已提交' : '未提交' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="交送部门">{{ form.send_dept_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="交送工段">{{ form.send_mgroup_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="交送人">{{ form.send_user_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="接收部门">{{ form.recive_dept_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="接收工段">{{ form.recive_mgroup_name || '-' }}</el-descriptions-item>
<el-descriptions-item label="接收人">{{ form.recive_user_name || '-' }}</el-descriptions-item>
<el-descriptions-item v-if="form.new_batch" label="新批次号">{{ form.new_batch }}</el-descriptions-item>
<el-descriptions-item v-if="form.material_changed_fname" label="变更后物料">{{ form.material_changed_fname }}</el-descriptions-item>
<el-descriptions-item v-if="form.material_changed && form.state_changed_name" label="变更后状态">{{ form.state_changed_name }}</el-descriptions-item>
<el-descriptions-item v-if="form.clear_defect" label="清除批次缺陷"></el-descriptions-item>
<el-descriptions-item v-if="form.submit_time" label="提交时间">{{ form.submit_time }}</el-descriptions-item>
<el-descriptions-item v-if="form.submit_user_name" label="提交人">{{ form.submit_user_name }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="3">{{ form.note || '-' }}</el-descriptions-item>
</el-descriptions>
<div class="form-section-title">交接明细</div>
<el-table :data="form.handoverb" border stripe size="small">
<el-table-column v-if="hasProductDetails" type="expand" width="42">
<template #default="scope">
<div v-if="scope.row.handoverbw && scope.row.handoverbw.length" class="product-detail-list">
<span class="product-detail-label">板段号</span>
<el-tag v-for="item in scope.row.handoverbw" :key="item.id || item.number" size="small" effect="plain">
{{ item.number }}<template v-if="item.note">{{ item.note }}</template>
</el-tag>
</div>
<el-empty v-else description="无板段号" :image-size="48" />
</template>
</el-table-column>
<el-table-column label="批次" prop="batch" min-width="150" />
<el-table-column label="物料" prop="material_name" min-width="180">
<template #default="scope">{{ scope.row.material_name || form.material_name || '-' }}</template>
</el-table-column>
<el-table-column label="状态" prop="state_name" width="90" />
<el-table-column label="缺陷等级" prop="defect_grade_name" width="100" />
<el-table-column label="具体缺陷" prop="defect_name" min-width="120">
<template #default="scope">{{ scope.row.defect_name || '-' }}</template>
</el-table-column>
<el-table-column label="不合格标记" prop="notok_sign_name" width="110">
<template #default="scope">{{ scope.row.notok_sign_name || '-' }}</template>
</el-table-column>
<el-table-column label="来源位置" min-width="130">
<template #default="scope">{{ scope.row.mgroup_name || scope.row.belong_dept_name || '全局库存' }}</template>
</el-table-column>
<el-table-column label="交接数量" prop="count" width="100" align="right" />
</el-table>
</template>
<template v-else>
<el-row> <el-row>
<el-form-item label="交接物料"> <el-form-item label="交接物料">
<el-button type="primary" @click="addMaterial" v-if="mode!=='show'">手动添加</el-button> <el-button type="primary" @click="addMaterial" v-if="mode!=='show'">手动添加</el-button>
@ -144,20 +205,17 @@
</el-col> </el-col>
<el-col :md="12" :sm="24"> <el-col :md="12" :sm="24">
<el-form-item label="交送人"> <el-form-item label="交送人">
<el-select <xtSelect
:apiObj="$API.system.user.list"
:params="sendUserParams"
v-model="form.send_user" v-model="form.send_user"
v-model:label="form.send_user_name"
placeholder="交送人" placeholder="交送人"
clearable
filterable
style="width: 100%" style="width: 100%"
> >
<el-option <el-table-column label="姓名" prop="name" />
v-for="item in userList" <el-table-column label="部门" prop="belong_dept_name" />
:key="item.id" </xtSelect>
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :md="12" :sm="24"> <el-col :md="12" :sm="24">
@ -169,7 +227,7 @@
filterable filterable
style="width: 100%" style="width: 100%"
:disabled="type==40||mode!=='add'" :disabled="type==40||mode!=='add'"
@change="getUserList2" @change="reciveMgroupChange"
> >
<el-option <el-option
v-for="item in mgroupOptions" v-for="item in mgroupOptions"
@ -182,20 +240,18 @@
</el-col> </el-col>
<el-col :md="12" :sm="24"> <el-col :md="12" :sm="24">
<el-form-item label="接收人"> <el-form-item label="接收人">
<el-select <xtSelect
:apiObj="$API.system.user.list"
:params="reciveUserParams"
v-model="form.recive_user" v-model="form.recive_user"
v-model:label="form.recive_user_name"
:edit="Boolean(form.recive_dept) || type == 40"
placeholder="接收人" placeholder="接收人"
clearable
filterable
style="width: 100%" style="width: 100%"
> >
<el-option <el-table-column label="姓名" prop="name" />
v-for="item in userList2" <el-table-column label="部门" prop="belong_dept_name" />
:key="item.id" </xtSelect>
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :md="12" :sm="24" v-if="(mtype==30||type==50)&&new_wm==''"> <el-col :md="12" :sm="24" v-if="(mtype==30||type==50)&&new_wm==''">
@ -237,10 +293,11 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</template>
</el-form> </el-form>
<el-footer v-if="mode!=='show'"> <el-footer>
<el-button type="primary" v-loading="isSaveing" @click="submit">确定</el-button> <el-button v-if="mode!=='show'" type="primary" v-loading="isSaveing" @click="submit">确定</el-button>
<el-button @click="visible = false">取消</el-button> <el-button @click="visible = false">{{ mode === 'show' ? '关闭' : '取消' }}</el-button>
</el-footer> </el-footer>
</el-dialog> </el-dialog>
</template> </template>
@ -386,8 +443,6 @@ export default {
deptID:'', deptID:'',
bwIndex:0, bwIndex:0,
checkedStatus:[], checkedStatus:[],
userList: [],
userList2: [],
deptOptions:[], deptOptions:[],
mgroupOptions: [], mgroupOptions: [],
materialOptions: [], materialOptions: [],
@ -417,6 +472,10 @@ export default {
that.materialObj = materialObj; that.materialObj = materialObj;
that.form.handle_date =that.form.send_date =this.$TOOL.dateFormat2(new Date()); that.form.handle_date =that.form.send_date =this.$TOOL.dateFormat2(new Date());
that.form.send_mgroup = that.mgroupId; that.form.send_mgroup = that.mgroupId;
that.deptID = that.$TOOL.data.get('gx_deptID');
const userInfo = that.$TOOL.data.get("USER_INFO") || {};
that.form.send_user = userInfo.id || null;
that.form.send_user_name = userInfo.name || "";
if(that.new_wm!==''){ if(that.new_wm!==''){
that.mtype==30; that.mtype==30;
that.form.new_wm = that.new_wm; that.form.new_wm = that.new_wm;
@ -440,31 +499,23 @@ export default {
that.form.new_batch = 'HP'+that.Mmodel+year+month+day; that.form.new_batch = 'HP'+that.Mmodel+year+month+day;
} }
}) })
// type=10
// type=20
// type=30
// type=40
// type=50
///
if(that.type==20&&that.mgroupName=='废品库'){//
that.getCkUserList();
}else{
that.deptID = that.$TOOL.data.get('gx_deptID');
that.getUserList();
}
//
if(that.type==10){//
that.getMaterial();
}else if(that.type==20){//
that.getMaterialOkFangong();
}else if(that.type==40){//
that.getMaterialNotok();
}else if(that.type==50){//
that.getMaterialFP();
}
that.getMgroupOptions();
}, },
computed: { computed: {
dialogTitle() {
return this.mode === "show" ? "查看交接记录" : (this.titleMap[this.mode + this.type] || "交接记录");
},
sendUserParams() {
return this.type == 20 && this.mgroupName === "废品库"
? { posts__code: "inm&check" }
: { depts: this.deptID };
},
reciveUserParams() {
if (this.type == 40) return { posts__code: "inm&check" };
return this.form.recive_dept ? { depts: this.form.recive_dept } : {};
},
hasProductDetails() {
return (this.form.handoverb || []).some(item => item.handoverbw && item.handoverbw.length);
},
// handoverb // handoverb
totalCount() { totalCount() {
if (!this.form.handoverb || this.form.handoverb.length === 0) return 0; if (!this.form.handoverb || this.form.handoverb.length === 0) return 0;
@ -494,6 +545,24 @@ export default {
} }
}, },
methods: { methods: {
prepareEditor() {
if (this.type == 10) {
this.getMaterial();
} else if (this.type == 20) {
this.getMaterialOkFangong();
} else if (this.type == 40) {
this.getMaterialNotok();
} else if (this.type == 50) {
this.getMaterialFP();
}
this.getMgroupOptions();
},
reciveMgroupChange(id) {
const group = this.mgroupOptions.find(item => String(item.id) === String(id));
this.form.recive_dept = group ? group.belong_dept : null;
this.form.recive_user = null;
this.form.recive_user_name = "";
},
deletebw(index){ deletebw(index){
let that = this; let that = this;
that.checkedStatus.splice(index,1); that.checkedStatus.splice(index,1);
@ -531,11 +600,9 @@ export default {
res.forEach(item=>{ res.forEach(item=>{
if(item.name=="废品库"){ if(item.name=="废品库"){
that.form.recive_mgroup = item.id; that.form.recive_mgroup = item.id;
that.form.recive_dept = item.belong_dept;
} }
}) })
that.getCkUserList();//
}else if(that.type==30){
this.getUserList3();
} }
}); });
}, },
@ -605,70 +672,6 @@ export default {
}) })
}); });
}, },
//
getUserList() {
let that = this;
let userInfo = that.$TOOL.data.get("USER_INFO");
this.$API.system.user.list.req({ depts: that.deptID, page: 0 }).then((res) => {
that.userList = res;
let arr = res.filter(item=>{
return item.id==userInfo.id;
})
if(arr.length>0){
if(that.mode=="add"){
that.form.send_user = userInfo.id;
}
}else{
let obj = {};
obj.id = userInfo.id;
obj.name = userInfo.name;
that.userList.push(obj)
if(that.mode=="add"){
that.form.send_user = userInfo.id;
}
}
});
},
//
getCkUserList() {
let that = this;
this.$API.system.user.list.req({ page: 0, posts__code: "inm&check" })
.then((res) => {
if(that.type==40){
that.userList2 = [];
that.userList2 = res;
}else if(that.type==20&&that.mgroupName=='废品库'){
that.userList = [];
that.userList = res;
}
});
},
//
getUserList2() {
let that = this;
if(that.mode=="add"){
that.$API.mtm.mgroup.item.req(that.form.recive_mgroup).then((res) => {
this.$API.system.user.list.req({ depts: res.belong_dept, page: 0 }).then((res) => {
that.userList2 = res;
});
})
}else{
this.mgroupOptions.forEach(item => {
if(item.id==that.form.recive_mgroup){
this.$API.system.user.list.req({ depts: item.belong_dept, page: 0 }).then((res) => {
that.userList2 = res;
});
}
});
}
},
//
getUserList3() {
let that = this;
this.$API.system.user.list.req({ depts: that.form.recive_dept, page: 0 }).then((res) => {
that.userList2 = res;
});
},
addMaterial(){ addMaterial(){
let that = this; let that = this;
that.addShow = true; that.addShow = true;
@ -703,6 +706,9 @@ export default {
that.change_batch = true; that.change_batch = true;
} }
that.form.handoverb = data?data:[]; that.form.handoverb = data?data:[];
if (mode !== "show") {
that.prepareEditor();
}
if(data&&data!==''&&data.length>0){ if(data&&data!==''&&data.length>0){
data.forEach((item,index)=>{ data.forEach((item,index)=>{
item.wm = item.id; item.wm = item.id;
@ -759,7 +765,7 @@ export default {
that.mgroupOptions = res; that.mgroupOptions = res;
if(res.length==1){ if(res.length==1){
that.form.recive_mgroup = res[0].id; that.form.recive_mgroup = res[0].id;
that.getUserList2(); that.reciveMgroupChange(res[0].id);
} }
}) })
} }
@ -884,28 +890,33 @@ export default {
}, },
// //
setData(data) { setData(data) {
let that = this; Object.assign(this.form, data, { handoverb: data.handoverb || [] });
Object.assign(this.form, data); this.mtype = Number(data.mtype ?? this.mtype ?? 10);
this.$API.system.user.list.req({ depts: data.send_dept, page: 0 }).then((res) => { this.change_batch = Boolean(data.new_batch) || this.mtype === 30;
that.userList = res; this.checkedStatus = this.form.handoverb.map(item =>
(item.handoverbw || []).every(detail => detail.checked !== false)
);
this.form.handoverb.forEach(item => {
item.count_canhandover = item.count_available ?? item.count_canhandover ?? item.count;
}); });
this.$API.system.user.list.req({ depts: data.recive_dept, page: 0 }).then((res) => { if (data.recive_mgroup && !this.mgroupOptions.some(item => String(item.id) === String(data.recive_mgroup))) {
that.userList2 = res; this.mgroupOptions.push({
}); id: data.recive_mgroup,
setTimeout(() => { name: data.recive_mgroup_name,
let arr =that.userList2.filter((item) => { belong_dept: data.recive_dept,
return item.id == data.recive_user });
})
if(arr.length>0){}else{
let obj = {};
obj.id = data.recive_user;
obj.name = data.recive_user_name;
that.userList2.push(obj);
}
},500)
if(data.new_batch!==''&&data.new_batch!==undefined&&data.new_batch!==null){
this.change_batch = true;
} }
return this;
},
async loadData(id) {
this.loading = true;
try {
const data = await this.$API.wpm.handover.item.req(id);
this.setData(data);
} finally {
this.loading = false;
}
return this;
}, },
// //
setFilters(filters) { setFilters(filters) {
@ -957,7 +968,7 @@ export default {
that.mgroupOptions = res0; that.mgroupOptions = res0;
if(res0.length==1){ if(res0.length==1){
that.form.recive_mgroup = res0[0].id; that.form.recive_mgroup = res0[0].id;
that.getUserList2(); that.reciveMgroupChange(res0[0].id);
} }
}) })
let obj = {}; let obj = {};
@ -1154,4 +1165,26 @@ export default {
height: 50px; height: 50px;
line-height: 50px; line-height: 50px;
} }
.form-section-title {
margin: 4px 0 12px;
padding-left: 10px;
font-size: 15px;
font-weight: 600;
line-height: 20px;
border-left: 3px solid var(--el-color-primary);
}
.handover-summary {
margin-bottom: 20px;
}
.product-detail-list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
padding: 8px 16px;
}
.product-detail-label {
margin-right: 4px;
color: var(--el-text-color-secondary);
}
</style> </style>