<template>
|
<div class="app-container metric-binding">
|
<!-- 左侧:检测标准列表(只读) -->
|
<div class="left-panel">
|
<PIMTable
|
rowKey="id"
|
:column="standardColumns"
|
:tableData="standardTableData"
|
:page="page"
|
:isSelection="false"
|
:rowClassName="rowClassNameCenter"
|
:tableLoading="tableLoading"
|
@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" @click="openBindingDialog">添加绑定</el-button>
|
<el-button type="danger" plain :disabled="!currentStandard" @click="handleBatchUnbind">删除</el-button>
|
</div>
|
|
<el-table
|
v-loading="bindingLoading"
|
:data="bindingTableData"
|
border
|
:row-class-name="() => 'row-center'"
|
class="center-table"
|
style="width: 100%"
|
height="calc(100vh - 220px)"
|
@selection-change="handleBindingSelectionChange"
|
>
|
<el-table-column type="selection" width="48" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column prop="productName" label="产品名称" min-width="140" />
|
<el-table-column label="操作" width="120" fixed="right" align="center">
|
<template #default="{ row }">
|
<el-button link type="danger" size="small" @click="handleUnbind(row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
|
<!-- 添加绑定弹框 -->
|
<el-dialog
|
v-model="bindingDialogVisible"
|
title="添加绑定"
|
width="520px"
|
@close="closeBindingDialog"
|
>
|
<el-form label-width="100px">
|
<el-form-item label="产品">
|
<el-tree-select
|
v-model="selectedProductIds"
|
multiple
|
collapse-tags
|
collapse-tags-tooltip
|
placeholder="请选择产品(可多选)"
|
clearable
|
check-strictly
|
:data="productOptions"
|
:render-after-expand="false"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="closeBindingDialog">取消</el-button>
|
<el-button type="primary" @click="submitBinding">确定</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { Search } from '@element-plus/icons-vue'
|
import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
|
import { ElMessageBox } from 'element-plus'
|
import PIMTable from '@/components/PIMTable/PIMTable.vue'
|
import { productTreeList } from '@/api/basicData/product.js'
|
import {
|
qualityTestStandardListPage
|
} from '@/api/qualityManagement/metricMaintenance.js'
|
import { productProcessListPage } from '@/api/basicData/productProcess.js'
|
import {
|
qualityTestStandardBindingList,
|
qualityTestStandardBindingAdd,
|
qualityTestStandardBindingDel
|
} from '@/api/qualityManagement/qualityTestStandardBinding.js'
|
|
const { proxy } = getCurrentInstance()
|
|
// 左侧标准列表:整行内容居中(配合样式)
|
const rowClassNameCenter = () => 'row-center'
|
|
const data = reactive({
|
searchForm: {
|
standardNo: '',
|
standardName: '',
|
state: '',
|
inspectType: ''
|
}
|
})
|
const { searchForm } = toRefs(data)
|
|
// 左侧
|
const standardTableData = 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 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',
|
dataType: 'tag',
|
formatData: (val) => {
|
const target = processOptions.value.find(
|
(item) => String(item.value) === String(val)
|
)
|
return target?.label || val
|
}
|
},
|
{
|
label: '备注',
|
prop: 'remark',
|
minWidth: 160
|
}
|
// {
|
// label: '状态',
|
// prop: 'state',
|
// headerSlot: 'stateHeader',
|
// dataType: 'tag',
|
// formatData: (val) => {
|
// const map = { 0: '草稿', 1: '通过', 2: '撤销' }
|
// return map[val] || val
|
// },
|
// formatType: (val) => {
|
// if (val == 1) return 'success'
|
// if (val == 2) return 'warning'
|
// return 'info'
|
// }
|
// }
|
])
|
|
const currentStandard = ref(null)
|
|
// 右侧绑定
|
const bindingTableData = ref([])
|
const bindingLoading = ref(false)
|
const bindingSelectedRows = ref([])
|
const bindingDialogVisible = ref(false)
|
|
// 产品树(用于绑定选择)
|
const productOptions = ref([])
|
const selectedProductIds = ref([])
|
|
const getProductOptions = async () => {
|
// 避免重复请求
|
if (productOptions.value?.length) return
|
const res = await productTreeList()
|
productOptions.value = convertIdToValue(Array.isArray(res) ? res : [])
|
}
|
|
function convertIdToValue(data) {
|
return (data || []).map((item) => {
|
const { id, children, ...rest } = item
|
const newItem = {
|
...rest,
|
value: id
|
}
|
if (children && children.length > 0) {
|
newItem.children = convertIdToValue(children)
|
}
|
return newItem
|
})
|
}
|
|
const handleQuery = () => {
|
page.current = 1
|
getStandardList()
|
}
|
|
const handlePagination = (obj) => {
|
page.current = obj.page
|
page.size = obj.limit
|
getStandardList()
|
}
|
|
const getStandardList = () => {
|
tableLoading.value = true
|
qualityTestStandardListPage({
|
...searchForm.value,
|
current: page.current,
|
size: page.size,
|
state: 1
|
})
|
.then((res) => {
|
const records = res?.data?.records || []
|
standardTableData.value = records
|
page.total = res?.data?.total || records.length
|
})
|
.finally(() => {
|
tableLoading.value = false
|
})
|
}
|
|
const handleStandardRowClick = (row) => {
|
currentStandard.value = row
|
loadBindingList()
|
}
|
|
const loadBindingList = () => {
|
if (!currentStandard.value?.id) {
|
bindingTableData.value = []
|
return
|
}
|
bindingLoading.value = true
|
qualityTestStandardBindingList({ testStandardId: currentStandard.value.id })
|
.then((res) => {
|
const base = res?.data || []
|
// 将当前标准的工序和备注带到绑定列表中展示
|
bindingTableData.value = base.map((item) => ({
|
...item,
|
processId: currentStandard.value?.processId,
|
remark: currentStandard.value?.remark
|
}))
|
})
|
.finally(() => {
|
bindingLoading.value = false
|
})
|
}
|
|
const handleBindingSelectionChange = (selection) => {
|
bindingSelectedRows.value = selection
|
}
|
|
const openBindingDialog = () => {
|
if (!currentStandard.value?.id) return
|
selectedProductIds.value = []
|
getProductOptions()
|
bindingDialogVisible.value = true
|
}
|
|
const closeBindingDialog = () => {
|
bindingDialogVisible.value = false
|
}
|
|
const submitBinding = async () => {
|
const testStandardId = currentStandard.value?.id
|
if (!testStandardId) return
|
const ids = (selectedProductIds.value || []).filter(Boolean)
|
if (!ids.length) {
|
proxy.$message.warning('请选择产品')
|
return
|
}
|
const payload = ids.map((pid) => ({
|
productId: pid,
|
testStandardId
|
}))
|
await qualityTestStandardBindingAdd(payload)
|
proxy.$message.success('添加成功')
|
bindingDialogVisible.value = false
|
loadBindingList()
|
}
|
|
const handleUnbind = async (row) => {
|
if (!row?.id) return
|
try {
|
await ElMessageBox.confirm('确认删除该绑定?', '提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardBindingDel([row.qualityTestStandardBindingId])
|
proxy.$message.success('删除成功')
|
loadBindingList()
|
}
|
|
const handleBatchUnbind = async () => {
|
if (!bindingSelectedRows.value.length) {
|
proxy.$message.warning('请选择数据')
|
return
|
}
|
const ids = bindingSelectedRows.value.map((i) => i.qualityTestStandardBindingId)
|
try {
|
await ElMessageBox.confirm('选中的内容将被删除,是否确认删除?', '删除提示', { type: 'warning' })
|
} catch {
|
return
|
}
|
await qualityTestStandardBindingDel(ids)
|
proxy.$message.success('删除成功')
|
loadBindingList()
|
}
|
|
onMounted(() => {
|
getStandardList()
|
getProcessList()
|
})
|
</script>
|
|
<style scoped>
|
.metric-binding {
|
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-right {
|
flex-shrink: 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>
|