| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // æ åææ¬å¯¼å
¥ |
| | | <template> |
| | | <div class="standard-cost-ledger-page"> |
| | | <el-card shadow="never" class="query-card"> |
| | | <el-form :inline="true" :model="queryForm"> |
| | | <el-form-item label="导å
¥æä»½"> |
| | | <el-date-picker |
| | | v-model="queryForm.month" |
| | | type="month" |
| | | value-format="YYYY-MM" |
| | | placeholder="éæ©æä»½" |
| | | @change="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¹æ¬¡å·"> |
| | | <el-select |
| | | v-model="queryForm.batchNo" |
| | | clearable |
| | | filterable |
| | | placeholder="å
¨é¨æ¹æ¬¡" |
| | | style="width: 220px" |
| | | @change="handleQuery" |
| | | > |
| | | <el-option |
| | | v-for="item in batchOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <el-card shadow="never" class="ledger-card"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ åææ¬å¯¼å
¥å°è´¦</span> |
| | | <span class="meta">å
± {{ filteredLedgerRows.length }} æ¡å¯¼å
¥è®°å½</span> |
| | | </div> |
| | | </template> |
| | | <el-table |
| | | :data="filteredLedgerRows" |
| | | border |
| | | highlight-current-row |
| | | @current-change="handleLedgerRowChange" |
| | | > |
| | | <el-table-column prop="month" label="æä»½" width="120" /> |
| | | <el-table-column prop="batchNo" label="æ¹æ¬¡å·" width="180" /> |
| | | <el-table-column prop="importTime" label="导å
¥æ¶é´" min-width="180" /> |
| | | <el-table-column prop="importUser" label="导å
¥äºº" width="120" /> |
| | | <el-table-column prop="remark" label="夿³¨" min-width="220" show-overflow-tooltip /> |
| | | </el-table> |
| | | </el-card> |
| | | |
| | | <el-card shadow="never" class="matrix-card"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ åææ¬æç»ï¼{{ activeLedgerRow?.month || "-" }}ï¼</span> |
| | | <span class="meta">æ¹æ¬¡ï¼{{ activeLedgerRow?.batchNo || "-" }}</span> |
| | | </div> |
| | | </template> |
| | | <el-table :data="matrixRows" border class="matrix-table" :row-class-name="getRowClassName"> |
| | | <el-table-column prop="itemName" label="项ç®åç§°" min-width="180" /> |
| | | <el-table-column |
| | | v-for="column in productColumns" |
| | | :key="column.key" |
| | | :prop="column.key" |
| | | :label="column.label" |
| | | min-width="130" |
| | | align="right" |
| | | > |
| | | <template #default="{ row }"> |
| | | {{ formatNumber(row[column.key]) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from "vue"; |
| | | |
| | | const getCurrentMonth = () => { |
| | | const now = new Date(); |
| | | const year = now.getFullYear(); |
| | | const month = String(now.getMonth() + 1).padStart(2, "0"); |
| | | return `${year}-${month}`; |
| | | }; |
| | | |
| | | const queryForm = ref({ |
| | | month: getCurrentMonth(), |
| | | batchNo: "", |
| | | }); |
| | | |
| | | const ledgerRows = ref([ |
| | | { |
| | | id: 1, |
| | | month: "2026-01", |
| | | batchNo: "SC-202601-001", |
| | | importTime: "2026-01-05 09:18:22", |
| | | importUser: "çä¼è®¡", |
| | | remark: "æåæ åææ¬å¯¼å
¥", |
| | | matrix: buildMatrixData(), |
| | | }, |
| | | { |
| | | id: 2, |
| | | month: "2026-02", |
| | | batchNo: "SC-202602-001", |
| | | importTime: "2026-02-03 10:08:16", |
| | | importUser: "æä¼è®¡", |
| | | remark: "æäº§åæ´æ°äººå·¥ä¸è´¹ç¨å£å¾", |
| | | matrix: buildMatrixData({ |
| | | yieldA35: 1050, |
| | | yieldA50: 920, |
| | | yieldBoard: 840, |
| | | directMaterialA35: 12.4, |
| | | directMaterialA50: 11.9, |
| | | directMaterialBoard: 9.2, |
| | | }), |
| | | }, |
| | | { |
| | | id: 3, |
| | | month: "2026-03", |
| | | batchNo: "SC-202603-001", |
| | | importTime: "2026-03-04 14:32:09", |
| | | importUser: "çä¼è®¡", |
| | | remark: "ææå¯¼å
¥æ åææ¬", |
| | | matrix: buildMatrixData({ |
| | | yieldA35: 1100, |
| | | yieldA50: 960, |
| | | yieldBoard: 900, |
| | | directMaterialA35: 12.9, |
| | | directMaterialA50: 12.1, |
| | | directMaterialBoard: 9.6, |
| | | }), |
| | | }, |
| | | ]); |
| | | |
| | | const activeLedgerId = ref(ledgerRows.value[0]?.id || null); |
| | | |
| | | const batchOptions = computed(() => { |
| | | return ledgerRows.value.map((row) => ({ |
| | | label: `${row.batchNo}ï¼${row.month}ï¼`, |
| | | value: row.batchNo, |
| | | })); |
| | | }); |
| | | |
| | | const filteredLedgerRows = computed(() => { |
| | | return ledgerRows.value.filter((row) => { |
| | | const byMonth = !queryForm.value.month || row.month === queryForm.value.month; |
| | | const byBatch = !queryForm.value.batchNo || row.batchNo === queryForm.value.batchNo; |
| | | return byMonth && byBatch; |
| | | }); |
| | | }); |
| | | |
| | | const activeLedgerRow = computed(() => { |
| | | const list = filteredLedgerRows.value; |
| | | const target = list.find((row) => row.id === activeLedgerId.value); |
| | | return target || list[0] || null; |
| | | }); |
| | | |
| | | const matrixRows = computed(() => activeLedgerRow.value?.matrix || []); |
| | | |
| | | const productColumns = [ |
| | | { key: "a35", label: "å æ°å-A3.5" }, |
| | | { key: "a50", label: "å æ°å-A5.0" }, |
| | | { key: "board", label: "æ¿æ" }, |
| | | { key: "total", label: "综å" }, |
| | | ]; |
| | | |
| | | function buildMatrixData(override = {}) { |
| | | const yieldA35 = override.yieldA35 ?? 980; |
| | | const yieldA50 = override.yieldA50 ?? 860; |
| | | const yieldBoard = override.yieldBoard ?? 800; |
| | | const directMaterialA35 = override.directMaterialA35 ?? 12.6; |
| | | const directMaterialA50 = override.directMaterialA50 ?? 11.7; |
| | | const directMaterialBoard = override.directMaterialBoard ?? 9.1; |
| | | const manufacturingA35 = 3.2; |
| | | const manufacturingA50 = 3.5; |
| | | const manufacturingBoard = 2.8; |
| | | const mgmtA35 = 1.4; |
| | | const mgmtA50 = 1.2; |
| | | const mgmtBoard = 1.0; |
| | | const salesA35 = 0.9; |
| | | const salesA50 = 0.8; |
| | | const salesBoard = 0.7; |
| | | const financeA35 = 0.4; |
| | | const financeA50 = 0.3; |
| | | const financeBoard = 0.2; |
| | | const offSeasonA35 = 1.1; |
| | | const offSeasonA50 = 1.0; |
| | | const offSeasonBoard = 0.8; |
| | | |
| | | const subtotalA35 = directMaterialA35 + manufacturingA35; |
| | | const subtotalA50 = directMaterialA50 + manufacturingA50; |
| | | const subtotalBoard = directMaterialBoard + manufacturingBoard; |
| | | |
| | | const totalA35 = subtotalA35 + mgmtA35 + salesA35 + financeA35 + offSeasonA35; |
| | | const totalA50 = subtotalA50 + mgmtA50 + salesA50 + financeA50 + offSeasonA50; |
| | | const totalBoard = subtotalBoard + mgmtBoard + salesBoard + financeBoard + offSeasonBoard; |
| | | |
| | | return [ |
| | | { |
| | | itemName: "产é", |
| | | a35: yieldA35, |
| | | a50: yieldA50, |
| | | board: yieldBoard, |
| | | total: yieldA35 + yieldA50 + yieldBoard, |
| | | }, |
| | | { |
| | | itemName: "ç´æ¥ææåæ¹ææ¬", |
| | | a35: directMaterialA35, |
| | | a50: directMaterialA50, |
| | | board: directMaterialBoard, |
| | | total: (directMaterialA35 + directMaterialA50 + directMaterialBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "å¶é è´¹ç¨", |
| | | a35: manufacturingA35, |
| | | a50: manufacturingA50, |
| | | board: manufacturingBoard, |
| | | total: (manufacturingA35 + manufacturingA50 + manufacturingBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "çäº§ææ¬å°è®¡", |
| | | a35: subtotalA35, |
| | | a50: subtotalA50, |
| | | board: subtotalBoard, |
| | | total: (subtotalA35 + subtotalA50 + subtotalBoard) / 3, |
| | | isSubtotal: true, |
| | | }, |
| | | { |
| | | itemName: "管çè´¹ç¨", |
| | | a35: mgmtA35, |
| | | a50: mgmtA50, |
| | | board: mgmtBoard, |
| | | total: (mgmtA35 + mgmtA50 + mgmtBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "éå®è´¹ç¨", |
| | | a35: salesA35, |
| | | a50: salesA50, |
| | | board: salesBoard, |
| | | total: (salesA35 + salesA50 + salesBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "è´¢å¡è´¹ç¨", |
| | | a35: financeA35, |
| | | a50: financeA50, |
| | | board: financeBoard, |
| | | total: (financeA35 + financeA50 + financeBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "æ·¡å£è´¹ç¨-çäº§ææ¬", |
| | | a35: offSeasonA35, |
| | | a50: offSeasonA50, |
| | | board: offSeasonBoard, |
| | | total: (offSeasonA35 + offSeasonA50 + offSeasonBoard) / 3, |
| | | }, |
| | | { |
| | | itemName: "å计", |
| | | a35: totalA35, |
| | | a50: totalA50, |
| | | board: totalBoard, |
| | | total: (totalA35 + totalA50 + totalBoard) / 3, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | function handleQuery() { |
| | | if (filteredLedgerRows.value.length > 0) { |
| | | activeLedgerId.value = filteredLedgerRows.value[0].id; |
| | | return; |
| | | } |
| | | activeLedgerId.value = null; |
| | | } |
| | | |
| | | function handleReset() { |
| | | queryForm.value.month = getCurrentMonth(); |
| | | queryForm.value.batchNo = ""; |
| | | handleQuery(); |
| | | } |
| | | |
| | | function handleLedgerRowChange(row) { |
| | | if (!row) return; |
| | | activeLedgerId.value = row.id; |
| | | } |
| | | |
| | | function getRowClassName({ row }) { |
| | | return row.isSubtotal ? "is-subtotal-row" : ""; |
| | | } |
| | | |
| | | function formatNumber(value) { |
| | | if (typeof value !== "number") return "-"; |
| | | if (Number.isInteger(value)) return value.toLocaleString("zh-CN"); |
| | | return value.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .standard-cost-ledger-page { |
| | | padding: 16px; |
| | | background: #f6f8fa; |
| | | min-height: calc(100vh - 100px); |
| | | } |
| | | |
| | | .query-card, |
| | | .ledger-card, |
| | | .matrix-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .meta { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | .matrix-table :deep(.is-subtotal-row td) { |
| | | background: #fff200 !important; |
| | | } |
| | | </style> |