From 5131abc9cc51aa5e6c57b8f6ee897f6778637814 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 14 一月 2026 15:32:45 +0800
Subject: [PATCH] fix: 参考中天的[检测标准绑定]页面,再新增一个分表,表示检测标准汇总表应用于哪些产品,是一对多的关系,这个维护好以后,后面的来料检,过程检,出厂检可以根据对应检验类型和产品id去获取具体的检测参数信息
---
src/views/qualityManagement/metricMaintenance/index.vue | 79 +++++++
src/api/qualityManagement/metricMaintenance.js | 10 +
src/api/qualityManagement/qualityTestStandardBinding.js | 28 ++
src/views/qualityManagement/metricBinding/index.vue | 428 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 540 insertions(+), 5 deletions(-)
diff --git a/src/api/qualityManagement/metricMaintenance.js b/src/api/qualityManagement/metricMaintenance.js
index 2f71bb1..53ca650 100644
--- a/src/api/qualityManagement/metricMaintenance.js
+++ b/src/api/qualityManagement/metricMaintenance.js
@@ -53,6 +53,16 @@
});
}
+// 鎵归噺瀹℃牳锛堢姸鎬侊細1=閫氳繃/鎵瑰噯锛�2=鎾ら攢锛�
+// 浼犲弬锛歔{ id, state }]
+export function qualityTestStandardAudit(data) {
+ return request({
+ url: "/qualityTestStandard/qualityTestStandardAudit",
+ method: "post",
+ data,
+ });
+}
+
// 鏍囧噯鍙傛暟锛氬垪琛紙涓嶅垎椤碉級
export function qualityTestStandardParamList(query) {
return request({
diff --git a/src/api/qualityManagement/qualityTestStandardBinding.js b/src/api/qualityManagement/qualityTestStandardBinding.js
new file mode 100644
index 0000000..e4432a6
--- /dev/null
+++ b/src/api/qualityManagement/qualityTestStandardBinding.js
@@ -0,0 +1,28 @@
+import request from "@/utils/request";
+
+// 缁戝畾鍒楄〃锛堜笉鍒嗛〉锛�
+export function qualityTestStandardBindingList(query) {
+ return request({
+ url: "/qualityTestStandardBinding/list",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鏂板缁戝畾锛堟敮鎸佹壒閲忥級
+export function qualityTestStandardBindingAdd(data) {
+ return request({
+ url: "/qualityTestStandardBinding/add",
+ method: "post",
+ data,
+ });
+}
+
+// 鍒犻櫎缁戝畾锛堜紶 id 鏁扮粍锛�
+export function qualityTestStandardBindingDel(ids) {
+ return request({
+ url: "/qualityTestStandardBinding/del",
+ method: "delete",
+ data: ids,
+ });
+}
diff --git a/src/views/qualityManagement/metricBinding/index.vue b/src/views/qualityManagement/metricBinding/index.vue
new file mode 100644
index 0000000..616a5e5
--- /dev/null
+++ b/src/views/qualityManagement/metricBinding/index.vue
@@ -0,0 +1,428 @@
+<template>
+ <div class="app-container metric-binding">
+ <!-- 宸︿晶锛氭娴嬫爣鍑嗗垪琛紙鍙锛� -->
+ <div class="left-panel">
+ <PIMTable
+ rowKey="id"
+ :column="standardColumns"
+ :tableData="standardTableData"
+ :page="page"
+ :isSelection="false"
+ :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 {
+ qualityTestStandardBindingList,
+ qualityTestStandardBindingAdd,
+ qualityTestStandardBindingDel
+} from '@/api/qualityManagement/qualityTestStandardBinding.js'
+
+const { proxy } = getCurrentInstance()
+
+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 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: '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) => {
+ bindingTableData.value = res?.data || []
+ })
+ .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()
+})
+</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 琛ㄥご/鍐呭缁熶竴灞呬腑锛坮ow-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>
diff --git a/src/views/qualityManagement/metricMaintenance/index.vue b/src/views/qualityManagement/metricMaintenance/index.vue
index 4f62bca..876d10f 100644
--- a/src/views/qualityManagement/metricMaintenance/index.vue
+++ b/src/views/qualityManagement/metricMaintenance/index.vue
@@ -6,6 +6,8 @@
<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>
@@ -16,6 +18,7 @@
:page="page"
:isSelection="true"
:tableLoading="tableLoading"
+ :rowClassName="rowClassNameCenter"
@selection-change="handleSelectionChange"
@pagination="handlePagination"
:total="page.total"
@@ -92,10 +95,10 @@
</div>
<div class="right-toolbar">
- <el-button type="primary" :disabled="!currentStandard" @click="openParamDialog('add')">
+ <el-button type="primary" :disabled="!currentStandard || isStandardReadonly" @click="openParamDialog('add')">
鏂板
</el-button>
- <el-button type="danger" plain :disabled="!currentStandard" @click="handleParamBatchDelete">
+ <el-button type="danger" plain :disabled="!currentStandard || isStandardReadonly" @click="handleParamBatchDelete">
鍒犻櫎
</el-button>
</div>
@@ -104,6 +107,8 @@
v-loading="detailLoading"
:data="detailTableData"
border
+ :row-class-name="() => 'row-center'"
+ class="center-table"
style="width: 100%"
height="calc(100vh - 220px)"
@selection-change="handleParamSelectionChange"
@@ -117,10 +122,10 @@
<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" @click="openParamDialog('edit', row)">
+ <el-button link type="primary" size="small" :disabled="isStandardReadonly" @click="openParamDialog('edit', row)">
缂栬緫
</el-button>
- <el-button link type="danger" size="small" @click="handleParamDelete(row)">
+ <el-button link type="danger" size="small" :disabled="isStandardReadonly" @click="handleParamDelete(row)">
鍒犻櫎
</el-button>
</template>
@@ -155,7 +160,7 @@
<script setup>
import { Search } from '@element-plus/icons-vue'
-import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
+import { ref, reactive, toRefs, onMounted, getCurrentInstance, computed } from 'vue'
import { ElMessageBox } from 'element-plus'
import {
qualityTestStandardListPage,
@@ -163,6 +168,7 @@
qualityTestStandardUpdate,
qualityTestStandardDel,
qualityTestStandardCopyParam,
+ qualityTestStandardAudit,
qualityTestStandardParamList,
qualityTestStandardParamAdd,
qualityTestStandardParamUpdate,
@@ -173,6 +179,15 @@
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({
@@ -399,6 +414,32 @@
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
@@ -425,6 +466,10 @@
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, {
@@ -449,6 +494,10 @@
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)
@@ -463,6 +512,10 @@
const handleParamDelete = async (row) => {
if (!row?.id) return
+ if (isStandardReadonly.value) {
+ proxy.$message.warning('璇ユ爣鍑嗗凡閫氳繃锛屽弬鏁颁笉鍙紪杈�')
+ return
+ }
try {
await ElMessageBox.confirm('纭鍒犻櫎璇ュ弬鏁帮紵', '鎻愮ず', { type: 'warning' })
} catch {
@@ -474,6 +527,10 @@
}
const handleParamBatchDelete = async () => {
+ if (isStandardReadonly.value) {
+ proxy.$message.warning('璇ユ爣鍑嗗凡閫氳繃锛屽弬鏁颁笉鍙紪杈�')
+ return
+ }
if (!paramSelectedRows.value.length) {
proxy.$message.warning('璇烽�夋嫨鏁版嵁')
return
@@ -682,4 +739,16 @@
.clickable-link:hover {
text-decoration: underline;
}
+
+:deep(.row-center td) {
+ text-align: center !important;
+}
+
+/* el-table 琛ㄥご/鍐呭缁熶竴灞呬腑锛坮ow-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>
\ No newline at end of file
--
Gitblit v1.9.3