<template>
|
<div class="app-container metric-maintenance">
|
<!-- 左侧:检测标准列表 -->
|
<div class="left-panel">
|
<div class="toolbar">
|
<div class="toolbar-left"></div>
|
<div class="toolbar-right">
|
<el-button type="primary" @click="openStandardDialog('add')">新增</el-button>
|
<el-button type="success" plain @click="handleBatchAudit(1)">批准</el-button>
|
<el-button type="warning" plain @click="handleBatchAudit(2)">撤销</el-button>
|
<el-button type="danger" plain @click="handleBatchDelete">删除</el-button>
|
</div>
|
</div>
|
<PIMTable
|
rowKey="id"
|
:column="standardColumns"
|
:tableData="standardTableData"
|
:page="page"
|
:isSelection="true"
|
:tableLoading="tableLoading"
|
:rowClassName="rowClassNameCenter"
|
@selection-change="handleSelectionChange"
|
@pagination="handlePagination"
|
:total="page.total"
|
>
|
<template #standardNoCell="{ row }">
|
<span class="clickable-link" @click="handleStandardRowClick(row)">
|
{{ row.standardNo }}
|
</span>
|
</template>
|
|
<!-- 表头搜索插槽 -->
|
<template #standardNoHeader>
|
<el-input
|
v-model="searchForm.standardNo"
|
placeholder="标准编号"
|
clearable
|
size="small"
|
@change="handleQuery"
|
@clear="handleQuery"
|
/>
|
</template>
|
<template #standardNameHeader>
|
<el-input
|
v-model="searchForm.standardName"
|
placeholder="标准名称"
|
clearable
|
size="small"
|
@change="handleQuery"
|
@clear="handleQuery"
|
/>
|
</template>
|
<template #inspectTypeHeader>
|
<el-select
|
v-model="searchForm.inspectType"
|
placeholder="类别"
|
clearable
|
size="small"
|
style="width: 120px"
|
@change="handleQuery"
|
@clear="handleQuery"
|
>
|
<el-option label="原材料检验" value="0" />
|
<el-option label="过程检验" value="1" />
|
<el-option label="出厂检验" value="2" />
|
</el-select>
|
</template>
|
<template #stateHeader>
|
<el-select
|
v-model="searchForm.state"
|
placeholder="状态"
|
clearable
|
size="small"
|
style="width: 110px"
|
@change="handleQuery"
|
@clear="handleQuery"
|
>
|
<el-option label="草稿" value="0" />
|
<el-option label="通过" value="1" />
|
<el-option label="撤销" value="2" />
|
</el-select>
|
</template>
|
</PIMTable>
|
</div>
|
|
<!-- 右侧:标准参数列表 -->
|
<div class="right-panel">
|
<div class="right-header">
|
<div class="title">标准参数</div>
|
<div class="desc" v-if="currentStandard">
|
您当前选择的检测标准编号是:
|
<span class="link-text">{{ currentStandard.standardNo }}</span>
|
</div>
|
<div class="desc" v-else>请先在左侧选择一个检测标准</div>
|
</div>
|
|
<div class="right-toolbar">
|
<el-button type="primary" :disabled="!currentStandard || isStandardReadonly" @click="openParamDialog('add')">
|
新增
|
</el-button>
|
<el-button type="danger" plain :disabled="!currentStandard || isStandardReadonly" @click="handleParamBatchDelete">
|
删除
|
</el-button>
|
</div>
|
|
<el-table
|
v-loading="detailLoading"
|
:data="detailTableData"
|
border
|
:row-class-name="() => 'row-center'"
|
class="center-table"
|
style="width: 100%"
|
height="calc(100vh - 220px)"
|
@selection-change="handleParamSelectionChange"
|
>
|
<el-table-column type="selection" width="48" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column prop="parameterItem" label="参数项" min-width="120" />
|
<el-table-column prop="unit" label="单位" width="80" />
|
<el-table-column prop="standardValue" label="标准值" min-width="120" />
|
<el-table-column prop="controlValue" label="内控值" min-width="120" />
|
<el-table-column prop="defaultValue" label="默认值" min-width="120" />
|
<el-table-column label="操作" width="140" fixed="right" align="center">
|
<template #default="{ row }">
|
<el-button link type="primary" size="small" :disabled="isStandardReadonly" @click="openParamDialog('edit', row)">
|
编辑
|
</el-button>
|
<el-button link type="danger" size="small" :disabled="isStandardReadonly" @click="handleParamDelete(row)">
|
删除
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
|
<!-- 新增 / 编辑检测标准 -->
|
<StandardFormDialog
|
ref="standardFormDialogRef"
|
v-model="standardDialogVisible"
|
:operation-type="standardOperationType"
|
:form="standardForm"
|
:rules="standardRules"
|
:process-options="processOptions"
|
@confirm="submitStandardForm"
|
@close="closeStandardDialog"
|
@cancel="closeStandardDialog"
|
/>
|
|
<ParamFormDialog
|
ref="paramFormDialogRef"
|
v-model="paramDialogVisible"
|
:operation-type="paramOperationType"
|
:form="paramForm"
|
@confirm="submitParamForm"
|
@close="closeParamDialog"
|
@cancel="closeParamDialog"
|
/>
|
</div>
|
</template>
|
|
<script setup>
|
import { Search } from '@element-plus/icons-vue'
|
import { ref, reactive, toRefs, onMounted, getCurrentInstance, computed } from 'vue'
|
import { ElMessageBox } from 'element-plus'
|
import {
|
qualityTestStandardListPage,
|
qualityTestStandardAdd,
|
qualityTestStandardUpdate,
|
qualityTestStandardDel,
|
qualityTestStandardCopyParam,
|
qualityTestStandardAudit,
|
qualityTestStandardParamList,
|
qualityTestStandardParamAdd,
|
qualityTestStandardParamUpdate,
|
qualityTestStandardParamDel
|
} from '@/api/qualityManagement/metricMaintenance.js'
|
import { productProcessListPage } from '@/api/basicData/productProcess.js'
|
import StandardFormDialog from './StandardFormDialog.vue'
|
import ParamFormDialog from './ParamFormDialog.vue'
|
|
const { proxy } = getCurrentInstance()
|
|
// 左侧标准列表:整行内容居中(配合样式)
|
const rowClassNameCenter = () => 'row-center'
|
|
// 标准状态为“通过(1)”时,右侧参数禁止增删改
|
const isStandardReadonly = computed(() => {
|
const state = currentStandard.value?.state
|
return state === 1 || state === '1'
|
})
|
|
// 搜索条件
|
const data = reactive({
|
searchForm: {
|
standardNo: '',
|
standardName: '',
|
remark: '',
|
state: '',
|
inspectType: '',
|
processId: ''
|
},
|
standardForm: {
|
id: undefined,
|
standardNo: '',
|
standardName: '',
|
remark: '',
|
state: '0',
|
inspectType: '',
|
processId: ''
|
},
|
standardRules: {
|
standardNo: [{ required: true, message: '请输入标准编号', trigger: 'blur' }],
|
standardName: [{ required: true, message: '请输入标准名称', trigger: 'blur' }],
|
inspectType: [{ required: true, message: '请选择检测类型', trigger: 'change' }],
|
processId: [{ required: true, message: '请选择工序', trigger: 'change' }]
|
}
|
})
|
|
const { searchForm, standardForm, standardRules } = toRefs(data)
|
|
// 左侧表格
|
const standardTableData = ref([])
|
const selectedRows = ref([])
|
const tableLoading = ref(false)
|
const page = reactive({
|
current: 1,
|
size: 10,
|
total: 0
|
})
|
|
// 工序下拉
|
const processOptions = ref([])
|
|
// 获取工序列表
|
const getProcessList = async () => {
|
try {
|
const res = await productProcessListPage({ current: 1, size: 1000 })
|
if (res?.code === 200) {
|
const records = res?.data?.records || []
|
processOptions.value = records.map(item => ({
|
label: item.processName || item.name || item.label,
|
value: item.id || item.processId || item.value
|
}))
|
}
|
} catch (error) {
|
console.error('获取工序列表失败:', error)
|
}
|
}
|
|
// 当前选中的标准 & 右侧详情
|
const currentStandard = ref(null)
|
const detailTableData = ref([])
|
const detailLoading = ref(false)
|
const paramSelectedRows = ref([])
|
const paramDialogVisible = ref(false)
|
const paramOperationType = ref('add') // add | edit
|
const paramFormDialogRef = ref(null)
|
const paramForm = reactive({
|
id: undefined,
|
parameterItem: '',
|
unit: '',
|
standardValue: '',
|
controlValue: '',
|
defaultValue: ''
|
})
|
|
// 弹窗
|
const standardDialogVisible = ref(false)
|
const standardOperationType = ref('add') // add | edit | copy
|
const standardFormDialogRef = ref(null)
|
|
// 列定义
|
const standardColumns = ref([
|
{
|
label: '标准编号',
|
prop: 'standardNo',
|
dataType: 'slot',
|
slot: 'standardNoCell',
|
minWidth: 160,
|
headerSlot: 'standardNoHeader'
|
},
|
{
|
label: '标准名称',
|
prop: 'standardName',
|
minWidth: 180,
|
headerSlot: 'standardNameHeader'
|
},
|
{
|
label: '类别',
|
prop: 'inspectType',
|
headerSlot: 'inspectTypeHeader',
|
dataType: 'tag',
|
formatData: (val) => {
|
const map = {
|
0: '原材料检验',
|
1: '过程检验',
|
2: '出厂检验'
|
}
|
return map[val] || val
|
}
|
},
|
{
|
label: '工序',
|
prop: 'processId'
|
},
|
{
|
label: '状态',
|
prop: 'state',
|
headerSlot: 'stateHeader',
|
dataType: 'tag',
|
formatData: (val) => {
|
const map = {
|
0: '草稿',
|
1: '通过',
|
2: '撤销'
|
}
|
return map[val] || val
|
},
|
formatType: (val) => {
|
if (val === '1' || val === 1) return 'success'
|
if (val === '2' || val === 2) return 'warning'
|
return 'info'
|
}
|
},
|
{
|
label: '备注',
|
prop: 'remark',
|
minWidth: 160
|
},
|
{
|
dataType: 'action',
|
label: '操作',
|
align: 'center',
|
fixed: 'right',
|
width: 220,
|
operation: [
|
{
|
name: '编辑',
|
type: 'text',
|
clickFun: (row) => {
|
openStandardDialog('edit', row)
|
}
|
},
|
{
|
name: '复制',
|
type: 'text',
|
clickFun: async (row) => {
|
if (!row?.id) return
|
try {
|
await ElMessageBox.confirm('确认复制该标准参数?', '提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardCopyParam(row.id)
|
proxy.$message.success('复制成功')
|
getStandardList()
|
if (currentStandard.value?.id === row.id) {
|
loadDetail(row.id)
|
}
|
}
|
},
|
{
|
name: '删除',
|
type: 'text',
|
clickFun: (row) => {
|
handleDelete(row)
|
}
|
}
|
]
|
}
|
])
|
|
// 查询列表
|
const getStandardList = () => {
|
tableLoading.value = true
|
const params = {
|
...searchForm.value,
|
current: page.current,
|
size: page.size
|
}
|
qualityTestStandardListPage(params)
|
.then((res) => {
|
const records = res?.data?.records || []
|
standardTableData.value = records
|
page.total = res?.data?.total || records.length
|
})
|
.finally(() => {
|
tableLoading.value = false
|
})
|
}
|
|
const handleQuery = () => {
|
page.current = 1
|
getStandardList()
|
}
|
|
const resetQuery = () => {
|
searchForm.value.standardNo = ''
|
searchForm.value.standardName = ''
|
searchForm.value.remark = ''
|
searchForm.value.state = ''
|
searchForm.value.inspectType = ''
|
searchForm.value.processId = ''
|
handleQuery()
|
}
|
|
const handlePagination = (obj) => {
|
page.current = obj.page
|
page.size = obj.limit
|
getStandardList()
|
}
|
|
const handleSelectionChange = (selection) => {
|
selectedRows.value = selection
|
}
|
|
// 批量审核:状态 1=批准,2=撤销
|
const handleBatchAudit = async (state) => {
|
if (!selectedRows.value.length) {
|
proxy.$message.warning('请选择数据')
|
return
|
}
|
const text = state === 1 ? '批准' : '撤销'
|
const payload = selectedRows.value
|
.filter(i => i?.id)
|
.map((item) => ({ id: item.id, state }))
|
|
if (!payload.length) {
|
proxy.$message.warning('请选择有效数据')
|
return
|
}
|
|
try {
|
await ElMessageBox.confirm(`确认${text}选中的标准?`, '提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardAudit(payload)
|
proxy.$message.success(`${text}成功`)
|
getStandardList()
|
}
|
|
// 左侧行点击,加载右侧参数
|
const handleStandardRowClick = (row) => {
|
currentStandard.value = row
|
loadDetail(row.id)
|
}
|
|
const loadDetail = (standardId) => {
|
if (!standardId) {
|
detailTableData.value = []
|
return
|
}
|
detailLoading.value = true
|
qualityTestStandardParamList({ testStandardId: standardId }).then((res) => {
|
detailTableData.value = res?.data || []
|
})
|
.finally(() => {
|
detailLoading.value = false
|
})
|
}
|
|
const handleParamSelectionChange = (selection) => {
|
paramSelectedRows.value = selection
|
}
|
|
const openParamDialog = (type, row) => {
|
if (!currentStandard.value?.id) return
|
if (isStandardReadonly.value) {
|
proxy.$message.warning('该标准已通过,参数不可编辑')
|
return
|
}
|
paramOperationType.value = type
|
if (type === 'add') {
|
Object.assign(paramForm, {
|
id: undefined,
|
parameterItem: '',
|
unit: '',
|
standardValue: '',
|
controlValue: '',
|
defaultValue: ''
|
})
|
} else if (type === 'edit' && row) {
|
Object.assign(paramForm, row)
|
}
|
paramDialogVisible.value = true
|
}
|
|
const closeParamDialog = () => {
|
paramDialogVisible.value = false
|
paramFormDialogRef.value?.resetFields?.()
|
}
|
|
const submitParamForm = async () => {
|
const testStandardId = currentStandard.value?.id
|
if (!testStandardId) return
|
if (isStandardReadonly.value) {
|
proxy.$message.warning('该标准已通过,参数不可编辑')
|
return
|
}
|
const payload = { ...paramForm, testStandardId }
|
if (paramOperationType.value === 'edit') {
|
await qualityTestStandardParamUpdate(payload)
|
proxy.$message.success('提交成功')
|
} else {
|
await qualityTestStandardParamAdd(payload)
|
proxy.$message.success('提交成功')
|
}
|
closeParamDialog()
|
loadDetail(testStandardId)
|
}
|
|
const handleParamDelete = async (row) => {
|
if (!row?.id) return
|
if (isStandardReadonly.value) {
|
proxy.$message.warning('该标准已通过,参数不可编辑')
|
return
|
}
|
try {
|
await ElMessageBox.confirm('确认删除该参数?', '提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardParamDel([row.id])
|
proxy.$message.success('删除成功')
|
loadDetail(currentStandard.value?.id)
|
}
|
|
const handleParamBatchDelete = async () => {
|
if (isStandardReadonly.value) {
|
proxy.$message.warning('该标准已通过,参数不可编辑')
|
return
|
}
|
if (!paramSelectedRows.value.length) {
|
proxy.$message.warning('请选择数据')
|
return
|
}
|
const ids = paramSelectedRows.value.map((i) => i.id)
|
try {
|
await ElMessageBox.confirm('选中的内容将被删除,是否确认删除?', '删除提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardParamDel(ids)
|
proxy.$message.success('删除成功')
|
loadDetail(currentStandard.value?.id)
|
}
|
|
// 新增 / 编辑 / 复制
|
const openStandardDialog = (type, row) => {
|
standardOperationType.value = type
|
if (type === 'add') {
|
Object.assign(standardForm.value, {
|
id: undefined,
|
standardNo: '',
|
standardName: '',
|
remark: '',
|
state: '0',
|
inspectType: '',
|
processId: ''
|
})
|
} else if (type === 'edit' && row) {
|
Object.assign(standardForm.value, row)
|
} else if (type === 'copy' && row) {
|
const { id, ...rest } = row
|
Object.assign(standardForm.value, {
|
...rest,
|
id: undefined,
|
standardNo: '',
|
state: '0'
|
})
|
}
|
standardDialogVisible.value = true
|
}
|
|
const closeStandardDialog = () => {
|
standardDialogVisible.value = false
|
standardFormDialogRef.value?.resetFields?.()
|
}
|
|
const submitStandardForm = () => {
|
const payload = { ...standardForm.value }
|
const isEdit = standardOperationType.value === 'edit'
|
if (isEdit) {
|
qualityTestStandardUpdate(payload).then(() => {
|
proxy.$message.success('提交成功')
|
standardDialogVisible.value = false
|
getStandardList()
|
})
|
} else {
|
qualityTestStandardAdd(payload).then(() => {
|
proxy.$message.success('提交成功')
|
standardDialogVisible.value = false
|
getStandardList()
|
})
|
}
|
}
|
|
// 删除(单条)
|
const handleDelete = (row) => {
|
const ids = [row.id]
|
ElMessageBox.confirm('选中的内容将被删除,是否确认删除?', '删除提示', {
|
confirmButtonText: '确认',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
.then(() => {
|
tableLoading.value = true
|
qualityTestStandardDel(ids)
|
.then(() => {
|
proxy.$message.success('删除成功')
|
getStandardList()
|
if (currentStandard.value && currentStandard.value.id === row.id) {
|
currentStandard.value = null
|
detailTableData.value = []
|
}
|
})
|
.finally(() => {
|
tableLoading.value = false
|
})
|
})
|
.catch(() => {
|
proxy.$modal?.msg('已取消')
|
})
|
}
|
|
// 批量删除
|
const handleBatchDelete = () => {
|
if (!selectedRows.value.length) {
|
proxy.$message.warning('请选择数据')
|
return
|
}
|
const ids = selectedRows.value.map((item) => item.id)
|
ElMessageBox.confirm('选中的内容将被删除,是否确认删除?', '删除提示', {
|
confirmButtonText: '确认',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
.then(() => {
|
tableLoading.value = true
|
qualityTestStandardDel(ids)
|
.then(() => {
|
proxy.$message.success('删除成功')
|
getStandardList()
|
if (currentStandard.value && ids.includes(currentStandard.value.id)) {
|
currentStandard.value = null
|
detailTableData.value = []
|
}
|
})
|
.finally(() => {
|
tableLoading.value = false
|
})
|
})
|
.catch(() => {
|
proxy.$modal?.msg('已取消')
|
})
|
}
|
|
onMounted(() => {
|
getProcessList()
|
getStandardList()
|
})
|
</script>
|
|
<style scoped>
|
.metric-maintenance {
|
display: flex;
|
gap: 16px;
|
}
|
|
.left-panel,
|
.right-panel {
|
flex: 1;
|
background: #ffffff;
|
padding: 16px;
|
box-sizing: border-box;
|
}
|
|
.toolbar {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 12px;
|
}
|
|
.toolbar-left {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 4px;
|
}
|
|
.toolbar-right {
|
flex-shrink: 0;
|
}
|
|
.search-label {
|
margin: 0 4px 0 12px;
|
}
|
|
.search-label:first-of-type {
|
margin-left: 0;
|
}
|
|
.right-header {
|
display: flex;
|
align-items: baseline;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
|
.right-header .title {
|
font-size: 16px;
|
font-weight: 600;
|
}
|
|
.right-header .desc {
|
font-size: 13px;
|
color: #666;
|
}
|
|
.right-toolbar {
|
display: flex;
|
justify-content: flex-end;
|
gap: 10px;
|
margin-bottom: 10px;
|
}
|
|
.link-text {
|
color: #409eff;
|
cursor: default;
|
}
|
|
.clickable-link {
|
color: #409eff;
|
cursor: pointer;
|
}
|
|
.clickable-link:hover {
|
text-decoration: underline;
|
}
|
|
:deep(.row-center td) {
|
text-align: center !important;
|
}
|
|
/* el-table 表头/内容统一居中(row-class-name 不作用于表头) */
|
:deep(.center-table .el-table__header-wrapper th .cell) {
|
text-align: center !important;
|
}
|
:deep(.center-table .el-table__body-wrapper td .cell) {
|
text-align: center !important;
|
}
|
</style>
|