From 9ea5ff67655241271bdf04bb50ca3a8d60c4e22a Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期二, 11 八月 2026 15:07:02 +0800
Subject: [PATCH] fix: 用河南鹤壁代码覆盖山西长治
---
src/views/qualityManagement/metricBinding/index.vue | 333 +++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 273 insertions(+), 60 deletions(-)
diff --git a/src/views/qualityManagement/metricBinding/index.vue b/src/views/qualityManagement/metricBinding/index.vue
index 80eb66f..ba989ea 100644
--- a/src/views/qualityManagement/metricBinding/index.vue
+++ b/src/views/qualityManagement/metricBinding/index.vue
@@ -1,7 +1,9 @@
<template>
<div class="app-container metric-binding">
- <!-- 宸︿晶锛氭娴嬫爣鍑嗗垪琛紙鍙锛� -->
- <div class="left-panel">
+ <el-row :gutter="16" class="metric-binding-row">
+ <!-- 宸︿晶锛氭娴嬫爣鍑嗗垪琛� -->
+ <el-col :xs="24" :sm="24" :md="12" :lg="14" :xl="14" class="left-col">
+ <div class="panel left-panel">
<PIMTable
rowKey="id"
:column="standardColumns"
@@ -10,6 +12,7 @@
:isSelection="false"
:rowClassName="rowClassNameCenter"
:tableLoading="tableLoading"
+ :rowClick="handleTableRowClick"
@pagination="handlePagination"
:total="page.total"
>
@@ -71,10 +74,12 @@
</el-select>
</template>
</PIMTable>
- </div>
+ </div>
+ </el-col>
- <!-- 鍙充晶锛氱粦瀹氬垪琛� -->
- <div class="right-panel">
+ <!-- 鍙充晶锛氱粦瀹氬垪琛� -->
+ <el-col :xs="24" :sm="24" :md="12" :lg="10" :xl="10" class="right-col">
+ <div class="panel right-panel">
<div class="right-header">
<div class="title">缁戝畾鍏崇郴</div>
<div class="desc" v-if="currentStandard">
@@ -107,31 +112,53 @@
</template>
</el-table-column>
</el-table>
- </div>
+ </div>
+ </el-col>
+ </el-row>
<!-- 娣诲姞缁戝畾寮规 -->
<el-dialog
v-model="bindingDialogVisible"
title="娣诲姞缁戝畾"
- width="520px"
+ width="640px"
@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>
+ <div class="binding-dialog">
+ <el-input
+ v-model="productSearchKeyword"
+ placeholder="鎼滅储浜у搧"
+ clearable
+ prefix-icon="Search"
+ class="binding-search"
+ />
+ <el-tree
+ ref="productTreeRef"
+ :key="productTreeKey"
+ v-loading="productTreeLoading"
+ :data="productTreeData"
+ show-checkbox
+ check-strictly
+ node-key="id"
+ :props="{ label: 'label', children: 'children', disabled: 'disabled' }"
+ :filter-node-method="filterProductNode"
+ class="product-binding-tree"
+ @check="handleProductTreeCheck"
+ />
+ <div v-if="selectedProductLabels.length" class="selected-products">
+ <div class="selected-title">宸查�夋嫨锛坽{ selectedProductLabels.length }}锛�</div>
+ <div class="selected-tags">
+ <el-tag
+ v-for="item in selectedProductLabels"
+ :key="item.id"
+ closable
+ type="info"
+ @close="removeSelectedProduct(item.id)"
+ >
+ {{ item.label }}
+ </el-tag>
+ </div>
+ </div>
+ </div>
<template #footer>
<span class="dialog-footer">
<el-button @click="closeBindingDialog">鍙栨秷</el-button>
@@ -143,14 +170,14 @@
</template>
<script setup>
-import { Search } from '@element-plus/icons-vue'
-import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
+import { ref, reactive, toRefs, computed, watch, nextTick, 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,
@@ -177,19 +204,56 @@
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: 'standardNo', dataType: 'slot', slot: 'standardNoCell', minWidth: 160, align: 'center', headerSlot: 'standardNoHeader' },
+ { label: '鏍囧噯鍚嶇О', prop: 'standardName', minWidth: 180, align: 'center', headerSlot: 'standardNameHeader' },
{
- label: '妫�娴嬬被鍨�',
+ label: '绫诲埆',
prop: 'inspectType',
headerSlot: 'inspectTypeHeader',
+ align: 'center',
dataType: 'tag',
formatData: (val) => {
const map = { 0: '鍘熸潗鏂欐楠�', 1: '杩囩▼妫�楠�', 2: '鍑哄巶妫�楠�' }
return map[val] || val
}
},
+ {
+ label: '宸ュ簭',
+ prop: 'processId',
+ align: 'center',
+ dataType: 'tag',
+ formatData: (val) => {
+ const target = processOptions.value.find(
+ (item) => String(item.value) === String(val)
+ )
+ return target?.label || val
+ }
+ },
+ {
+ label: '澶囨敞',
+ prop: 'remark',
+ minWidth: 160,
+ align: 'center'
+ }
// {
// label: '鐘舵��',
// prop: 'state',
@@ -216,28 +280,74 @@
const bindingDialogVisible = ref(false)
// 浜у搧鏍戯紙鐢ㄤ簬缁戝畾閫夋嫨锛�
-const productOptions = ref([])
+const productTreeData = ref([])
+const productTreeLoading = ref(false)
+const productTreeRef = ref(null)
+const productTreeKey = ref(0)
+const productSearchKeyword = ref('')
const selectedProductIds = ref([])
-const getProductOptions = async () => {
- // 閬垮厤閲嶅璇锋眰
- if (productOptions.value?.length) return
- const res = await productTreeList()
- productOptions.value = convertIdToValue(Array.isArray(res) ? res : [])
+const markParentNodesDisabled = (nodes) => {
+ return (nodes || []).map((node) => {
+ const children = node.children?.length ? markParentNodesDisabled(node.children) : []
+ return {
+ ...node,
+ children,
+ disabled: children.length > 0
+ }
+ })
}
-function convertIdToValue(data) {
- return (data || []).map((item) => {
- const { id, children, ...rest } = item
- const newItem = {
- ...rest,
- value: id
+const buildProductLabelMap = (nodes, map = {}) => {
+ ;(nodes || []).forEach((node) => {
+ if (node.id != null) {
+ map[node.id] = node.label
}
- if (children && children.length > 0) {
- newItem.children = convertIdToValue(children)
+ if (node.children?.length) {
+ buildProductLabelMap(node.children, map)
}
- return newItem
})
+ return map
+}
+
+const productLabelMap = computed(() => buildProductLabelMap(productTreeData.value))
+
+const selectedProductLabels = computed(() =>
+ selectedProductIds.value.map((id) => ({
+ id,
+ label: productLabelMap.value[id] || id
+ }))
+)
+
+const filterProductNode = (value, data) => {
+ if (!value) return true
+ return String(data.label || '').includes(value)
+}
+
+watch(productSearchKeyword, (val) => {
+ productTreeRef.value?.filter(val)
+})
+
+const getProductTreeData = async () => {
+ if (productTreeData.value?.length) return
+ productTreeLoading.value = true
+ try {
+ const res = await productTreeList()
+ productTreeData.value = markParentNodesDisabled(Array.isArray(res) ? res : [])
+ } catch (error) {
+ console.error('鑾峰彇浜у搧鏍戝け璐�:', error)
+ } finally {
+ productTreeLoading.value = false
+ }
+}
+
+const handleProductTreeCheck = () => {
+ selectedProductIds.value = productTreeRef.value?.getCheckedKeys(true) || []
+}
+
+const removeSelectedProduct = (id) => {
+ selectedProductIds.value = selectedProductIds.value.filter((item) => item !== id)
+ productTreeRef.value?.setChecked(id, false, false)
}
const handleQuery = () => {
@@ -269,6 +379,13 @@
})
}
+// 琛ㄦ牸琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃
+const handleTableRowClick = (row) => {
+ currentStandard.value = row
+ loadBindingList()
+}
+
+// 宸︿晶琛岀偣鍑伙紝鍔犺浇鍙充晶缁戝畾鍒楄〃锛堜繚鐣欑敤浜庢爣鍑嗙紪鍙峰垪鐨勭偣鍑伙級
const handleStandardRowClick = (row) => {
currentStandard.value = row
loadBindingList()
@@ -282,7 +399,13 @@
bindingLoading.value = true
qualityTestStandardBindingList({ testStandardId: currentStandard.value.id })
.then((res) => {
- bindingTableData.value = res?.data || []
+ const base = res?.data || []
+ // 灏嗗綋鍓嶆爣鍑嗙殑宸ュ簭鍜屽娉ㄥ甫鍒扮粦瀹氬垪琛ㄤ腑灞曠ず
+ bindingTableData.value = base.map((item) => ({
+ ...item,
+ processId: currentStandard.value?.processId,
+ remark: currentStandard.value?.remark
+ }))
})
.finally(() => {
bindingLoading.value = false
@@ -296,12 +419,20 @@
const openBindingDialog = () => {
if (!currentStandard.value?.id) return
selectedProductIds.value = []
- getProductOptions()
+ productSearchKeyword.value = ''
+ productTreeKey.value += 1
bindingDialogVisible.value = true
+ nextTick(() => {
+ productTreeRef.value?.setCheckedKeys([])
+ productTreeRef.value?.filter('')
+ })
}
const closeBindingDialog = () => {
bindingDialogVisible.value = false
+ selectedProductIds.value = []
+ productSearchKeyword.value = ''
+ productTreeRef.value?.setCheckedKeys([])
}
const submitBinding = async () => {
@@ -323,15 +454,21 @@
}
const handleUnbind = async (row) => {
- if (!row?.id) return
+ const id = row?.id ?? row?.qualityTestStandardBindingId
+ if (id == null || id === '') return
try {
await ElMessageBox.confirm('纭鍒犻櫎璇ョ粦瀹氾紵', '鎻愮ず', { type: 'warning' })
} catch {
return
}
- await qualityTestStandardBindingDel([row.qualityTestStandardBindingId])
- proxy.$message.success('鍒犻櫎鎴愬姛')
- loadBindingList()
+ try {
+ await qualityTestStandardBindingDel([id])
+ proxy.$message.success('鍒犻櫎鎴愬姛')
+ loadBindingList()
+ } catch (err) {
+ console.error('鍒犻櫎缁戝畾澶辫触:', err)
+ proxy.$message?.error(err?.message || '鍒犻櫎澶辫触')
+ }
}
const handleBatchUnbind = async () => {
@@ -339,34 +476,56 @@
proxy.$message.warning('璇烽�夋嫨鏁版嵁')
return
}
- const ids = bindingSelectedRows.value.map((i) => i.qualityTestStandardBindingId)
+ const ids = bindingSelectedRows.value
+ .map((i) => i?.id ?? i?.qualityTestStandardBindingId)
+ .filter((id) => id != null && id !== '')
+ if (!ids.length) {
+ proxy.$message.warning('閫変腑鏁版嵁缂哄皯鏈夋晥 id')
+ return
+ }
try {
await ElMessageBox.confirm('閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�', '鍒犻櫎鎻愮ず', { type: 'warning' })
} catch {
return
}
- await qualityTestStandardBindingDel(ids)
- proxy.$message.success('鍒犻櫎鎴愬姛')
- loadBindingList()
+ try {
+ await qualityTestStandardBindingDel(ids)
+ proxy.$message.success('鍒犻櫎鎴愬姛')
+ loadBindingList()
+ } catch (err) {
+ console.error('鎵归噺鍒犻櫎缁戝畾澶辫触:', err)
+ proxy.$message?.error(err?.message || '鍒犻櫎澶辫触')
+ }
}
onMounted(() => {
getStandardList()
+ getProcessList()
+ getProductTreeData()
})
</script>
<style scoped>
-.metric-binding {
- display: flex;
- gap: 16px;
+.metric-binding-row {
+ width: 100%;
+}
+
+.metric-binding-row .left-col,
+.metric-binding-row .right-col {
+ margin-bottom: 16px;
+}
+
+.metric-binding-row .panel {
+ background: #ffffff;
+ padding: 16px;
+ box-sizing: border-box;
+ height: 100%;
+ min-height: 400px;
}
.left-panel,
.right-panel {
- flex: 1;
- background: #ffffff;
- padding: 16px;
- box-sizing: border-box;
+ height: 100%;
}
.toolbar {
@@ -429,4 +588,58 @@
:deep(.center-table .el-table__body-wrapper td .cell) {
text-align: center !important;
}
+
+/* PIMTable 琛ㄥご灞呬腑 */
+:deep(.lims-table .pim-table-header-cell) {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+:deep(.lims-table .pim-table-header-title) {
+ text-align: center;
+ width: 100%;
+}
+
+:deep(.lims-table .pim-table-header-extra) {
+ width: 100%;
+ margin-top: 4px;
+}
+
+.binding-dialog {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.binding-search {
+ width: 100%;
+}
+
+.product-binding-tree {
+ max-height: 360px;
+ overflow-y: auto;
+ border: 1px solid #ebeef5;
+ border-radius: 4px;
+ padding: 8px;
+}
+
+.selected-products {
+ border-top: 1px solid #ebeef5;
+ padding-top: 12px;
+}
+
+.selected-title {
+ font-size: 13px;
+ color: #606266;
+ margin-bottom: 8px;
+}
+
+.selected-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
</style>
--
Gitblit v1.9.3