Files
klp-oa/klp-ui/src/views/mes/qc/qualityReview/index.vue
王文昊 d5d77c53b6 refactor(qc): 移除页面顶部审批操作按钮,调整审批逻辑
1.  移除待审批状态下页面顶部的审批通过和驳回按钮
2.  重构审批相关的前端方法,删除冗余的handleApprove和handleReject
3.  优化后端审批日志逻辑,自动获取当前登录用户作为操作人
4.  新增评审单修改状态校验,仅草稿和已驳回状态可修改
5.  新增钢卷改判状态完整性校验,确保所有钢卷都已指定改判质量
6.  完善保存前的数据校验,新增产品名称非空校验和默认传审部门
2026-07-04 11:23:13 +08:00

797 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container quality-review-container">
<div class="left-panel">
<div class="panel-header">
<div class="header-title">
<i class="el-icon-document-checked"></i>
<span>质量评审单</span>
<el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;" title="刷新列表"></el-button>
</div>
<el-select v-model="queryParams.flowStatus" placeholder="全部状态" clearable size="mini" @change="handleQuery" class="header-filter">
<el-option v-for="item in dict.type.quality_review_status" :key="item.value" :label="item.label" :value="parseInt(item.value)" />
</el-select>
</div>
<div class="search-row">
<el-input v-model="queryParams.reviewNo" placeholder="搜索评审单编号..." clearable prefix-icon="el-icon-search" size="small" @keyup.enter.native="handleQuery" @clear="handleQuery" />
<el-button type="primary" size="small" @click="handleAdd" v-hasPermi="['qc:qualityReview:add']">
<i class="el-icon-plus"></i>
</el-button>
</div>
<div v-loading="loading" class="list-body">
<div v-for="item in dataList" :key="item.reviewId" class="list-item"
:class="{ active: currentRow && currentRow.reviewId === item.reviewId }" @click="handleRowClick(item)">
<div class="item-main">
<span class="item-title">{{ item.reviewNo }}</span>
<span class="item-sub">{{ item.transmitUser }} · {{ item.productName }}</span>
</div>
<div class="item-meta">
<el-tag v-if="item.flowStatus === 1" type="info" size="mini">待提交</el-tag>
<el-tag v-else-if="item.flowStatus === 2" type="warning" size="mini">待审批</el-tag>
<el-tag v-else-if="item.flowStatus === 3" type="success" size="mini">已通过</el-tag>
<el-tag v-else-if="item.flowStatus === 4" type="danger" size="mini">已驳回</el-tag>
</div>
<div class="item-actions">
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)" v-hasPermi="['qc:qualityReview:edit']"></el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(item)" v-hasPermi="['qc:qualityReview:delete']"></el-button>
</div>
</div>
<div v-if="dataList.length === 0 && !loading" class="list-empty">
<i class="el-icon-folder-opened"></i>
<span>暂无质量评审单</span>
</div>
</div>
<div class="list-footer">
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
</div>
</div>
<!-- 右侧详情 -->
<div class="right-panel">
<div v-if="!currentRow" class="empty-tip">
<i class="el-icon-info"></i>
<span>请在左侧列表中选择一条评审单查看详情</span>
</div>
<div v-else v-loading="detailLoading" class="detail-content">
<!-- ===== 顶部操作栏 ===== -->
<div class="detail-header">
<div class="detail-header-left">
<span class="detail-title">{{ currentRow.reviewNo }}</span>
<el-tag v-if="currentRow.flowStatus === 1" type="info" size="small">待提交</el-tag>
<el-tag v-else-if="currentRow.flowStatus === 2" type="warning" size="small">待审批</el-tag>
<el-tag v-else-if="currentRow.flowStatus === 3" type="success" size="small">已通过</el-tag>
<el-tag v-else-if="currentRow.flowStatus === 4" type="danger" size="small">已驳回</el-tag>
</div>
<div class="detail-header-actions">
<!-- 待提交提交送审 -->
<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>
<!-- 待审批审批/驳回表单在下方展示顶部不再重复放置操作按钮 -->
<!-- 已通过执行改判 -->
<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"
@click="handleReSubmit" v-hasPermi="['qc:qualityReview:submit']">重新提交</el-button>
<!-- 通用 -->
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail">刷新</el-button>
<el-button v-if="currentRow.flowStatus === 1 || currentRow.flowStatus === 4" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(currentRow)">编辑</el-button>
<el-button v-if="currentRow.flowStatus === 1 || currentRow.flowStatus === 4" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(currentRow)">删除</el-button>
</div>
</div>
<!-- ===== 基本信息 ===== -->
<el-card class="detail-section" shadow="never">
<div slot="header"><span><i class="el-icon-info"></i> 基本信息</span></div>
<el-form :model="currentRow" label-width="100px" size="small" class="basic-form">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="评审单编号">{{ currentRow.reviewNo }}</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="产品名称">{{ currentRow.productName }}</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="传递部门">{{ currentRow.transmitDept }}</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="传递人">{{ currentRow.transmitUser }}</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="传递日期">{{ currentRow.transmitDate }}</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="生产日期">{{ currentRow.prodDateRange }}</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- ===== 钢卷明细表详情只读 ===== -->
<el-card class="detail-section" shadow="never">
<div slot="header">
<span><i class="el-icon-s-management"></i> 问题钢卷明细</span>
</div>
<el-table :data="coilList" border style="width: 100%" size="small" max-height="400">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="currentCoilNo" label="产品卷号" min-width="140" />
<el-table-column prop="supplierCoilNo" label="原料卷号" min-width="140" />
<el-table-column prop="spec" label="规格(mm)" width="110" />
<el-table-column prop="netWeight" label="卷重(t)" width="90" align="right" />
<el-table-column prop="defectDesc" label="缺陷描述" min-width="200" show-overflow-tooltip />
<el-table-column prop="beforeQuality" label="改判前" width="80" align="center">
<template slot-scope="scope">
<el-tag size="mini" type="danger">{{ scope.row.beforeQuality }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="regradeQuality" label="改判后" width="110" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.regradeQuality" size="mini" type="warning">{{ scope.row.regradeQuality }}</el-tag>
<span v-else class="text-muted">待指定</span>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- ===== 品质部评审意见 ===== -->
<el-card class="detail-section" shadow="never">
<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">
<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-footer" v-if="currentRow.deptOpinion">
<span>签字{{ currentRow.deptSign || '-' }}</span>
<span>日期{{ currentRow.deptSignDate || '-' }}</span>
</div>
</div>
</el-card>
<!-- ===== 领导审批意见 ===== -->
<el-card class="detail-section" shadow="never">
<div slot="header"><span><i class="el-icon-s-check"></i> 领导审批意见</span></div>
<!-- flowStatus=2时显示审批表单权限由后端API控制前端不做限制 -->
<div v-if="currentRow.flowStatus === 2" class="section-editor">
<!-- 审批通过模式 -->
<el-radio-group v-model="approveAction" style="margin-bottom:12px;">
<el-radio-button label="approve">通过</el-radio-button>
<el-radio-button label="reject">驳回</el-radio-button>
</el-radio-group>
<template v-if="approveAction === 'approve'">
<el-input type="textarea" :rows="3" v-model="approveForm.leaderOpinion" placeholder="请输入领导审批意见..." />
<div style="margin:8px 0;">
<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 v-else>
<el-input type="textarea" :rows="3" v-model="rejectReason" placeholder="请输入驳回原因..." />
<el-button size="small" type="danger" @click="doReject" style="margin-top:8px;">确认驳回</el-button>
</template>
</div>
<div v-else class="section-display">
<div class="opinion-text">{{ currentRow.leaderOpinion || '暂无审批意见' }}</div>
<div class="opinion-footer" v-if="currentRow.leaderOpinion">
<span>签字{{ currentRow.leaderSign || '-' }}</span>
<span>日期{{ currentRow.leaderSignDate || '-' }}</span>
</div>
<div v-if="currentRow.flowStatus === 4 && currentRow.rejectReason" class="reject-reason">
<el-alert :title="'驳回原因:' + currentRow.rejectReason" type="error" show-icon :closable="false" />
</div>
</div>
</el-card>
<!-- ===== 审批日志 ===== -->
<el-card class="detail-section" shadow="never">
<div slot="header"><span><i class="el-icon-time"></i> 审批记录</span></div>
<div v-if="logList.length === 0" class="text-muted" style="padding:12px;">暂无审批记录</div>
<el-timeline v-else>
<el-timeline-item v-for="log in logList" :key="log.logId"
:timestamp="log.createTime"
:type="log.action === 'submit' ? 'primary' : (log.action === 'approve' ? 'success' : 'danger')"
:icon="log.action === 'submit' ? 'el-icon-s-promotion' : (log.action === 'approve' ? 'el-icon-check' : 'el-icon-close')">
<div>
<strong>{{ log.action === 'submit' ? '提交送审' : (log.action === 'approve' ? '审批通过' : '驳回') }}</strong>
<span v-if="log.operator"> {{ log.operator }}</span>
</div>
<div v-if="log.opinion" class="timeline-opinion">{{ log.opinion }}</div>
</el-timeline-item>
</el-timeline>
</el-card>
</div>
</div>
<!-- 编辑弹窗 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="900px" :close-on-click-modal="false" append-to-body>
<el-form ref="form" :model="editForm" :rules="rules" label-width="100px" size="small">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产品名称" prop="productName">
<el-input v-model="editForm.productName" placeholder="如:镀锌产品" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="传递部门" prop="transmitDept">
<el-input v-model="editForm.transmitDept" placeholder="品质部" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="传递人" prop="transmitUser">
<el-input v-model="editForm.transmitUser" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="传递日期" prop="transmitDate">
<el-date-picker v-model="editForm.transmitDate" type="date" placeholder="选择日期" style="width:100%;" />
</el-form-item>
</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>
<!-- ===== 钢卷选择 ===== -->
<div class="dialog-section">
<div class="dialog-section-header">
<span>问题钢卷</span>
</div>
<el-table :data="editForm.coilList" border style="width:100%" size="small" max-height="250">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="currentCoilNo" label="产品卷号" min-width="130" />
<el-table-column prop="supplierCoilNo" label="原料卷号" min-width="130" />
<el-table-column prop="spec" label="规格(mm)" width="100" />
<el-table-column prop="netWeight" label="卷重(t)" width="80" align="right" />
<el-table-column prop="defectDesc" label="缺陷描述" min-width="160">
<template slot-scope="scope">
<el-input v-model="scope.row.defectDesc" size="mini" placeholder="输入缺陷描述" />
</template>
</el-table-column>
<el-table-column label="操作" width="60" align="center">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="editForm.coilList.splice(scope.$index, 1)"></el-button>
</template>
</el-table-column>
</el-table>
<div v-if="editForm.coilList.length === 0" class="dialog-table-empty" style="cursor:pointer;" @click="showCoilSelector = true">请选择O级钢卷</div>
</div>
<!-- ===== 钢卷选择器嵌套在弹窗内 ===== -->
<CoilSelector
:visible.sync="showCoilSelector"
:multiple="true"
:filters="{ qualityStatusCsv: 'O', status: 0 }"
@confirm="onDialogCoilConfirm" />
<el-divider />
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="品质部意见" prop="deptOpinion">
<el-input type="textarea" :rows="3" v-model="editForm.deptOpinion" placeholder="请填写品质部评审意见" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="签字人">
<el-input v-model="editForm.deptSign" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="签字日期">
<el-date-picker v-model="editForm.deptSignDate" type="date" placeholder="选择日期" style="width:100%;" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="saveForm">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { listQualityReview, getQualityReview, addQualityReview, updateQualityReview, delQualityReview,
submitQualityReview, approveQualityReview, rejectQualityReview, executeQualityReview,
listQualityReviewCoil, listQualityReviewLog } from '@/api/mes/qc/qualityReview'
import CoilSelector from '@/components/CoilSelector'
export default {
name: 'QualityReview',
components: { CoilSelector },
dicts: ['quality_review_status', 'regrade_quality_type', 'coil_quality_status'],
data() {
return {
// 列表
loading: false,
dataList: [],
total: 0,
queryParams: {
pageNum: 1,
pageSize: 20,
reviewNo: undefined,
flowStatus: undefined
},
currentRow: null,
// 详情
detailLoading: false,
coilList: [],
logList: [],
// 钢卷选择
showCoilSelector: false,
// 品质部意见编辑独立于editForm避免串数据
opinionForm: {
deptOpinion: '',
deptSign: '',
deptSignDate: undefined
},
// 编辑弹窗
dialogVisible: false,
dialogTitle: '',
editing: false,
editForm: {
reviewId: undefined,
productName: '',
transmitDept: '品质部',
transmitUser: '',
transmitDate: undefined,
prodDateRange: '',
deptOpinion: '',
deptSign: '',
deptSignDate: undefined,
coilList: []
},
rules: {
productName: [{ required: true, message: '请输入产品名称', trigger: 'blur' }]
},
// 审批
approveAction: 'approve',
approveForm: {
reviewId: undefined,
leaderOpinion: '',
leaderSign: ''
},
approveCoilMap: {},
rejectReason: ''
}
},
created() {
this.getList()
},
methods: {
// ===== 列表 =====
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
getList() {
this.loading = true
listQualityReview(this.queryParams).then(res => {
this.dataList = res.rows || []
this.total = res.total || 0
this.loading = false
}).catch(() => { this.loading = false })
},
handleRowClick(row) {
this.currentRow = row
this.loadDetail(row.reviewId)
},
// ===== 详情 =====
loadDetail(reviewId) {
this.detailLoading = true
getQualityReview(reviewId).then(res => {
const data = res.data
this.currentRow = data
this.coilList = data.coilList || []
this.logList = data.logList || []
// 初始化审批表单数据先构建完整对象再赋值解决Vue2响应式问题
const map = {}
this.coilList.forEach(c => {
map[c.detailId] = c.regradeQuality || ''
})
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.leaderSign = ''
this.rejectReason = ''
this.detailLoading = false
}).catch(() => { this.detailLoading = false })
},
handleRefreshDetail() {
if (this.currentRow) {
this.loadDetail(this.currentRow.reviewId)
this.getList()
}
},
// ===== 新增/编辑 =====
handleAdd() {
this.dialogTitle = '新建质量评审单'
this.editForm = {
reviewId: undefined,
productName: '',
transmitDept: '品质部',
transmitUser: '',
transmitDate: undefined,
prodDateRange: '',
deptOpinion: '',
deptSign: '',
deptSignDate: undefined,
coilList: []
}
this.editing = true
this.dialogVisible = true
},
handleUpdate(row) {
this.dialogTitle = '编辑质量评审单'
this.editForm = {
reviewId: row.reviewId,
productName: row.productName,
transmitDept: row.transmitDept,
transmitUser: row.transmitUser,
transmitDate: row.transmitDate,
prodDateRange: row.prodDateRange,
deptOpinion: row.deptOpinion,
deptSign: row.deptSign,
deptSignDate: row.deptSignDate,
coilList: this.coilList.map(c => ({ ...c }))
}
this.editing = true
this.dialogVisible = true
},
saveForm() {
this.$refs.form.validate(valid => {
if (!valid) return
const data = { ...this.editForm, coilList: this.editForm.coilList || [] }
if (this.editForm.reviewId) {
updateQualityReview(data).then(() => {
this.$modal.msgSuccess('修改成功')
this.dialogVisible = false
this.handleRefreshDetail()
})
} else {
addQualityReview(data).then(() => {
this.$modal.msgSuccess('创建成功')
this.dialogVisible = false
this.getList()
})
}
})
},
// ===== 钢卷选择(弹窗内) =====
onDialogCoilConfirm(selected) {
if (!selected || selected.length === 0) return
const startIdx = this.editForm.coilList.length || 0
const newCoils = selected.map((coil, idx) => ({
coilId: coil.coilId,
currentCoilNo: coil.currentCoilNo,
supplierCoilNo: coil.supplierCoilNo || coil.enterCoilNo,
spec: coil.specification, // CoilSelector返回的字段名为specification
netWeight: coil.netWeight,
defectDesc: '',
groupSeq: startIdx + idx + 1,
beforeQuality: coil.qualityStatus || 'O'
}))
this.editForm.coilList = [...(this.editForm.coilList || []), ...newCoils]
},
handleRemoveCoil(index) {
this.coilList.splice(index, 1)
},
// ===== 提交送审 =====
handleSubmit() {
this.$confirm('确认提交送审?', '提示', { type: 'warning' }).then(() => {
submitQualityReview(this.currentRow.reviewId).then(() => {
this.$modal.msgSuccess('送审成功')
this.handleRefreshDetail()
})
}).catch(() => {})
},
handleReSubmit() {
this.$confirm('确认重新提交?提交后将进入待审批状态。', '提示', { type: 'warning' }).then(() => {
submitQualityReview(this.currentRow.reviewId).then(() => {
this.$modal.msgSuccess('送审成功')
this.handleRefreshDetail()
})
}).catch(() => {})
},
// ===== 审批 =====
doApprove() {
if (!this.approveForm.leaderOpinion) {
this.$modal.msgError('请输入审批意见')
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.handleRefreshDetail()
})
}).catch(() => {})
},
doReject() {
if (!this.rejectReason) {
this.$modal.msgError('请输入驳回原因')
return
}
this.$confirm('确认驳回该评审单?', '提示', { type: 'warning' }).then(() => {
rejectQualityReview(this.currentRow.reviewId, this.rejectReason).then(() => {
this.$modal.msgSuccess('已驳回')
this.handleRefreshDetail()
})
}).catch(() => {})
},
// ===== 执行改判 =====
handleExecute() {
this.$confirm('确认执行改判?执行后钢卷质量状态将被更新。', '提示', { type: 'warning' }).then(() => {
executeQualityReview(this.currentRow.reviewId).then(() => {
this.$modal.msgSuccess('改判执行成功')
this.handleRefreshDetail()
})
}).catch(() => {})
},
// ===== 删除 =====
handleDelete(row) {
this.$confirm('确认删除评审单【' + (row.reviewNo || row.reviewId) + '】?', '提示', { type: 'warning' }).then(() => {
delQualityReview(row.reviewId).then(() => {
this.$modal.msgSuccess('删除成功')
if (this.currentRow && this.currentRow.reviewId === row.reviewId) {
this.currentRow = null
this.coilList = []
this.logList = []
}
this.getList()
})
}).catch(() => {})
},
// ===== 辅助 =====
hasPermi(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>
<style lang="scss">
.quality-review-container {
display: flex;
height: calc(100vh - 84px);
gap: 12px;
padding: 0;
.left-panel {
width: 320px;
min-width: 320px;
display: flex;
flex-direction: column;
background: #fff;
border-radius: 4px;
border: 1px solid #e4e7ed;
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 12px 0;
.header-title {
font-weight: 600;
font-size: 15px;
display: flex;
align-items: center;
gap: 6px;
}
.header-filter { width: 130px; }
}
.search-row {
display: flex;
padding: 8px 12px;
gap: 6px;
.el-input { flex: 1; }
}
.list-body {
flex: 1;
overflow-y: auto;
padding: 0 8px;
}
.list-item {
padding: 10px 12px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
border-radius: 4px;
margin: 2px 0;
&:hover { background: #f5f7fa; }
&.active { background: #ecf5ff; }
.item-main {
display: flex;
justify-content: space-between;
align-items: center;
.item-title { font-weight: 500; font-size: 13px; }
.item-sub { font-size: 12px; color: #909399; }
}
.item-meta { margin-top: 4px; }
.item-actions {
margin-top: 4px;
text-align: right;
}
}
.list-empty {
text-align: center;
padding: 40px 0;
color: #c0c4cc;
i { font-size: 36px; display: block; margin-bottom: 8px; }
}
.list-footer { padding: 8px; }
}
.right-panel {
flex: 1;
background: #fff;
border-radius: 4px;
border: 1px solid #e4e7ed;
overflow-y: auto;
padding: 16px;
.empty-tip {
text-align: center;
padding: 80px 0;
color: #c0c4cc;
i { font-size: 48px; display: block; margin-bottom: 12px; }
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 12px;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px;
.detail-header-left {
display: flex;
align-items: center;
gap: 8px;
.detail-title { font-size: 16px; font-weight: 600; }
}
.detail-header-actions { display: flex; gap: 4px; flex-wrap: wrap; }
}
.detail-section {
margin-bottom: 12px;
.basic-form .el-form-item { margin-bottom: 0; }
}
.section-editor {
.approve-coil-section {
background: #fafafa;
padding: 12px;
border-radius: 4px;
margin: 8px 0;
.approve-coil-title { font-weight: 500; margin-bottom: 8px; }
.approve-coil-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 6px;
.approve-coil-label { min-width: 200px; font-size: 13px; }
}
}
}
.section-display {
.opinion-text {
background: #fafafa;
padding: 12px;
border-radius: 4px;
line-height: 1.6;
white-space: pre-wrap;
}
.opinion-footer {
margin-top: 8px;
display: flex;
gap: 20px;
color: #909399;
font-size: 13px;
}
.reject-reason { margin-top: 12px; }
}
.dialog-section {
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 12px;
margin-bottom: 16px;
.dialog-section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
font-weight: 600;
font-size: 14px;
}
.dialog-table-empty {
text-align: center;
padding: 20px;
color: #c0c4cc;
font-size: 13px;
}
}
.text-muted { color: #c0c4cc; }
.timeline-opinion {
font-size: 13px;
color: #606266;
margin-top: 4px;
background: #f5f7fa;
padding: 6px 10px;
border-radius: 4px;
}
}
}
</style>