From a660db06773007b1be690e0674829c00a57aeb7b Mon Sep 17 00:00:00 2001
From: 廖井涛 <2265517004@qq.com>
Date: 星期三, 24 十二月 2025 16:21:23 +0800
Subject: [PATCH] 订单首页流程卡新增楼层编号显示
---
north-glass-erp/northglass-erp/src/views/sd/bom/ProductBomAdd.vue | 372 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 333 insertions(+), 39 deletions(-)
diff --git a/north-glass-erp/northglass-erp/src/views/sd/bom/ProductBomAdd.vue b/north-glass-erp/northglass-erp/src/views/sd/bom/ProductBomAdd.vue
index 6d5191f..a364e41 100644
--- a/north-glass-erp/northglass-erp/src/views/sd/bom/ProductBomAdd.vue
+++ b/north-glass-erp/northglass-erp/src/views/sd/bom/ProductBomAdd.vue
@@ -1,10 +1,44 @@
<script setup>
-import {reactive, ref} from "vue";
+import { reactive, ref, computed, watch,onMounted } from "vue";
import {useI18n} from "vue-i18n";
+import request from "@/utils/request"
+import {changeFilterEvent, filterChanged} from "@/hook";
+import deepClone from "@/utils/deepClone"
+import { ElMessage, ElMessageBox} from "element-plus"
const { t } = useI18n()
+const emit = defineEmits(['closeDialog'])
+let produceList = ref([])
+let props = defineProps({
+ productName:null,
+ produceId:null,
+ baseGridOptions: { type: Object, required: true },
+
+ gridDataByProduct: { type: Object, default: () => ({}) }
+})
+
+
+
const xGrid = ref()
const xGridByProduct = ref()
+const activeProduct = ref('') // 褰撳墠閫変腑鐨勪骇鍝佸悕
let materialType = ref(1)
+
+//鍏抽棴寮圭獥
+const closeDialog = () => {
+ emit('closeDialog')
+}
+
+const value = ref('')
+const options = [
+ {
+ value: t('ingredients.originalFilm'),
+ label: t('ingredients.originalFilm')
+ },
+ {
+ value: t('ingredients.accessories'),
+ label: t('ingredients.accessories'),
+ }
+]
const gridOptions = reactive({
border: "full",//琛ㄦ牸鍔犺竟妗�
keepSource: true,//淇濇寔婧愭暟鎹�
@@ -26,25 +60,9 @@
customConfig: {
storage: true
},
- editConfig: {
- trigger: 'click',
- mode: 'row',
- showStatus: true
- },
columns:[
- {field:'id',title: '鐗╂枡缂栧彿', },
- {field: 'name', title: '鐗╂枡鍚嶇О'},
- {field: 'thickness', title: '鍘氬害'},
- {field: 'size', title: '灏哄'},
- {field:'consumption',title: '娑堣�楅噺' },
- {field:'unit',title: '鍗曚綅' },
- {field:'price',title: '浠锋牸' }
],//琛ㄥご鍙傛暟
data:[
- {id:'1',name:'6mm瓒呯櫧',thickness:6,size:3660*2440,consumption:'1.2',unit:'/銕�',price:'60'},
- {id:'2',name:'6mmPDE60A03',thickness:6,size:3660*3300,consumption:'1.17',unit:'/銕�',price:'70'},
- {id:'3',name:'7mmPDE60A03',thickness:7,size:4280*3050,consumption:'1.21',unit:'/銕�',price:'75'},
- {id:'4',name:'8mm瓒呯櫧US1.16',thickness:6,size:5800*3300,consumption:'1.3',unit:'/銕�',price:'90'}
],//琛ㄦ牸鏁版嵁
toolbarConfig: {
slots:{
@@ -80,16 +98,18 @@
showStatus: true
},
columns:[
- {field:'id',title: '鐗╂枡缂栧彿', },
- {field: 'name', title: '鐗╂枡鍚嶇О'},
- {field: 'thickness', title: '鍘氬害'},
- {field: 'size', title: '灏哄'},
- {field:'consumption',title: '娑堣�楅噺' },
- {field:'unit',title: '鍗曚綅' },
- {field:'price',title: '浠锋牸' }
+ {title: '', width: '110', slots: { default: 'button_slot' },fixed:'left'},
+ {field:'id',title: t('ingredients.materialCode') },
+ {field: 'name', title: t('ingredientsStock.materialName')},
+ {field: 'thickness', title: t('product.msg.allThickness')},
+ {field: 'width', title: t('order.width')},
+ {field: 'height', title: t('order.height')},
+ {field:'consume',title: t('bom.consume') },
+ {field:'unit',title: t('ingredients.unit') },
+ {field:'price',title: t('bom.price1') }
],//琛ㄥご鍙傛暟
data:[
- {id:'1',name:'6mm瓒呯櫧',thickness:6,size:3660*2440,consumption:'1.2',unit:'/銕�',price:'60'}
+
],//琛ㄦ牸鏁版嵁
toolbarConfig: {
slots: {
@@ -98,20 +118,252 @@
}
})
+let arr = [
+ {title: t('basicData.add'), width: '110', slots: { default: 'button_slot' },fixed:'left'},
+ {field: 'tabId', width: '150',title: 'BOMId', sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged},
+ {field: 'id', width: '150',title: t('ingredients.materialCode'), sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged},
+ {field: 'consume',title: t('bom.consume'),showOverflow:'ellipsis' },
+ {field: 'price',title: t('bom.price'),showOverflow:'ellipsis' }
+]
+const bomTitle = [
+
+]
+let pageNum=ref(1)
+let total = reactive({
+ pageTotal : 0,
+ dataTotal : 0,
+ pageSize : 1000
+})
+let filterData = ref({
+ type:''
+
+})
+let BasicData = ref([])
+
+let materialStore= ref([])
+onMounted(async () => {
+ //绗竴娆″姞杞介粯璁�
+ value.value=t('ingredients.originalFilm')
+ filterData.value.type=t('ingredients.originalFilm')
+ request.get(`/BasicWarehouse/BasicWarehouseType/${value.value}`).then((res) => {
+ if(res.code==200){
+ gridOptions.columns.splice(0,gridOptions.columns.length)
+ BasicData.value = res.data
+ //娣诲姞鍒�
+ gridOptions.columns=arr.slice()
+ for (let i=0;i<BasicData.value.length;i++){
+ let aa={field: BasicData.value[i].OperateType, width: '150',title: BasicData.value[i].OperateTypeName, sortable: true,showOverflow:'ellipsis' ,filters:[{ data: '' }],slots: { filter: 'num1_filter' },filterMethod:filterChanged}
+ gridOptions.columns.push(aa)
+ }
+ bomTitle.forEach((item) => {
+ gridOptions.columns.push(item)
+ })
+
+ getWorks()
+ getDetails();
+ editProductBOM();
+ }else{
+ ElMessage.warning(res.msg)
+ }
+ })
+})
+
+//鍒楁煡璇�
+const getWork = () => {
+ filterData.value.type=value.value
+ request.get(`/BasicWarehouse/BasicWarehouseType/${value.value}`).then((res) => {
+ if(res.code==200){
+ gridOptions.columns=[]
+ BasicData.value = res.data
+ //娣诲姞鍒�
+ gridOptions.columns=arr.slice()
+
+ for (let i=0;i<BasicData.value.length;i++){
+ let column={field: BasicData.value[i].OperateType,
+ width: '150',title: BasicData.value[i].OperateTypeName,
+ sortable: true,showOverflow:'ellipsis' ,
+ filters:[{ data: '' }],
+ slots: { filter: 'num1_filter' },
+ filterMethod:filterChanged}
+
+ gridOptions.columns.push(column)
+
+ }
+ bomTitle.forEach((item) => {
+ gridOptions.columns.push(item)
+ })
+ getWorks()
+
+ }else{
+ ElMessage.warning(res.msg)
+ }
+ })
+}
+
+
+//鏁版嵁缁戝畾
+const getWorks = () => {
+ request.post(`/materialStore/getSelectProductBOM/1/${total.pageSize}`,filterData.value).then((res) => {
+
+ if(res.code==200){
+ materialStore.value=[]
+ for (let i=0;i<res.data.data.length;i++){
+ materialStore.value[i]= JSON.parse(res.data.data[i].json)
+ materialStore.value[i].id= res.data.data[i].id
+ materialStore.value[i].consume= res.data.data[i].consume
+ materialStore.value[i].tabId= res.data.data[i].tabId
+ switch (res.data.data[i].bomType) {
+ case '1':
+ materialStore.value[i].bomType = t('order.area');
+ break;
+ case '2':
+ materialStore.value[i].bomType = t('order.perimeter');
+ break;
+ case "3":
+ materialStore.value[i].bomType = t('order.quantity');
+ break;
+ default:
+ materialStore.value[i].bomType = res.data.data[i].bomType; // 淇濈暀鍘熷��
+ }
+ materialStore.value[i].price= res.data.data[i].price
+ }
+
+ total.dataTotal = res.data.total.total*1
+ total.pageTotal= res.data.total.pageTotal
+ pageNum.value=1
+
+ produceList = deepClone(materialStore.value)
+ xGrid.value.loadData(produceList)
+ gridOptions.loading=false
+ }else{
+ ElMessage.warning(res.msg)
+ router.push("/login")
+ }
+ })
+}
+
+
+const getDetails = () => {
+}
+
+//鎷嗗垎姣忎釜浜у搧
+const productList = computed(() => {
+ const raw = (props.productName ?? '').toString().trim()
+ if (!raw) return [t('bom.other')]
+
+ const parts = raw
+ .split(/[+*]/)
+ .map(s => s.trim())
+ .filter(Boolean)
+
+ parts.push(t('bom.other'))
+
+ return parts
+})
+
+// 褰撳墠閫変腑 tab 鐨勪笅鏍�
+const activeProductIndex = ref(null)
+
+const gridDataMapByProduct = reactive({})
+
+const handleTabClick = (name, index) => {
+ activeProductIndex.value = index
+ if (!gridDataMapByProduct[index]) {
+ gridDataMapByProduct[index] = [] // 鍒濆鍖�
+ }
+ xGridByProduct.value?.loadData(gridDataMapByProduct[index])
+}
+const getTableRow = (row, type) => {
+ if (type !== 'add') return
+ const key = activeProductIndex.value
+ if (key=="" && key==null) {
+ ElMessage.warning(t('bom.msg.msg1'))
+ return
+ }
+ const plainRow = JSON.parse(JSON.stringify(row))
+ const oldData = (gridDataMapByProduct[key] || []).map((item) =>
+ JSON.parse(JSON.stringify(item))
+ )
+ gridDataMapByProduct[key] = [...oldData, plainRow]
+ xGridByProduct.value.loadData(gridDataMapByProduct[key])
+}
+const getTableRowDils = (row,type) =>{
+ switch (type) {
+ case 'delete' :{
+ const key = activeProductIndex.value
+ gridDataMapByProduct[key] = (gridDataMapByProduct[key] || []).filter(
+ item => item.id !== row.id
+ )
+
+ xGridByProduct.value.loadData(gridDataMapByProduct[key])
+ return
+ }
+ }
+}
+
+const saveProductBOM = () => {
+ gridOptionsByProduct.loading=true
+ productList.value.forEach((name, index) => {
+ const rows = gridDataMapByProduct[index] || []
+ const seq = index + 1
+
+ //缁欐瘡鏉℃暟鎹姞涓婂搴斿眰鍙枫�佷骇鍝佺紪鍙�
+ rows.forEach(row => {
+ row.layer = seq
+ row.produceId = props.produceId
+ })
+ })
+ request.post(`/BomData/saveProductBOM`,gridDataMapByProduct).then((res) => {
+ if(res.code==200){
+ ElMessage.success(t('basicData.msg.saveSuccess'))
+ gridOptionsByProduct.loading=false
+ emit('closeDialog')
+ }})
+}
+
+const editProductBOM = () => {
+ request.post(`/BomData/editProductBOM/${props.produceId}`).then((res) => {
+ if (res.code == 200 ) {
+ // 鍒濆鍖栨竻绌�
+ productList.value.forEach((_, index) => {
+ gridDataMapByProduct[index + 1] = []
+ })
+ // 閬嶅巻鍚庣杩斿洖鐨勬暟鎹�
+ res.data.data.forEach(item => {
+ const layer = item.product_layer - 1 // 渚嬪 1, 2, 3
+ if (!gridDataMapByProduct[layer]) {
+ gridDataMapByProduct[layer] = []
+ }
+
+ const plainItem = JSON.parse(JSON.stringify(item))
+ gridDataMapByProduct[layer].push(plainItem)
+ })
+
+ // 榛樿閫夋嫨绗竴灞�
+ activeProductIndex.value = 0
+ xGridByProduct.value.loadData(gridDataMapByProduct[0])
+ }
+ })
+}
</script>
<template>
<div id="main_add">
<div class="product">
- <el-card style="max-width: 480px">
- <p class="text item">6mm瓒呯櫧閽㈠寲</p>
- <p class="text item">12AR</p>
- <p style="color: blue" class="text item">6mm瓒呯櫧閽㈠寲</p>
- <p class="text item">0.76PVB</p>
- <p class="text item">6mm瓒呯櫧閽㈠寲</p>
- <p class="text item">鍏朵粬</p>
+ <el-card class="product-card" shadow="never">
+ <div class="product-tabs">
+ <p
+ v-for="(name, i) in productList"
+ :key="i"
+ class="text item tab"
+ :class="{ active: activeProductIndex === i }"
+ @click="handleTabClick(name, i)"
+ >
+ {{ name }}
+ </p>
+ </div>
</el-card>
</div>
<div class="productLayer">
@@ -121,10 +373,16 @@
height="100%"
size="small"
v-bind="gridOptionsByProduct"
+
>
<template #toolbar_buttons>
- <el-button >鍒犻櫎</el-button>
- <el-button type="primary" >淇濆瓨</el-button>
+ <el-button type="primary" @click="saveProductBOM">淇濆瓨</el-button>
+ </template>
+ <template #button_slot="{ row }">
+ <el-button @click="getTableRowDils(row,'delete')"
+
+ link type="primary" size="small">{{ $t('basicData.delete') }}</el-button>
+
</template>
</vxe-grid>
@@ -138,10 +396,27 @@
size="small"
>
<template #toolbar_buttons>
- <vxe-select v-model="materialType">
- <vxe-option :value="1" :label="'鍘熺墖'"></vxe-option>
- <vxe-option :value="2" :label="'杈呮枡'"></vxe-option>
- </vxe-select>
+ <el-select v-model="value" style="width: 150px;" :placeholder="$t('ingredients.pleaseSelectACategory')" @change="getWork">
+ <el-option
+ v-for="item in options"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </template>
+ <template #num1_filter="{ column, $panel }">
+ <div>
+ <div v-for="(option, index) in column.filters" :key="index">
+ <input type="type" v-model="option.data" @keyup.enter.native="$panel.confirmFilter()" @input="changeFilterEvent($event, option, $panel)"/>
+ </div>
+ </div>
+ </template>
+ <template #button_slot="{ row }">
+ <el-button @click="getTableRow(row,'add')"
+
+ link type="primary" size="small">{{ $t('basicData.add') }}</el-button>
+
</template>
</vxe-grid>
</div>
@@ -157,7 +432,7 @@
height: 100%;
}
.product{
- width: 35%;
+ width: 30%;
height:50%;
float: left;
}
@@ -171,4 +446,23 @@
height:50%;
float: left;
}
+.product-card { max-width: 960px; padding: 2px 2px 4px; }
+.product-tabs { display: flex; flex-direction: column; gap: 2px 12px; }
+.tab {
+ margin: 0; padding: 6px 10px; line-height: 1.6;
+ border-radius: 6px; cursor: pointer; user-select: none;
+ transition: all .15s ease; border: 1px solid var(--el-border-color);
+}
+.tab:hover { transform: translateY(-1px); }
+.tab.active {
+ background: var(--el-color-primary-light-9);
+ border-color: var(--el-color-primary);
+ color: var(--el-color-primary); font-weight: 600;
+}
+
+.tab.active {
+ font-weight: bold;
+ color: #409EFF; /* Element Plus 涓昏壊 */
+ border-bottom: 2px solid #409EFF;
+}
</style>
\ No newline at end of file
--
Gitblit v1.8.0