feat(qc): 优化质量评审审批流程,改为创建时预填内容领导仅确认

1.  调整审批接口为路径参数传递评审单ID,移除审批BO参数
2.  待审批页面改为只读展示已填写的审批意见和钢卷改判状态
3.  审批通过时直接执行改判,无需额外操作
4.  重构编辑弹窗和详情页的布局与展示逻辑
5.  移除独立的品质部意见编辑,整合到表单中
This commit is contained in:
王文昊
2026-07-04 14:35:20 +08:00
parent ec40ab90ba
commit 0f054c189d
6 changed files with 198 additions and 195 deletions

View File

@@ -10,7 +10,6 @@ import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup; import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType; import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil; import com.klp.common.utils.poi.ExcelUtil;
import com.klp.mes.qc.domain.bo.QcQualityReviewApproveBo;
import com.klp.mes.qc.domain.bo.QcQualityReviewBo; import com.klp.mes.qc.domain.bo.QcQualityReviewBo;
import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo; import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo;
import com.klp.mes.qc.domain.vo.QcQualityReviewLogVo; import com.klp.mes.qc.domain.vo.QcQualityReviewLogVo;
@@ -110,12 +109,13 @@ public class QcQualityReviewController extends BaseController {
} }
/** /**
* 审批通过 * 审批通过(创建时已填好领导意见和改判等级,领导仅确认)
*/ */
@Log(title = "质量评审单", businessType = BusinessType.UPDATE) @Log(title = "质量评审单", businessType = BusinessType.UPDATE)
@PostMapping("/approve") @PostMapping("/approve/{reviewId}")
public R<Void> approve(@Validated @RequestBody QcQualityReviewApproveBo bo) { public R<Void> approve(@NotNull(message = "主键不能为空")
return toAjax(iQcQualityReviewService.approve(bo)); @PathVariable Long reviewId) {
return toAjax(iQcQualityReviewService.approve(reviewId));
} }
/** /**

View File

@@ -2,7 +2,6 @@ package com.klp.mes.qc.service;
import com.klp.common.core.domain.PageQuery; import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo; import com.klp.common.core.page.TableDataInfo;
import com.klp.mes.qc.domain.bo.QcQualityReviewApproveBo;
import com.klp.mes.qc.domain.bo.QcQualityReviewBo; import com.klp.mes.qc.domain.bo.QcQualityReviewBo;
import com.klp.mes.qc.domain.vo.QcQualityReviewVo; import com.klp.mes.qc.domain.vo.QcQualityReviewVo;
import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo; import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo;
@@ -55,9 +54,9 @@ public interface IQcQualityReviewService {
Boolean submit(Long reviewId); Boolean submit(Long reviewId);
/** /**
* 审批通过flowStatus: 2→3 * 审批通过flowStatus: 2→3,所有填写内容已在创建时完成,领导仅确认
*/ */
Boolean approve(QcQualityReviewApproveBo bo); Boolean approve(Long reviewId);
/** /**
* 驳回flowStatus: 2→4 * 驳回flowStatus: 2→4

View File

@@ -16,7 +16,6 @@ import com.klp.service.IWmsMaterialCoilService;
import com.klp.mes.qc.domain.QcQualityReview; import com.klp.mes.qc.domain.QcQualityReview;
import com.klp.mes.qc.domain.QcQualityReviewCoil; import com.klp.mes.qc.domain.QcQualityReviewCoil;
import com.klp.mes.qc.domain.QcQualityReviewLog; import com.klp.mes.qc.domain.QcQualityReviewLog;
import com.klp.mes.qc.domain.bo.QcQualityReviewApproveBo;
import com.klp.mes.qc.domain.bo.QcQualityReviewBo; import com.klp.mes.qc.domain.bo.QcQualityReviewBo;
import com.klp.mes.qc.domain.bo.QcQualityReviewCoilBo; import com.klp.mes.qc.domain.bo.QcQualityReviewCoilBo;
import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo; import com.klp.mes.qc.domain.vo.QcQualityReviewCoilVo;
@@ -32,7 +31,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* 质量评审单Service业务层处理 * 质量评审单Service业务层处理
@@ -189,6 +187,10 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
if (StringUtils.isBlank(review.getDeptOpinion())) { if (StringUtils.isBlank(review.getDeptOpinion())) {
throw new RuntimeException("请先填写品质部评审意见"); throw new RuntimeException("请先填写品质部评审意见");
} }
// 校验:必须有领导审批意见
if (StringUtils.isBlank(review.getLeaderOpinion())) {
throw new RuntimeException("请先填写领导审批意见");
}
// 校验:至少有一个钢卷 // 校验:至少有一个钢卷
Long coilCount = coilMapper.selectCount( Long coilCount = coilMapper.selectCount(
Wrappers.<QcQualityReviewCoil>lambdaQuery() Wrappers.<QcQualityReviewCoil>lambdaQuery()
@@ -197,6 +199,18 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
if (coilCount == null || coilCount == 0) { if (coilCount == null || coilCount == 0) {
throw new RuntimeException("请至少添加一个钢卷"); throw new RuntimeException("请至少添加一个钢卷");
} }
// 校验:每个钢卷必须指定改判后质量等级
List<QcQualityReviewCoil> submitCoilList = coilMapper.selectList(
Wrappers.<QcQualityReviewCoil>lambdaQuery()
.eq(QcQualityReviewCoil::getReviewId, reviewId)
.eq(QcQualityReviewCoil::getDelFlag, 0));
for (QcQualityReviewCoil coil : submitCoilList) {
if (StringUtils.isBlank(coil.getRegradeQuality())) {
String coilNo = StringUtils.isNotBlank(coil.getCurrentCoilNo())
? coil.getCurrentCoilNo() : "ID:" + coil.getDetailId();
throw new RuntimeException("钢卷【" + coilNo + "】未指定改判后质量状态");
}
}
// 更新流程状态为待审批,清除驳回原因 // 更新流程状态为待审批,清除驳回原因
baseMapper.update(null, Wrappers.<QcQualityReview>lambdaUpdate() baseMapper.update(null, Wrappers.<QcQualityReview>lambdaUpdate()
@@ -210,53 +224,30 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
} }
/** /**
* 审批通过 * 审批通过并直接执行改判(创建时已填好所有内容,领导确认后立即生效)
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean approve(QcQualityReviewApproveBo bo) { public Boolean approve(Long reviewId) {
QcQualityReview review = baseMapper.selectById(bo.getReviewId()); QcQualityReview review = baseMapper.selectById(reviewId);
if (review == null) { if (review == null) {
throw new RuntimeException("评审单不存在"); throw new RuntimeException("评审单不存在");
} }
if (!Long.valueOf(2L).equals(review.getFlowStatus())) { if (!Long.valueOf(2L).equals(review.getFlowStatus())) {
throw new RuntimeException("只有待审批状态的评审单才能审批"); throw new RuntimeException("只有待审批状态的评审单才能审批");
} }
if (CollUtil.isEmpty(bo.getCoilRegradeList())) {
throw new RuntimeException("请为每个钢卷指定改判后质量状态");
}
// 校验coilRegradeList 是否覆盖了评审单中的所有有效钢卷 // 1. 更新主表流程状态为已通过
List<QcQualityReviewCoil> dbCoils = coilMapper.selectList(
Wrappers.<QcQualityReviewCoil>lambdaQuery()
.eq(QcQualityReviewCoil::getReviewId, bo.getReviewId())
.eq(QcQualityReviewCoil::getDelFlag, 0));
Set<Long> regradedIds = bo.getCoilRegradeList().stream()
.map(QcQualityReviewApproveBo.CoilRegradeBo::getDetailId)
.collect(Collectors.toSet());
for (QcQualityReviewCoil coil : dbCoils) {
if (!regradedIds.contains(coil.getDetailId())) {
throw new RuntimeException("钢卷【" + coil.getCurrentCoilNo() + "】未指定改判后质量状态");
}
}
// 1. 更新主表流程状态
baseMapper.update(null, Wrappers.<QcQualityReview>lambdaUpdate() baseMapper.update(null, Wrappers.<QcQualityReview>lambdaUpdate()
.eq(QcQualityReview::getReviewId, bo.getReviewId()) .eq(QcQualityReview::getReviewId, reviewId)
.set(QcQualityReview::getFlowStatus, 3L) .set(QcQualityReview::getFlowStatus, 3L));
.set(QcQualityReview::getLeaderOpinion, bo.getLeaderOpinion())
.set(QcQualityReview::getLeaderSign, bo.getLeaderSign())
.set(QcQualityReview::getLeaderSignDate, new java.sql.Date(System.currentTimeMillis())));
// 2. 更新每个钢卷的改判状态 // 2. 记录审批日志
for (QcQualityReviewApproveBo.CoilRegradeBo regrade : bo.getCoilRegradeList()) { addLog(reviewId, "approve", review.getLeaderOpinion());
coilMapper.update(null, Wrappers.<QcQualityReviewCoil>lambdaUpdate()
.eq(QcQualityReviewCoil::getDetailId, regrade.getDetailId()) // 3. 直接执行改判(无需单独点击执行改判按钮)
.set(QcQualityReviewCoil::getRegradeQuality, regrade.getRegradeQuality())); execute(reviewId);
}
// 3. 记录审批日志
addLog(bo.getReviewId(), "approve", bo.getLeaderOpinion());
return true; return true;
} }

View File

@@ -51,12 +51,11 @@ export function submitQualityReview(reviewId) {
}) })
} }
// 审批通过 // 审批通过(创建时已填好内容,领导仅确认)
export function approveQualityReview(data) { export function approveQualityReview(reviewId) {
return request({ return request({
url: '/qc/qualityReview/approve', url: '/qc/qualityReview/approve/' + reviewId,
method: 'post', method: 'post'
data: data
}) })
} }

View File

@@ -70,9 +70,7 @@
<el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain icon="el-icon-s-promotion" <el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain icon="el-icon-s-promotion"
@click="handleSubmit" v-hasPermi="['qc:qualityReview:submit']">提交送审</el-button> @click="handleSubmit" v-hasPermi="['qc:qualityReview:submit']">提交送审</el-button>
<!-- 待审批审批/驳回表单在下方展示顶部不再重复放置操作按钮 --> <!-- 待审批审批/驳回表单在下方展示顶部不再重复放置操作按钮 -->
<!-- 已通过执行改判 --> <!-- 已通过审批通过时已直接执行改判无需额外操作 -->
<el-button v-if="currentRow.flowStatus === 3" size="mini" type="warning" plain icon="el-icon-setting"
@click="handleExecute" v-hasPermi="['qc:qualityReview:execute']">执行改判</el-button>
<!-- 已驳回重新提交 --> <!-- 已驳回重新提交 -->
<el-button v-if="currentRow.flowStatus === 4" size="mini" type="primary" plain icon="el-icon-s-promotion" <el-button v-if="currentRow.flowStatus === 4" size="mini" type="primary" plain icon="el-icon-s-promotion"
@click="handleReSubmit" v-hasPermi="['qc:qualityReview:submit']">重新提交</el-button> @click="handleReSubmit" v-hasPermi="['qc:qualityReview:submit']">重新提交</el-button>
@@ -105,9 +103,6 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item label="传递日期">{{ currentRow.transmitDate }}</el-form-item> <el-form-item label="传递日期">{{ currentRow.transmitDate }}</el-form-item>
</el-col> </el-col>
<el-col :span="8">
<el-form-item label="生产日期">{{ currentRow.prodDateRange }}</el-form-item>
</el-col>
</el-row> </el-row>
</el-form> </el-form>
</el-card> </el-card>
@@ -141,15 +136,7 @@
<!-- ===== 品质部评审意见 ===== --> <!-- ===== 品质部评审意见 ===== -->
<el-card class="detail-section" shadow="never"> <el-card class="detail-section" shadow="never">
<div slot="header"><span><i class="el-icon-edit-outline"></i> 品质部评审意见</span></div> <div slot="header"><span><i class="el-icon-edit-outline"></i> 品质部评审意见</span></div>
<div v-if="currentRow.flowStatus === 1 || currentRow.flowStatus === 4" class="section-editor"> <div class="section-display">
<el-input type="textarea" :rows="3" v-model="opinionForm.deptOpinion" placeholder="请填写品质部评审意见..." />
<div style="margin-top:8px; display:flex; gap:8px;">
<el-input v-model="opinionForm.deptSign" placeholder="签字人" style="width:160px;" size="small" />
<el-date-picker v-model="opinionForm.deptSignDate" type="date" placeholder="签字日期" size="small" />
</div>
<el-button size="small" type="primary" @click="saveOpinion" style="margin-top:8px;">保存意见</el-button>
</div>
<div v-else class="section-display">
<div class="opinion-text">{{ currentRow.deptOpinion || '暂未填写' }}</div> <div class="opinion-text">{{ currentRow.deptOpinion || '暂未填写' }}</div>
<div class="opinion-footer" v-if="currentRow.deptOpinion"> <div class="opinion-footer" v-if="currentRow.deptOpinion">
<span>签字{{ currentRow.deptSign || '-' }}</span> <span>签字{{ currentRow.deptSign || '-' }}</span>
@@ -161,35 +148,52 @@
<!-- ===== 领导审批意见 ===== --> <!-- ===== 领导审批意见 ===== -->
<el-card class="detail-section" shadow="never"> <el-card class="detail-section" shadow="never">
<div slot="header"><span><i class="el-icon-s-check"></i> 领导审批意见</span></div> <div slot="header"><span><i class="el-icon-s-check"></i> 领导审批意见</span></div>
<!-- flowStatus=2时显示审批表单权限由后端API控制前端不做限制 --> <!-- flowStatus=2时显示审批表单创建时已填好内容领导仅确认/驳回 -->
<div v-if="currentRow.flowStatus === 2" class="section-editor"> <div v-if="currentRow.flowStatus === 2" class="section-editor">
<!-- 审批通过模式 --> <!-- 领导意见只读展示 -->
<el-radio-group v-model="approveAction" style="margin-bottom:12px;"> <div class="approve-opinion-box">
<label>领导审批意见</label>
<div class="opinion-content">{{ currentRow.leaderOpinion || '暂未填写' }}</div>
<div class="opinion-footer" v-if="currentRow.leaderOpinion">
<span>签字{{ currentRow.leaderSign || '-' }}</span>
<span>日期{{ currentRow.leaderSignDate || '-' }}</span>
</div>
</div>
<!-- 各钢卷改判后等级只读展示 -->
<div class="approve-coil-section">
<div class="approve-coil-title">各钢卷改判后质量状态</div>
<el-table :data="coilList" size="small" border max-height="300">
<el-table-column prop="currentCoilNo" label="产品卷号" width="140" />
<el-table-column prop="spec" label="规格(mm)" width="100" />
<el-table-column prop="defectDesc" label="缺陷描述" min-width="160" show-overflow-tooltip />
<el-table-column prop="beforeQuality" label="当前等级" width="80" align="center">
<template slot-scope="s"><el-tag size="mini" type="danger">{{ s.row.beforeQuality }}</el-tag></template>
</el-table-column>
<el-table-column prop="regradeQuality" label="改判后等级" width="110" align="center">
<template slot-scope="s"><el-tag size="mini" type="warning">{{ s.row.regradeQuality }}</el-tag></template>
</el-table-column>
</el-table>
</div>
<div class="approve-actions">
<el-radio-group v-model="approveAction" size="small">
<el-radio-button label="approve">通过</el-radio-button> <el-radio-button label="approve">通过</el-radio-button>
<el-radio-button label="reject">驳回</el-radio-button> <el-radio-button label="reject">驳回</el-radio-button>
</el-radio-group> </el-radio-group>
<div class="approve-action-body">
<template v-if="approveAction === 'approve'"> <template v-if="approveAction === 'approve'">
<el-input type="textarea" :rows="3" v-model="approveForm.leaderOpinion" placeholder="请输入领导审批意见..." /> <p class="approve-hint">确认审批通过后将直接执行改判钢卷质量状态和库区将同步更新</p>
<div style="margin:8px 0;"> <el-button type="success" @click="doApprove" :size="'small'" icon="el-icon-check" round>确认通过</el-button>
<el-input v-model="approveForm.leaderSign" placeholder="签字人" style="width:160px;" size="small" />
</div>
<div class="approve-coil-section">
<div class="approve-coil-title">请为每个钢卷指定改判后质量状态</div>
<div v-for="coil in coilList" :key="coil.detailId" class="approve-coil-row">
<span class="approve-coil-label">{{ coil.currentCoilNo }}{{ coil.spec }}</span>
<el-select v-model="approveCoilMap[coil.detailId]" placeholder="请选择改判后等级" size="small" style="width:180px;">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
<el-button size="small" type="success" @click="doApprove">确认通过</el-button>
</template> </template>
<template v-else> <template v-else>
<el-input type="textarea" :rows="3" v-model="rejectReason" placeholder="请输入驳回原因..." /> <el-input type="textarea" :rows="2" v-model="rejectReason" placeholder="请输入驳回原因..." style="margin-bottom:8px;" />
<el-button size="small" type="danger" @click="doReject" style="margin-top:8px;">确认驳回</el-button> <el-button type="danger" @click="doReject" :size="'small'" icon="el-icon-close" round>确认驳回</el-button>
</template> </template>
</div> </div>
</div>
</div>
<div v-else class="section-display"> <div v-else class="section-display">
<div class="opinion-text">{{ currentRow.leaderOpinion || '暂无审批意见' }}</div> <div class="opinion-text">{{ currentRow.leaderOpinion || '暂无审批意见' }}</div>
<div class="opinion-footer" v-if="currentRow.leaderOpinion"> <div class="opinion-footer" v-if="currentRow.leaderOpinion">
@@ -224,8 +228,14 @@
</div> </div>
<!-- 编辑弹窗 --> <!-- 编辑弹窗 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="900px" :close-on-click-modal="false" append-to-body> <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="960px" :close-on-click-modal="false" append-to-body class="review-dialog">
<el-form ref="form" :model="editForm" :rules="rules" label-width="100px" size="small"> <el-form ref="form" :model="editForm" :rules="rules" label-width="100px" size="small">
<!-- ===== 基本信息 ===== -->
<div class="dialog-section">
<div class="dialog-section-header">
<i class="el-icon-info"></i>
<span>基本信息</span>
</div>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="产品名称" prop="productName"> <el-form-item label="产品名称" prop="productName">
@@ -239,23 +249,20 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="8"> <el-col :span="12">
<el-form-item label="传递人" prop="transmitUser"> <el-form-item label="传递人" prop="transmitUser">
<el-input v-model="editForm.transmitUser" /> <el-input v-model="editForm.transmitUser" placeholder="填写传递人姓名" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="12">
<el-form-item label="传递日期" prop="transmitDate"> <el-form-item label="传递日期" prop="transmitDate">
<el-date-picker v-model="editForm.transmitDate" type="date" placeholder="选择日期" style="width:100%;" /> <el-date-picker v-model="editForm.transmitDate" type="date" placeholder="选择日期" style="width:100%;" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8">
<el-form-item label="生产日期" prop="prodDateRange">
<el-input v-model="editForm.prodDateRange" placeholder="如14-15" />
</el-form-item>
</el-col>
</el-row> </el-row>
</div>
<!-- ===== 钢卷选择 ===== --> <!-- ===== 钢卷选择 ===== -->
<div class="dialog-section"> <div class="dialog-section">
<div class="dialog-section-header"> <div class="dialog-section-header">
@@ -272,13 +279,23 @@
<el-input v-model="scope.row.defectDesc" size="mini" placeholder="输入缺陷描述" /> <el-input v-model="scope.row.defectDesc" size="mini" placeholder="输入缺陷描述" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="regradeQuality" label="改判后等级" min-width="130">
<template slot-scope="scope">
<el-select v-model="scope.row.regradeQuality" placeholder="请选择" size="mini">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" width="60" align="center"> <el-table-column label="操作" width="60" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="editForm.coilList.splice(scope.$index, 1)"></el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="editForm.coilList.splice(scope.$index, 1)"></el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div v-if="editForm.coilList.length === 0" class="dialog-table-empty" style="cursor:pointer;" @click="showCoilSelector = true">请选择O级钢卷</div> <div v-if="editForm.coilList.length === 0" class="dialog-table-empty" @click="showCoilSelector = true">
<i class="el-icon-circle-plus-outline"></i>
<span>点击选择O级钢卷</span>
</div>
</div> </div>
<!-- ===== 钢卷选择器嵌套在弹窗内 ===== --> <!-- ===== 钢卷选择器嵌套在弹窗内 ===== -->
@@ -288,31 +305,63 @@
:filters="{ qualityStatusCsv: 'O', status: 0 }" :filters="{ qualityStatusCsv: 'O', status: 0 }"
@confirm="onDialogCoilConfirm" /> @confirm="onDialogCoilConfirm" />
<el-divider /> <!-- ===== 品质部评审 ===== -->
<div class="dialog-section">
<div class="dialog-section-header">
<i class="el-icon-edit-outline"></i>
<span>品质部评审意见</span>
</div>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="品质部意见" prop="deptOpinion"> <el-form-item label="评审意见" prop="deptOpinion">
<el-input type="textarea" :rows="3" v-model="editForm.deptOpinion" placeholder="请填写品质部评审意见" /> <el-input type="textarea" :rows="3" v-model="editForm.deptOpinion" placeholder="请填写品质部评审意见" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="8"> <el-col :span="12">
<el-form-item label="签字人"> <el-form-item label="签字人">
<el-input v-model="editForm.deptSign" /> <el-input v-model="editForm.deptSign" placeholder="签字人姓名" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="12">
<el-form-item label="签字日期"> <el-form-item label="签字日期">
<el-date-picker v-model="editForm.deptSignDate" type="date" placeholder="选择日期" style="width:100%;" /> <el-date-picker v-model="editForm.deptSignDate" type="date" placeholder="选择日期" style="width:100%;" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</div>
<!-- ===== 领导审批 ===== -->
<div class="dialog-section">
<div class="dialog-section-header">
<i class="el-icon-s-check"></i>
<span>领导审批意见</span>
</div>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="审批意见" prop="leaderOpinion">
<el-input type="textarea" :rows="3" v-model="editForm.leaderOpinion" placeholder="请填写领导审批意见" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="签字人">
<el-input v-model="editForm.leaderSign" placeholder="领导姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="签字日期">
<el-date-picker v-model="editForm.leaderSignDate" type="date" placeholder="选择日期" style="width:100%;" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form> </el-form>
<span slot="footer"> <span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button> <el-button @click="dialogVisible = false" icon="el-icon-close">取消</el-button>
<el-button type="primary" @click="saveForm">确定</el-button> <el-button type="primary" @click="saveForm" icon="el-icon-check">确定</el-button>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
@@ -350,12 +399,6 @@ export default {
// 钢卷选择 // 钢卷选择
showCoilSelector: false, showCoilSelector: false,
// 品质部意见编辑独立于editForm避免串数据
opinionForm: {
deptOpinion: '',
deptSign: '',
deptSignDate: undefined
},
// 编辑弹窗 // 编辑弹窗
dialogVisible: false, dialogVisible: false,
dialogTitle: '', dialogTitle: '',
@@ -370,6 +413,9 @@ export default {
deptOpinion: '', deptOpinion: '',
deptSign: '', deptSign: '',
deptSignDate: undefined, deptSignDate: undefined,
leaderOpinion: '',
leaderSign: '',
leaderSignDate: undefined,
coilList: [] coilList: []
}, },
rules: { rules: {
@@ -423,13 +469,6 @@ export default {
map[c.detailId] = c.regradeQuality || '' map[c.detailId] = c.regradeQuality || ''
}) })
this.approveCoilMap = map this.approveCoilMap = map
// 初始化品质部意见编辑独立于editForm
this.opinionForm = {
deptOpinion: data.deptOpinion || '',
deptSign: data.deptSign || '',
deptSignDate: data.deptSignDate || undefined
}
this.approveForm.reviewId = reviewId
this.approveForm.leaderOpinion = '' this.approveForm.leaderOpinion = ''
this.approveForm.leaderSign = '' this.approveForm.leaderSign = ''
this.rejectReason = '' this.rejectReason = ''
@@ -456,6 +495,9 @@ export default {
deptOpinion: '', deptOpinion: '',
deptSign: '', deptSign: '',
deptSignDate: undefined, deptSignDate: undefined,
leaderOpinion: '',
leaderSign: '',
leaderSignDate: undefined,
coilList: [] coilList: []
} }
this.editing = true this.editing = true
@@ -473,6 +515,9 @@ export default {
deptOpinion: row.deptOpinion, deptOpinion: row.deptOpinion,
deptSign: row.deptSign, deptSign: row.deptSign,
deptSignDate: row.deptSignDate, deptSignDate: row.deptSignDate,
leaderOpinion: row.leaderOpinion || '',
leaderSign: row.leaderSign || '',
leaderSignDate: row.leaderSignDate || undefined,
coilList: this.coilList.map(c => ({ ...c })) coilList: this.coilList.map(c => ({ ...c }))
} }
this.editing = true this.editing = true
@@ -509,6 +554,7 @@ export default {
spec: coil.specification, // CoilSelector返回的字段名为specification spec: coil.specification, // CoilSelector返回的字段名为specification
netWeight: coil.netWeight, netWeight: coil.netWeight,
defectDesc: '', defectDesc: '',
regradeQuality: '', // 改判后等级,由创建者填写
groupSeq: startIdx + idx + 1, groupSeq: startIdx + idx + 1,
beforeQuality: coil.qualityStatus || 'O' beforeQuality: coil.qualityStatus || 'O'
})) }))
@@ -538,26 +584,8 @@ export default {
// ===== 审批 ===== // ===== 审批 =====
doApprove() { doApprove() {
if (!this.approveForm.leaderOpinion) { this.$confirm('确认审批通过?审批后将直接执行改判,钢卷质量状态将同步更新。', '提示', { type: 'success' }).then(() => {
this.$modal.msgError('请输入审批意见') approveQualityReview(this.currentRow.reviewId).then(() => {
return
}
const coilRegradeList = this.coilList.map(c => ({
detailId: c.detailId,
regradeQuality: this.approveCoilMap[c.detailId]
}))
const invalid = coilRegradeList.some(r => !r.regradeQuality)
if (invalid) {
this.$modal.msgError('请为每个钢卷指定改判后质量状态')
return
}
this.$confirm('确认审批通过?', '提示', { type: 'success' }).then(() => {
approveQualityReview({
reviewId: this.currentRow.reviewId,
leaderOpinion: this.approveForm.leaderOpinion,
leaderSign: this.approveForm.leaderSign,
coilRegradeList
}).then(() => {
this.$modal.msgSuccess('审批通过') this.$modal.msgSuccess('审批通过')
this.handleRefreshDetail() this.handleRefreshDetail()
}) })
@@ -605,20 +633,8 @@ export default {
hasPermi(permi) { hasPermi(permi) {
return this.$store.getters.permissions && this.$store.getters.permissions.includes(permi) return this.$store.getters.permissions && this.$store.getters.permissions.includes(permi)
}, },
saveOpinion() {
if (!this.currentRow) return
updateQualityReview({
reviewId: this.currentRow.reviewId,
deptOpinion: this.opinionForm.deptOpinion,
deptSign: this.opinionForm.deptSign,
deptSignDate: this.opinionForm.deptSignDate
}).then(() => {
this.$modal.msgSuccess('保存成功')
this.handleRefreshDetail()
})
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -782,6 +798,20 @@ export default {
font-size: 13px; font-size: 13px;
} }
} }
.approve-actions {
background: #fafafa;
border-radius: 4px;
padding: 16px;
margin-top: 8px;
}
.approve-actions .approve-action-body {
margin-top: 12px;
}
.approve-actions .approve-hint {
margin: 0 0 10px;
font-size: 13px;
color: #909399;
}
.text-muted { color: #c0c4cc; } .text-muted { color: #c0c4cc; }
.timeline-opinion { .timeline-opinion {
font-size: 13px; font-size: 13px;

View File

@@ -44,22 +44,28 @@
</el-radio-group> </el-radio-group>
<template v-if="approveAction === 'approve'"> <template v-if="approveAction === 'approve'">
<el-input type="textarea" :rows="3" v-model="approveForm.leaderOpinion" placeholder="请输入领导审批意见..." style="margin-bottom:12px;" /> <!-- 领导意见只读展示 -->
<el-input v-model="approveForm.leaderSign" placeholder="签字人" style="width:160px; margin-bottom:12px;" size="small" /> <div class="approve-opinion-box">
<label>领导审批意见</label>
<div class="opinion-content">{{ approveDialog.review.leaderOpinion || '暂未填写' }}</div>
<div class="opinion-footer" v-if="approveDialog.review.leaderOpinion">
<span>签字{{ approveDialog.review.leaderSign || '-' }}</span>
<span>日期{{ approveDialog.review.leaderSignDate || '-' }}</span>
</div>
</div>
<!-- 各钢卷改判后等级只读展示 -->
<div class="coil-regrade-section"> <div class="coil-regrade-section">
<div class="coil-regrade-title">请为以下钢卷指定改判后质量状态</div> <div class="coil-regrade-title">各钢卷改判后质量状态</div>
<el-table :data="approveCoilList" size="small" border max-height="300"> <el-table :data="approveCoilList" size="small" border max-height="300">
<el-table-column prop="currentCoilNo" label="产品卷号" width="140" /> <el-table-column prop="currentCoilNo" label="产品卷号" width="140" />
<el-table-column prop="spec" label="规格" width="100" /> <el-table-column prop="spec" label="规格" width="100" />
<el-table-column prop="beforeQuality" label="当前等级" width="80"> <el-table-column prop="defectDesc" label="缺陷描述" min-width="160" show-overflow-tooltip />
<el-table-column prop="beforeQuality" label="当前等级" width="80" align="center">
<template slot-scope="s"><el-tag size="mini" type="danger">{{ s.row.beforeQuality }}</el-tag></template> <template slot-scope="s"><el-tag size="mini" type="danger">{{ s.row.beforeQuality }}</el-tag></template>
</el-table-column> </el-table-column>
<el-table-column label="改判后状态" width="160"> <el-table-column prop="regradeQuality" label="改判后等级" width="110" align="center">
<template slot-scope="s"> <template slot-scope="s"><el-tag size="mini" type="warning">{{ s.row.regradeQuality }}</el-tag></template>
<el-select v-model="approveCoilMap[s.row.detailId]" placeholder="请选择" size="small">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
@@ -97,13 +103,7 @@ export default {
review: null review: null
}, },
approveAction: 'approve', approveAction: 'approve',
approveForm: {
reviewId: undefined,
leaderOpinion: '',
leaderSign: ''
},
approveCoilList: [], approveCoilList: [],
approveCoilMap: {},
approveLoading: false, approveLoading: false,
rejectReason: '' rejectReason: ''
} }
@@ -126,19 +126,13 @@ export default {
handleQuickApprove(row) { handleQuickApprove(row) {
this.approveAction = 'approve' this.approveAction = 'approve'
this.approveDialog.review = row this.approveDialog.review = row
this.approveForm = { reviewId: row.reviewId, leaderOpinion: '', leaderSign: '' }
this.rejectReason = '' this.rejectReason = ''
this.approveDialog.visible = true this.approveDialog.visible = true
// 加载明细 // 加载明细(只读展示)
getQualityReview(row.reviewId).then(res => { getQualityReview(row.reviewId).then(res => {
const data = res.data const data = res.data
this.approveCoilList = data.coilList || [] this.approveCoilList = data.coilList || []
const map = {}
;(data.coilList || []).forEach(c => {
map[c.detailId] = c.regradeQuality || ''
})
this.approveCoilMap = map
}) })
}, },
handleQuickReject(row) { handleQuickReject(row) {
@@ -150,25 +144,8 @@ export default {
}).catch(() => {}) }).catch(() => {})
}, },
doApprove() { doApprove() {
if (!this.approveForm.leaderOpinion) {
this.$modal.msgError('请输入审批意见')
return
}
const coilRegradeList = this.approveCoilList.map(c => ({
detailId: c.detailId,
regradeQuality: this.approveCoilMap[c.detailId]
}))
if (coilRegradeList.some(r => !r.regradeQuality)) {
this.$modal.msgError('请为每个钢卷指定改判后质量状态')
return
}
this.approveLoading = true this.approveLoading = true
approveQualityReview({ approveQualityReview(this.approveDialog.review.reviewId).then(() => {
reviewId: this.approveDialog.review.reviewId,
leaderOpinion: this.approveForm.leaderOpinion,
leaderSign: this.approveForm.leaderSign,
coilRegradeList
}).then(() => {
this.$modal.msgSuccess('审批通过') this.$modal.msgSuccess('审批通过')
this.approveDialog.visible = false this.approveDialog.visible = false
this.approveLoading = false this.approveLoading = false
@@ -205,6 +182,13 @@ export default {
line-height: 1.6; line-height: 1.6;
white-space: pre-wrap; white-space: pre-wrap;
} }
.opinion-footer {
margin-top: 8px;
display: flex;
gap: 20px;
color: #909399;
font-size: 13px;
}
} }
.coil-regrade-section { .coil-regrade-section {
margin-top: 12px; margin-top: 12px;