Merge remote-tracking branch 'origin/dev_银川_中盛建材' into dev_银川_中盛建材
| | |
| | | <div class="kpi-label">总生产成本</div> |
| | | <div class="kpi-value">¥{{ formatMoney(overview.totalCost) }}</div> |
| | | </div> |
| | | <div class="kpi-item kpi-raw"> |
| | | <div class="kpi-label">原料成本</div> |
| | | <div class="kpi-value">¥{{ formatMoney(overview.rawCost) }}</div> |
| | | </div> |
| | | <div class="kpi-item kpi-aux"> |
| | | <div class="kpi-label">辅料成本</div> |
| | | <div class="kpi-value">¥{{ formatMoney(overview.auxCost) }}</div> |
| | | <div class="kpi-item kpi-avg"> |
| | | <div class="kpi-label">每订单平均成本</div> |
| | | <div class="kpi-value">¥{{ formatMoney(overview.avgCostPerOrder) }}</div> |
| | | </div> |
| | | <div class="kpi-item kpi-order"> |
| | | <div class="kpi-label">订单数量</div> |
| | |
| | | </template> |
| | | <el-table :data="categorySummary" stripe class="lux-table" height="260"> |
| | | <el-table-column prop="category" label="产品类别" min-width="140" /> |
| | | <el-table-column prop="rawCost" label="原料成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="price-value">{{ formatMoney(scope.row.rawCost) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="auxCost" label="辅料成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="price-value">{{ formatMoney(scope.row.auxCost) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="totalCost" label="总成本(元)" align="right"> |
| | | <el-table-column prop="totalCost" label="成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="cost-value">¥{{ formatMoney(scope.row.totalCost) }}</span> |
| | | </template> |
| | |
| | | <el-table-column prop="timeLabel" :label="timeColumnLabel" min-width="110" /> |
| | | <el-table-column prop="category" label="产品类别" min-width="120" /> |
| | | <el-table-column prop="orderNo" label="生产订单" min-width="150" /> |
| | | <el-table-column prop="rawCost" label="原料成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="price-value">{{ formatMoney(scope.row.rawCost) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="auxCost" label="辅料成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="price-value">{{ formatMoney(scope.row.auxCost) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="totalCost" label="总成本(元)" align="right"> |
| | | <el-table-column prop="totalCost" label="成本(元)" align="right"> |
| | | <template #default="scope"> |
| | | <span class="cost-value">¥{{ formatMoney(scope.row.totalCost) }}</span> |
| | | </template> |
| | |
| | | </div> |
| | | <el-table :data="detailMaterials" class="lux-table" stripe> |
| | | <el-table-column prop="materialName" label="物料名称" min-width="120" /> |
| | | <el-table-column prop="materialType" label="类型" width="94"> |
| | | <template #default="scope"> |
| | | <span |
| | | class="material-type-tag" |
| | | :class="scope.row.materialType === '原料' ? 'is-raw' : 'is-aux'" |
| | | > |
| | | {{ scope.row.materialType }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="quantity" label="投入量" align="right" min-width="140"> |
| | | <template #default="scope"> |
| | | <span class="quantity-cell"> |
| | |
| | | </el-table-column> |
| | | </el-table> |
| | | <div class="drawer-foot"> |
| | | <div class="foot-item"> |
| | | <span class="foot-label">原料</span> |
| | | <span class="foot-value no-wrap-money">¥{{ formatMoney(detailRawCost) }}</span> |
| | | </div> |
| | | <div class="foot-item"> |
| | | <span class="foot-label">辅料</span> |
| | | <span class="foot-value no-wrap-money">¥{{ formatMoney(detailAuxCost) }}</span> |
| | | </div> |
| | | <div class="foot-item total"> |
| | | <span class="foot-label">合计</span> |
| | | <span class="foot-label">成本合计</span> |
| | | <span class="foot-value no-wrap-money">¥{{ formatMoney(detailTotalCost) }}</span> |
| | | </div> |
| | | </div> |
| | |
| | | const key = keyFn(item); |
| | | if (!map.has(key)) { |
| | | map.set(key, { |
| | | rawCost: 0, |
| | | auxCost: 0, |
| | | totalCost: 0, |
| | | materials: [], |
| | | }); |
| | | } |
| | | const bucket = map.get(key); |
| | | if (item.materialType === "原料") bucket.rawCost += item.cost; |
| | | if (item.materialType === "辅料") bucket.auxCost += item.cost; |
| | | bucket.totalCost += item.cost; |
| | | bucket.materials.push(item); |
| | | } |
| | |
| | | timeLabel, |
| | | category, |
| | | orderNo, |
| | | rawCost: val.rawCost, |
| | | auxCost: val.auxCost, |
| | | totalCost: val.totalCost, |
| | | materials: val.materials, |
| | | }); |
| | |
| | | for (const [category, val] of map) { |
| | | rows.push({ |
| | | category, |
| | | rawCost: val.rawCost, |
| | | auxCost: val.auxCost, |
| | | totalCost: val.totalCost, |
| | | }); |
| | | } |
| | |
| | | }); |
| | | |
| | | const overview = computed(() => { |
| | | const rawCost = filteredRecords.value |
| | | .filter((item) => item.materialType === "原料") |
| | | .reduce((sum, item) => sum + item.cost, 0); |
| | | const auxCost = filteredRecords.value |
| | | .filter((item) => item.materialType === "辅料") |
| | | .reduce((sum, item) => sum + item.cost, 0); |
| | | const orderCount = new Set(filteredRecords.value.map((item) => item.orderNo)).size; |
| | | const totalCost = filteredRecords.value.reduce((sum, item) => sum + item.cost, 0); |
| | | return { |
| | | rawCost, |
| | | auxCost, |
| | | totalCost: rawCost + auxCost, |
| | | totalCost, |
| | | orderCount, |
| | | avgCostPerOrder: orderCount === 0 ? 0 : totalCost / orderCount, |
| | | }; |
| | | }); |
| | | |
| | |
| | | |
| | | const detailMaterials = computed(() => detailRow.value?.materials || []); |
| | | |
| | | const detailRawCost = computed(() => |
| | | detailMaterials.value |
| | | .filter((item) => item.materialType === "原料") |
| | | .reduce((sum, item) => sum + item.cost, 0) |
| | | ); |
| | | const detailAuxCost = computed(() => |
| | | detailMaterials.value |
| | | .filter((item) => item.materialType === "辅料") |
| | | .reduce((sum, item) => sum + item.cost, 0) |
| | | ); |
| | | const detailTotalCost = computed(() => |
| | | detailMaterials.value.reduce((sum, item) => sum + item.cost, 0) |
| | | ); |
| | |
| | | }; |
| | | |
| | | const handleExport = () => { |
| | | const headers = [timeColumnLabel.value, "产品类别", "生产订单", "原料成本", "辅料成本", "总成本"]; |
| | | const headers = [timeColumnLabel.value, "产品类别", "生产订单", "成本(元)"]; |
| | | const lines = tableData.value.map((row) => |
| | | [ |
| | | row.timeLabel, |
| | | row.category, |
| | | row.orderNo, |
| | | row.rawCost.toFixed(2), |
| | | row.auxCost.toFixed(2), |
| | | row.totalCost.toFixed(2), |
| | | ].join(",") |
| | | ); |
| | |
| | | |
| | | .kpi-strip { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, minmax(0, 1fr)); |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | gap: 12px; |
| | | } |
| | | |
| | |
| | | background: linear-gradient(135deg, rgba(22, 163, 74, 0.1), rgba(255, 255, 255, 0.86)); |
| | | } |
| | | |
| | | .kpi-aux { |
| | | background: linear-gradient(135deg, rgba(245, 158, 11, 0.1), rgba(255, 255, 255, 0.86)); |
| | | .kpi-avg { |
| | | background: linear-gradient(135deg, rgba(99, 102, 241, 0.14), rgba(255, 255, 255, 0.86)); |
| | | } |
| | | |
| | | .kpi-order { |
| | |
| | | const largeChartVisible = ref(false); |
| | | const currentChartOption = ref(null); |
| | | |
| | | const actualCostSource = ref([ |
| | | { month: "2026-01", category: "瓷砖", costType: "能耗成本", actualCost: 182000 }, |
| | | { month: "2026-01", category: "瓷砖", costType: "生产成本", actualCost: 465000 }, |
| | | { month: "2026-01", category: "水泥", costType: "能耗成本", actualCost: 138500 }, |
| | | { month: "2026-01", category: "水泥", costType: "生产成本", actualCost: 398000 }, |
| | | { month: "2026-02", category: "瓷砖", costType: "能耗成本", actualCost: 191500 }, |
| | | { month: "2026-02", category: "瓷砖", costType: "生产成本", actualCost: 472500 }, |
| | | { month: "2026-02", category: "水泥", costType: "能耗成本", actualCost: 142300 }, |
| | | { month: "2026-02", category: "水泥", costType: "生产成本", actualCost: 407000 }, |
| | | { month: "2026-03", category: "砂浆", costType: "能耗成本", actualCost: 95800 }, |
| | | { month: "2026-03", category: "砂浆", costType: "生产成本", actualCost: 265400 }, |
| | | { month: "2026-03", category: "瓷砖", costType: "能耗成本", actualCost: 189800 }, |
| | | { month: "2026-03", category: "瓷砖", costType: "生产成本", actualCost: 469900 }, |
| | | ]); |
| | | // ------------------------------ |
| | | // 假数据:用于先联调页面渲染 |
| | | // ------------------------------ |
| | | const actualCostSource = ref([]); |
| | | const standardCostSource = ref([]); |
| | | |
| | | const standardCostSource = ref([ |
| | | { month: "2026-01", category: "瓷砖", costType: "能耗成本", standardCost: 176000 }, |
| | | { month: "2026-01", category: "瓷砖", costType: "生产成本", standardCost: 452000 }, |
| | | { month: "2026-01", category: "水泥", costType: "能耗成本", standardCost: 136000 }, |
| | | { month: "2026-01", category: "水泥", costType: "生产成本", standardCost: 392000 }, |
| | | { month: "2026-02", category: "瓷砖", costType: "能耗成本", standardCost: 186000 }, |
| | | { month: "2026-02", category: "瓷砖", costType: "生产成本", standardCost: 458000 }, |
| | | { month: "2026-02", category: "水泥", costType: "能耗成本", standardCost: 139000 }, |
| | | { month: "2026-02", category: "水泥", costType: "生产成本", standardCost: 401000 }, |
| | | { month: "2026-03", category: "砂浆", costType: "能耗成本", standardCost: 93000 }, |
| | | { month: "2026-03", category: "砂浆", costType: "生产成本", standardCost: 259000 }, |
| | | { month: "2026-03", category: "瓷砖", costType: "能耗成本", standardCost: 185000 }, |
| | | { month: "2026-03", category: "瓷砖", costType: "生产成本", standardCost: 461000 }, |
| | | ]); |
| | | const fakeMonths = ["2026-01", "2026-02", "2026-03"]; |
| | | const fakeCategories = [ |
| | | "粉煤灰", |
| | | "石灰", |
| | | "水泥", |
| | | "铝粉膏", |
| | | "脱模剂", |
| | | "石膏", |
| | | "打包带", |
| | | "防腐剂(板材用)", |
| | | "氧化镁(板材用)", |
| | | "冷挤丝(板材用)", |
| | | "卡扣(板材用)", |
| | | "材料小计", |
| | | "水", |
| | | "电", |
| | | "蒸汽", |
| | | ]; |
| | | |
| | | const fakeCostType = (category) => (["水", "电", "蒸汽"].includes(category) ? "能耗成本" : "生产成本"); |
| | | |
| | | // 每个类别的标准成本基准值(仅用于假数据) |
| | | const baseStandardCostByCategory = { |
| | | 粉煤灰: 98000, |
| | | 石灰: 52000, |
| | | 水泥: 175000, |
| | | 铝粉膏: 32000, |
| | | 脱模剂: 21000, |
| | | 石膏: 41000, |
| | | 打包带: 14500, |
| | | "防腐剂(板材用)": 12500, |
| | | "氧化镁(板材用)": 22000, |
| | | "冷挤丝(板材用)": 9800, |
| | | "卡扣(板材用)": 8600, |
| | | 材料小计: 420000, |
| | | 水: 6800, |
| | | 电: 26000, |
| | | 蒸汽: 52000, |
| | | }; |
| | | |
| | | // 月份波动系数(让图表看起来更“真实”一些) |
| | | const monthFactorByMonth = { |
| | | "2026-01": 1.0, |
| | | "2026-02": 1.06, |
| | | "2026-03": 0.97, |
| | | }; |
| | | |
| | | // 实际成本相对标准成本的偏移比例(用于测试正负差异展示) |
| | | const diffRatioByCategory = { |
| | | 粉煤灰: 0.05, |
| | | 石灰: -0.01, |
| | | 水泥: 0.03, |
| | | 铝粉膏: 0.0, |
| | | 脱模剂: -0.04, |
| | | 石膏: 0.02, |
| | | 打包带: -0.03, |
| | | "防腐剂(板材用)": 0.06, |
| | | "氧化镁(板材用)": -0.02, |
| | | "冷挤丝(板材用)": 0.01, |
| | | "卡扣(板材用)": -0.05, |
| | | 材料小计: 0.02, |
| | | 水: -0.01, |
| | | 电: 0.04, |
| | | 蒸汽: -0.03, |
| | | }; |
| | | |
| | | const buildFakeSources = () => { |
| | | const stdRows = []; |
| | | const actRows = []; |
| | | |
| | | for (const month of fakeMonths) { |
| | | const monthFactor = monthFactorByMonth[month] ?? 1; |
| | | const monthAdj = month === "2026-02" ? 0.005 : month === "2026-03" ? -0.006 : 0; |
| | | |
| | | for (const category of fakeCategories) { |
| | | const costType = fakeCostType(category); |
| | | const base = baseStandardCostByCategory[category] ?? 0; |
| | | const standardCost = Math.round(base * monthFactor); |
| | | const diffRatio = (diffRatioByCategory[category] ?? 0) + monthAdj; |
| | | const actualCost = Math.round(standardCost * (1 + diffRatio)); |
| | | |
| | | stdRows.push({ month, category, costType, standardCost }); |
| | | actRows.push({ month, category, costType, actualCost }); |
| | | } |
| | | } |
| | | |
| | | standardCostSource.value = stdRows; |
| | | actualCostSource.value = actRows; |
| | | }; |
| | | |
| | | buildFakeSources(); |
| | | |
| | | const categoryOptions = computed(() => { |
| | | const all = [...actualCostSource.value, ...standardCostSource.value]; |
| | |
| | | |
| | | const downloadTemplate = () => { |
| | | const sample = [ |
| | | { 月份: "2026-03", 产品类别: "瓷砖", 成本类型: "标准能耗成本", 标准成本: 185000 }, |
| | | { 月份: "2026-03", 产品类别: "瓷砖", 成本类型: "标准生产成本", 标准成本: 461000 }, |
| | | { 月份: "2026-03", 产品类别: "水泥", 成本类型: "标准能耗成本", 标准成本: 140000 }, |
| | | { 月份: "2026-03", 产品类别: "水泥", 成本类型: "标准生产成本", 标准成本: 405000 }, |
| | | { 月份: "2026-03", 产品类别: "粉煤灰", 成本类型: "标准生产成本", 标准成本: 98000 }, |
| | | { 月份: "2026-03", 产品类别: "水泥", 成本类型: "标准生产成本", 标准成本: 175000 }, |
| | | { 月份: "2026-03", 产品类别: "电", 成本类型: "标准能耗成本", 标准成本: 26000 }, |
| | | { 月份: "2026-03", 产品类别: "蒸汽", 成本类型: "标准能耗成本", 标准成本: 52000 }, |
| | | { 月份: "2026-03", 产品类别: "水", 成本类型: "标准能耗成本", 标准成本: 6800 }, |
| | | ]; |
| | | const ws = XLSX.utils.json_to_sheet(sample); |
| | | const wb = XLSX.utils.book_new(); |
| | |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="班组:"> |
| | | <el-input v-model="searchForm.teamName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | <el-select v-model="searchForm.teamName" |
| | | placeholder="请选择" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery"> |
| | | <el-option label="白班" |
| | | value="白班" /> |
| | | <el-option label="夜班" |
| | | value="夜班" /> |
| | | </el-select> |
| | | <!-- <el-input v-model="searchForm.teamName" |
| | | placeholder="请输入"" |
| | | @keyup.enter="handleQuery" /> --> |
| | | </el-form-item> |
| | | <el-form-item label="产品名称:"> |
| | | <el-input v-model="searchForm.productName" |
| | |
| | | { |
| | | label: "生产订单号", |
| | | prop: "orderNo", |
| | | width: "150px", |
| | | }, |
| | | { |
| | | label: "班组", |
| | | prop: "teamName", |
| | | width: "120px", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | | return params === "白班" ? "primary" : "warning"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "产品编码", |
| | |
| | | { |
| | | id: 1, |
| | | orderNo: "PO202401001", |
| | | teamName: "生产一组", |
| | | teamName: "白班", |
| | | materialCode: "PC001", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | { |
| | | id: 2, |
| | | orderNo: "PO202401002", |
| | | teamName: "生产二组", |
| | | teamName: "夜班", |
| | | materialCode: "PC002", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | { |
| | | id: 3, |
| | | orderNo: "PO202401003", |
| | | teamName: "生产三组", |
| | | teamName: "白班", |
| | | materialCode: "PC003", |
| | | productName: "加气砌块", |
| | | specification: "600×240×250", |
| | |
| | | { |
| | | id: 4, |
| | | orderNo: "PO202401004", |
| | | teamName: "生产一组", |
| | | teamName: "白班", |
| | | materialCode: "PC004", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | { |
| | | id: 5, |
| | | orderNo: "PO202401005", |
| | | teamName: "生产二组", |
| | | teamName: "夜班", |
| | | materialCode: "PC005", |
| | | productName: "加气砌块", |
| | | specification: "600×240×250", |
| | |
| | | { |
| | | id: 6, |
| | | orderNo: "PO202401006", |
| | | teamName: "生产三组", |
| | | teamName: "白班", |
| | | materialCode: "PC006", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | { |
| | | id: 7, |
| | | orderNo: "PO202401007", |
| | | teamName: "生产一组", |
| | | teamName: "白班", |
| | | materialCode: "PC007", |
| | | productName: "加气砌块", |
| | | specification: "600×240×250", |
| | |
| | | { |
| | | id: 8, |
| | | orderNo: "PO202401008", |
| | | teamName: "生产二组", |
| | | teamName: "夜班", |
| | | materialCode: "PC008", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | { |
| | | id: 9, |
| | | orderNo: "PO202401009", |
| | | teamName: "生产三组", |
| | | teamName: "白班", |
| | | materialCode: "PC009", |
| | | productName: "加气砌块", |
| | | specification: "600×240×250", |
| | |
| | | { |
| | | id: 10, |
| | | orderNo: "PO202401010", |
| | | teamName: "生产一组", |
| | | teamName: "白班", |
| | | materialCode: "PC010", |
| | | productName: "标准砌块", |
| | | specification: "600×240×200", |
| | |
| | | v-model="form.npsNo" |
| | | class="form-input" /> |
| | | </el-form-item> |
| | | <el-form-item label="班组" |
| | | prop="teamName" |
| | | required |
| | | class="form-item"> |
| | | <el-select v-model="form.teamName" |
| | | placeholder="请选择班组" |
| | | class="form-select"> |
| | | <el-option label="白班" |
| | | value="白班" /> |
| | | <el-option label="夜班" |
| | | value="夜班" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="产品编码" |
| | | prop="materialCode" |
| | | class="form-item"> |
| | |
| | | v-model="form.specification" |
| | | class="form-input" /> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间" |
| | | prop="createTime" |
| | | class="form-item"> |
| | | <el-date-picker disabled |
| | | v-model="form.createTime" |
| | | type="datetime" |
| | | placeholder="请选择创建时间" |
| | | class="form-input" /> |
| | | </el-form-item> |
| | | <el-form-item label="班组" |
| | | prop="teamName" |
| | | required |
| | | class="form-item"> |
| | | <el-select v-model="form.teamName" |
| | | placeholder="请选择班组" |
| | | class="form-select"> |
| | | <el-option label="白班" |
| | | value="白班" /> |
| | | <el-option label="夜班" |
| | | value="夜班" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="创建人" |
| | | prop="createBy" |
| | | required |
| | |
| | | :label="user.nickName || user.userName" |
| | | :value="user.nickName || user.userName" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间" |
| | | prop="createTime" |
| | | class="form-item"> |
| | | <el-date-picker disabled |
| | | v-model="form.createTime" |
| | | type="datetime" |
| | | placeholder="请选择创建时间" |
| | | class="form-input" /> |
| | | </el-form-item> |
| | | </div> |
| | | </el-form> |
| | |
| | | :key="param.id" |
| | | :label="param.paramName" |
| | | :label-width="120" |
| | | :required="param.isRequired" |
| | | :prop="`paramGroups.${activeProcessId}.${index}.${param.id}`" |
| | | :rules="param.isRequired ? [{ required: true, message: `请输入${param.paramName}`, trigger: 'blur' }] : []" |
| | | class="param-item"> |
| | | <template v-if="param.paramType == '1'"> |
| | | <!-- 数字类型 --> |
| | |
| | | <!-- 参数列 --> |
| | | <el-table-column v-for="param in params" |
| | | :key="param.id" |
| | | :label="param.paramName" |
| | | min-width="200"> |
| | | :min-width="200"> |
| | | <template #header> |
| | | <span :class="{ 'required-label': param.isRequired }">{{ param.paramName }}</span> |
| | | </template> |
| | | <template #default="{ row }"> |
| | | <template v-if="param.paramType == '1'"> |
| | | <!-- 数字类型 --> |
| | |
| | | <el-input-number v-model="form.outputVolume" |
| | | :min="0" |
| | | :precision="2" |
| | | @change="handleVolumeChange" |
| | | class="volume-input" /> |
| | | <span class="volume-unit">方</span> |
| | | </div> |
| | |
| | | <el-input-number v-model="form.unqualifiedVolume" |
| | | :min="0" |
| | | :precision="2" |
| | | @change="handleVolumeChange" |
| | | class="volume-input" /> |
| | | <span class="volume-unit">方</span> |
| | | </div> |
| | |
| | | id: data.id || undefined, |
| | | orderId: data.orderId || "", |
| | | npsNo: data.npsNo || "", |
| | | teamName: data.teamName || "", |
| | | teamName: data.teamName || "白班", |
| | | materialCode: data.materialCode || "", |
| | | productName: data.productName || "", |
| | | specification: data.specification || "", |
| | |
| | | .finally(() => { |
| | | orderLoading.value = false; |
| | | }); |
| | | }; |
| | | const handleVolumeChange = () => { |
| | | form.completedVolume = form.outputVolume - form.unqualifiedVolume; |
| | | }; |
| | | |
| | | // 处理生产订单选择 |
| | |
| | | } |
| | | }); |
| | | } else if (activeStep.value === 2) { |
| | | // 第三步:直接进入第四步 |
| | | // 第三步:验证参数必填项 |
| | | let isValid = true; |
| | | let errorMessage = ""; |
| | | |
| | | // 遍历所有工序 |
| | | for (const process of processList.value) { |
| | | const processId = process.processId; |
| | | const paramGroups = form.paramGroups[processId] || []; |
| | | const processParams = process.orderRouteItemParaVos || []; |
| | | |
| | | // 获取必填参数 |
| | | const requiredParams = processParams.filter(p => p.isRequired); |
| | | |
| | | if (requiredParams.length > 0) { |
| | | // 检查每个参数组中的必填参数 |
| | | for ( |
| | | let groupIndex = 0; |
| | | groupIndex < paramGroups.length; |
| | | groupIndex++ |
| | | ) { |
| | | const group = paramGroups[groupIndex]; |
| | | for (const param of requiredParams) { |
| | | const value = group[param.id]; |
| | | if (value === undefined || value === null || value === "") { |
| | | isValid = false; |
| | | errorMessage = `工序【${process.processName}】参数组${ |
| | | groupIndex + 1 |
| | | }的【${param.paramName}】为必填项`; |
| | | break; |
| | | } |
| | | } |
| | | if (!isValid) break; |
| | | } |
| | | } |
| | | if (!isValid) break; |
| | | } |
| | | |
| | | if (!isValid) { |
| | | ElMessage.error(errorMessage); |
| | | return; |
| | | } |
| | | |
| | | activeStep.value = 3; |
| | | } |
| | | }; |
| | |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | /* 必填标识样式 */ |
| | | .required-label::before { |
| | | content: "*"; |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | |
| | | .form-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); |