From afacd28d1593ce4698d83e239dc82440c7d945ad Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 30 三月 2026 17:18:44 +0800
Subject: [PATCH] 生产成品核算页面部分接口对接

---
 src/views/costAccounting/productionCostAccounting/index.vue | 1782 ++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 1,037 insertions(+), 745 deletions(-)

diff --git a/src/views/costAccounting/productionCostAccounting/index.vue b/src/views/costAccounting/productionCostAccounting/index.vue
index 8fc60c2..c1bc7fe 100644
--- a/src/views/costAccounting/productionCostAccounting/index.vue
+++ b/src/views/costAccounting/productionCostAccounting/index.vue
@@ -1,14 +1,17 @@
 <template>
   <div class="production-cost-page">
-    <el-card class="filter-card" shadow="never">
+    <el-card class="filter-card"
+             shadow="never">
       <template #header>
         <div class="card-head">
           <div class="card-head-left">
-            <el-icon class="card-icon ui-icon"><DataLine /></el-icon>
+            <el-icon class="card-icon ui-icon">
+              <DataLine />
+            </el-icon>
             <span class="card-title">鐢熶骇鎴愭湰鏍哥畻</span>
             <span class="subtle">鎴愭湰 = 危 鎶曞叆閲� 脳 瀵瑰簲鍗曚环</span>
           </div>
-          <div class="card-head-right">
+          <!-- <div class="card-head-right">
             <el-radio-group
               v-model="statisticsType"
               size="small"
@@ -17,96 +20,87 @@
               <el-radio-button label="day">鎸夋棩</el-radio-button>
               <el-radio-button label="month">鎸夋湀</el-radio-button>
             </el-radio-group>
-          </div>
+          </div> -->
         </div>
       </template>
-
       <div class="filter-layout">
-        <el-form :model="searchForm" :inline="true" class="filter-form">
+        <el-form :model="searchForm"
+                 :inline="true"
+                 class="filter-form">
           <el-form-item label="鏃堕棿鑼冨洿">
-            <el-date-picker
-              v-if="statisticsType === 'day'"
-              v-model="searchForm.dateRange"
-              type="daterange"
-              range-separator="鑷�"
-              start-placeholder="寮�濮嬫棩鏈�"
-              end-placeholder="缁撴潫鏃ユ湡"
-              value-format="YYYY-MM-DD"
-              class="w-260"
-              @change="handleQuery"
-            />
-            <el-date-picker
-              v-else
-              v-model="searchForm.monthRange"
-              type="monthrange"
-              range-separator="鑷�"
-              start-placeholder="寮�濮嬫湀浠�"
-              end-placeholder="缁撴潫鏈堜唤"
-              value-format="YYYY-MM"
-              class="w-260"
-              @change="handleQuery"
-            />
+            <el-date-picker v-if="statisticsType === 'day'"
+                            v-model="searchForm.dateRange"
+                            type="daterange"
+                            range-separator="鑷�"
+                            start-placeholder="寮�濮嬫棩鏈�"
+                            end-placeholder="缁撴潫鏃ユ湡"
+                            value-format="YYYY-MM-DD"
+                            class="w-260"
+                            @change="handleQuery" />
+            <el-date-picker v-else
+                            v-model="searchForm.monthRange"
+                            type="monthrange"
+                            range-separator="鑷�"
+                            start-placeholder="寮�濮嬫湀浠�"
+                            end-placeholder="缁撴潫鏈堜唤"
+                            value-format="YYYY-MM"
+                            class="w-260"
+                            @change="handleQuery" />
           </el-form-item>
           <el-form-item label="浜у搧绫诲埆">
-            <el-select
-              v-model="searchForm.category"
-              clearable
-              filterable
-              placeholder="鍏ㄩ儴绫诲埆"
-              class="w-180"
-              @change="handleQuery"
-            >
-              <el-option
-                v-for="item in categoryOptions"
-                :key="item"
-                :label="item"
-                :value="item"
-              />
+            <el-select v-model="searchForm.dictCode"
+                       clearable
+                       filterable
+                       placeholder="鍏ㄩ儴绫诲埆"
+                       class="w-180"
+                       @change="handleQuery">
+              <el-option v-for="item in categoryOptions"
+                         :key="item.dictCode"
+                         :label="item.dictLabel"
+                         :value="item.dictCode" />
             </el-select>
           </el-form-item>
           <el-form-item label="鐢熶骇璁㈠崟">
-            <el-select
-              v-model="searchForm.orderNo"
-              clearable
-              filterable
-              placeholder="鍏ㄩ儴璁㈠崟"
-              class="w-180"
-              @change="handleQuery"
-            >
-              <el-option
-                v-for="item in orderOptions"
-                :key="item"
-                :label="item"
-                :value="item"
-              />
+            <el-select v-model="searchForm.productOrderId"
+                       clearable
+                       filterable
+                       placeholder="鍏ㄩ儴璁㈠崟"
+                       class="w-180"
+                       @change="handleQuery">
+              <el-option v-for="order in orderList"
+                         :key="order.id"
+                         :label="`${order.npsNo}`"
+                         :value="order.id" />
             </el-select>
           </el-form-item>
         </el-form>
         <div class="filter-actions">
-          <el-button class="lux-btn" type="primary" @click="handleQuery">
+          <el-button class="lux-btn"
+                     type="primary"
+                     @click="handleQuery">
             鍒锋柊
           </el-button>
-          <el-button class="lux-btn" @click="handleReset">閲嶇疆</el-button>
-          <el-button class="lux-btn" type="success" plain @click="handleExport">
+          <el-button class="lux-btn"
+                     @click="handleReset">閲嶇疆</el-button>
+          <el-button class="lux-btn"
+                     type="success"
+                     plain
+                     @click="handleExport">
             瀵煎嚭
           </el-button>
         </div>
       </div>
     </el-card>
-
-    <el-card class="panel-card" shadow="never">
+    <el-card class="panel-card"
+             shadow="never">
       <div class="kpi-strip">
         <div class="kpi-item kpi-total">
           <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>
@@ -114,28 +108,37 @@
         </div>
       </div>
     </el-card>
-
-    <el-row :gutter="14" class="summary-row">
+    <el-row :gutter="14"
+            class="summary-row">
       <el-col :span="12">
-        <el-card class="table-card" shadow="never">
+        <el-card class="table-card"
+                 shadow="never">
           <template #header>
             <div class="panel-head">
               <span class="card-title">鎸変骇鍝佺被鍒眹鎬�</span>
             </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">
+          <el-table :data="categorySummary"
+                    stripe
+                    class="lux-table"
+                    height="260">
+            <el-table-column prop="name"
+                             label="浜у搧绫诲埆"
+                             min-width="140" />
+            <el-table-column prop="quantity"
+                             label="鐢ㄩ噺"
+                             align="right"
+                             min-width="120">
               <template #default="scope">
-                <span class="price-value">{{ formatMoney(scope.row.rawCost) }}</span>
+                <span class="quantity-cell">
+                  <span class="quantity-value">{{ formatNumber(scope.row.quantity, 2) }}</span>
+                  <span class="quantity-unit">{{ scope.row.unit || "-" }}</span>
+                </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>
@@ -144,16 +147,37 @@
         </el-card>
       </el-col>
       <el-col :span="12">
-        <el-card class="table-card" shadow="never">
+        <el-card class="table-card"
+                 shadow="never">
           <template #header>
             <div class="panel-head">
               <span class="card-title">鎸夌敓浜ц鍗曟眹鎬�</span>
             </div>
           </template>
-          <el-table :data="orderSummary" stripe class="lux-table" height="260">
-            <el-table-column prop="orderNo" label="鐢熶骇璁㈠崟" min-width="150" />
-            <el-table-column prop="category" label="浜у搧绫诲埆" min-width="120" />
-            <el-table-column prop="totalCost" label="鎬绘垚鏈�(鍏�)" align="right">
+          <el-table :data="orderSummary"
+                    stripe
+                    class="lux-table"
+                    height="260">
+            <el-table-column prop="name"
+                             label="鐢熶骇璁㈠崟"
+                             min-width="150" />
+            <el-table-column prop="strength"
+                             label="浜у搧绫诲埆"
+                             min-width="120" />
+            <el-table-column prop="quantity"
+                             label="鐢ㄩ噺"
+                             align="right"
+                             min-width="120">
+              <template #default="scope">
+                <span class="quantity-cell">
+                  <span class="quantity-value">{{ formatNumber(scope.row.quantity, 2) }}</span>
+                  <span class="quantity-unit">{{ scope.row.unit || "-" }}</span>
+                </span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="totalCost"
+                             label="鎬绘垚鏈�(鍏�)"
+                             align="right">
               <template #default="scope">
                 <span class="cost-value">楼{{ formatMoney(scope.row.totalCost) }}</span>
               </template>
@@ -162,63 +186,41 @@
         </el-card>
       </el-col>
     </el-row>
-
-    <el-card class="table-card" shadow="never">
-      <template #header>
-        <div class="panel-head">
-          <span class="card-title">澶氱淮搴︽眹鎬绘槑缁�</span>
-          <span class="subtle">{{ timeColumnLabel }} + 浜у搧绫诲埆 + 鐢熶骇璁㈠崟</span>
-        </div>
-      </template>
-
-      <el-table :data="pagedTableData" stripe class="lux-table">
-        <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>
+    <el-row :gutter="14"
+            class="summary-row">
+      <el-col :span="12">
+        <el-card class="table-card"
+                 shadow="never">
+          <template #header>
+            <div class="panel-head">
+              <span class="card-title">浜у搧鐗╂枡Top10</span>
+            </div>
           </template>
-        </el-table-column>
-        <el-table-column prop="auxCost" label="杈呮枡鎴愭湰(鍏�)" align="right">
-          <template #default="scope">
-            <span class="price-value">{{ formatMoney(scope.row.auxCost) }}</span>
+          <div ref="topOrdersChartRef"
+               class="chart-container"
+               style="height: 300px;"></div>
+        </el-card>
+      </el-col>
+      <el-col :span="12">
+        <el-card class="table-card"
+                 shadow="never">
+          <template #header>
+            <div class="panel-head">
+              <span class="card-title">鐢熶骇璁㈠崟Top10</span>
+            </div>
           </template>
-        </el-table-column>
-        <el-table-column prop="totalCost" label="鎬绘垚鏈�(鍏�)" align="right">
-          <template #default="scope">
-            <span class="cost-value">楼{{ formatMoney(scope.row.totalCost) }}</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="鎷嗗垎鏄庣粏" width="92" fixed="right">
-          <template #default="scope">
-            <el-button link type="primary" @click="openDetail(scope.row)">鏌ョ湅</el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-      <div class="pagination-container">
-        <el-pagination
-          v-model:current-page="page.current"
-          v-model:page-size="page.size"
-          :page-sizes="[10, 20, 50, 100]"
-          :total="tableData.length"
-          layout="total, sizes, prev, pager, next, jumper"
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
-      </div>
-    </el-card>
-
-    <el-drawer
-      v-model="detailVisible"
-      :with-header="false"
-      class="detail-drawer"
-      size="760px"
-      :close-on-click-modal="true"
-      :close-on-press-escape="true"
-      destroy-on-close
-    >
-      <div v-if="detailRow" class="drawer-head">
+        </el-card>
+      </el-col>
+    </el-row>
+    <el-drawer v-model="detailVisible"
+               :with-header="false"
+               class="detail-drawer"
+               size="760px"
+               :close-on-click-modal="true"
+               :close-on-press-escape="true"
+               destroy-on-close>
+      <div v-if="detailRow"
+           class="drawer-head">
         <div class="meta-item">
           <span class="meta-label">{{ timeColumnLabel }}</span>
           <span class="meta-value">{{ detailRow.timeLabel }}</span>
@@ -232,19 +234,16 @@
           <span class="meta-value">{{ detailRow.orderNo }}</span>
         </div>
       </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">
+      <el-table :data="detailMaterials"
+                class="lux-table"
+                stripe>
+        <el-table-column prop="materialName"
+                         label="鐗╂枡鍚嶇О"
+                         min-width="120" />
+        <el-table-column prop="quantity"
+                         label="鎶曞叆閲�"
+                         align="right"
+                         min-width="140">
           <template #default="scope">
             <span class="quantity-cell">
               <span class="quantity-value">{{ formatNumber(scope.row.quantity, 2) }}</span>
@@ -252,28 +251,25 @@
             </span>
           </template>
         </el-table-column>
-        <el-table-column prop="unitPrice" label="鍗曚环(鍏�)" align="right">
+        <el-table-column prop="unitPrice"
+                         label="鍗曚环(鍏�)"
+                         align="right">
           <template #default="scope">
             {{ formatNumber(scope.row.unitPrice, 2) }}
           </template>
         </el-table-column>
-        <el-table-column prop="cost" label="鎴愭湰(鍏�)" align="right" min-width="132">
+        <el-table-column prop="cost"
+                         label="鎴愭湰(鍏�)"
+                         align="right"
+                         min-width="132">
           <template #default="scope">
             <span class="cost-value no-wrap-money">楼{{ formatMoney(scope.row.cost) }}</span>
           </template>
         </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>
@@ -282,624 +278,920 @@
 </template>
 
 <script setup>
-import { computed, reactive, ref, watch } from "vue";
-import { DataLine } from "@element-plus/icons-vue";
-import { ElMessage } from "element-plus";
+  import { computed, reactive, ref, watch, onMounted, nextTick } from "vue";
+  import { DataLine } from "@element-plus/icons-vue";
+  import { ElMessage } from "element-plus";
+  import * as echarts from "echarts";
+  import { getDicts } from "@/api/system/dict/data.js";
+  import { productOrderListPage } from "@/api/productionManagement/productionOrder.js";
+  import {
+    getProductionCostSummary,
+    getProductionCostAggregateByProduct,
+    getProductionCostAggregateByOrder,
+    getProductionCostTopOrders,
+  } from "@/api/costAccounting/productionCost.js";
 
-const statisticsType = ref("day");
+  const statisticsType = ref("day");
 
-const getDefaultDateRange = () => {
-  const end = new Date();
-  const start = new Date();
-  start.setDate(start.getDate() - 6);
-  return [start.toISOString().slice(0, 10), end.toISOString().slice(0, 10)];
-};
-
-const getDefaultMonthRange = () => {
-  const end = new Date();
-  const start = new Date();
-  start.setMonth(start.getMonth() - 2);
-  return [start.toISOString().slice(0, 7), end.toISOString().slice(0, 7)];
-};
-
-const searchForm = reactive({
-  dateRange: getDefaultDateRange(),
-  monthRange: getDefaultMonthRange(),
-  category: "",
-  orderNo: "",
-});
-
-const sourceRecords = ref([
-  { date: "2026-03-17", category: "鐡风爾", orderNo: "PO-260317-01", materialName: "闄剁摲绮�", materialType: "鍘熸枡", quantity: 1200, unit: "kg", unitPrice: 2.8 },
-  { date: "2026-03-17", category: "鐡风爾", orderNo: "PO-260317-01", materialName: "閲夋枡", materialType: "杈呮枡", quantity: 180, unit: "kg", unitPrice: 8.6 },
-  { date: "2026-03-17", category: "姘存偿", orderNo: "PO-260317-02", materialName: "鐔熸枡", materialType: "鍘熸枡", quantity: 2200, unit: "kg", unitPrice: 1.36 },
-  { date: "2026-03-17", category: "姘存偿", orderNo: "PO-260317-02", materialName: "鐭宠啅", materialType: "杈呮枡", quantity: 260, unit: "kg", unitPrice: 0.92 },
-  { date: "2026-03-18", category: "鐮傛祮", orderNo: "PO-260318-01", materialName: "鏈哄埗鐮�", materialType: "鍘熸枡", quantity: 1600, unit: "kg", unitPrice: 0.58 },
-  { date: "2026-03-18", category: "鐮傛祮", orderNo: "PO-260318-01", materialName: "淇濇按鍓�", materialType: "杈呮枡", quantity: 65, unit: "kg", unitPrice: 11.4 },
-  { date: "2026-03-19", category: "鐡风爾", orderNo: "PO-260319-01", materialName: "闄剁摲绮�", materialType: "鍘熸枡", quantity: 980, unit: "kg", unitPrice: 2.9 },
-  { date: "2026-03-19", category: "鐡风爾", orderNo: "PO-260319-01", materialName: "鑹叉枡", materialType: "杈呮枡", quantity: 42, unit: "kg", unitPrice: 15.8 },
-  { date: "2026-03-19", category: "鐮傛祮", orderNo: "PO-260319-03", materialName: "鏈哄埗鐮�", materialType: "鍘熸枡", quantity: 1400, unit: "kg", unitPrice: 0.56 },
-  { date: "2026-03-19", category: "鐮傛祮", orderNo: "PO-260319-03", materialName: "鍑忔按鍓�", materialType: "杈呮枡", quantity: 74, unit: "kg", unitPrice: 7.2 },
-  { date: "2026-03-20", category: "姘存偿", orderNo: "PO-260320-02", materialName: "鐔熸枡", materialType: "鍘熸枡", quantity: 2400, unit: "kg", unitPrice: 1.33 },
-  { date: "2026-03-20", category: "姘存偿", orderNo: "PO-260320-02", materialName: "鐭跨矇", materialType: "杈呮枡", quantity: 380, unit: "kg", unitPrice: 1.08 },
-]);
-
-const normalizedRecords = computed(() =>
-  sourceRecords.value.map((item) => {
-    const month = item.date.slice(0, 7);
-    const cost = Number(item.quantity) * Number(item.unitPrice);
-    return { ...item, month, cost };
-  })
-);
-
-const categoryOptions = computed(() =>
-  Array.from(new Set(normalizedRecords.value.map((item) => item.category)))
-);
-
-const orderOptions = computed(() =>
-  Array.from(new Set(normalizedRecords.value.map((item) => item.orderNo)))
-);
-
-const inRange = (value, range) => {
-  if (!Array.isArray(range) || range.length !== 2 || !range[0] || !range[1]) return true;
-  return value >= range[0] && value <= range[1];
-};
-
-const getMonthRangeDays = (monthRange) => {
-  if (!Array.isArray(monthRange) || monthRange.length !== 2 || !monthRange[0] || !monthRange[1]) {
-    return 0;
-  }
-  const [startMonth, endMonth] = monthRange;
-  const startDate = new Date(`${startMonth}-01T00:00:00`);
-  const endDate = new Date(`${endMonth}-01T00:00:00`);
-  if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime()) || startDate > endDate) {
-    return 0;
-  }
-  const endMonthLastDay = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0);
-  const diffMs = endMonthLastDay.getTime() - startDate.getTime();
-  return Math.floor(diffMs / (24 * 60 * 60 * 1000)) + 1;
-};
-
-const buildQueryParams = () => {
-  const isDay = statisticsType.value === "day";
-  const params = {
-    statisticsType: statisticsType.value,
-    category: searchForm.category || undefined,
-    orderNo: searchForm.orderNo || undefined,
+  const getDefaultDateRange = () => {
+    const end = new Date();
+    const start = new Date();
+    start.setDate(start.getDate() - 6);
+    return [start.toISOString().slice(0, 10), end.toISOString().slice(0, 10)];
   };
 
-  if (isDay) {
-    const [startDate, endDate] = searchForm.dateRange || [];
-    params.startDate = startDate;
-    params.endDate = endDate;
-  } else {
-    const [startMonth, endMonth] = searchForm.monthRange || [];
-    params.startMonth = startMonth;
-    params.endMonth = endMonth;
-    params.days = getMonthRangeDays(searchForm.monthRange);
-  }
+  const getDefaultMonthRange = () => {
+    const end = new Date();
+    const start = new Date();
+    start.setMonth(start.getMonth() - 2);
+    return [start.toISOString().slice(0, 7), end.toISOString().slice(0, 7)];
+  };
 
-  return params;
-};
+  const searchForm = reactive({
+    dateRange: getDefaultDateRange(),
+    monthRange: getDefaultMonthRange(),
+    dictCode: "",
+    productOrderId: "",
+  });
 
-const filteredRecords = computed(() =>
-  normalizedRecords.value.filter((item) => {
-    const hitTime =
-      statisticsType.value === "day"
-        ? inRange(item.date, searchForm.dateRange)
-        : inRange(item.month, searchForm.monthRange);
-    const hitCategory = !searchForm.category || item.category === searchForm.category;
-    const hitOrder = !searchForm.orderNo || item.orderNo === searchForm.orderNo;
-    return hitTime && hitCategory && hitOrder;
-  })
-);
+  const sourceRecords = ref([
+    {
+      date: "2026-03-17",
+      category: "鐡风爾",
+      orderNo: "PO-260317-01",
+      materialName: "闄剁摲绮�",
+      materialType: "鍘熸枡",
+      quantity: 1200,
+      unit: "kg",
+      unitPrice: 2.8,
+    },
+    {
+      date: "2026-03-17",
+      category: "鐡风爾",
+      orderNo: "PO-260317-01",
+      materialName: "閲夋枡",
+      materialType: "杈呮枡",
+      quantity: 180,
+      unit: "kg",
+      unitPrice: 8.6,
+    },
+    {
+      date: "2026-03-17",
+      category: "姘存偿",
+      orderNo: "PO-260317-02",
+      materialName: "鐔熸枡",
+      materialType: "鍘熸枡",
+      quantity: 2200,
+      unit: "kg",
+      unitPrice: 1.36,
+    },
+    {
+      date: "2026-03-17",
+      category: "姘存偿",
+      orderNo: "PO-260317-02",
+      materialName: "鐭宠啅",
+      materialType: "杈呮枡",
+      quantity: 260,
+      unit: "kg",
+      unitPrice: 0.92,
+    },
+    {
+      date: "2026-03-18",
+      category: "鐮傛祮",
+      orderNo: "PO-260318-01",
+      materialName: "鏈哄埗鐮�",
+      materialType: "鍘熸枡",
+      quantity: 1600,
+      unit: "kg",
+      unitPrice: 0.58,
+    },
+    {
+      date: "2026-03-18",
+      category: "鐮傛祮",
+      orderNo: "PO-260318-01",
+      materialName: "淇濇按鍓�",
+      materialType: "杈呮枡",
+      quantity: 65,
+      unit: "kg",
+      unitPrice: 11.4,
+    },
+    {
+      date: "2026-03-19",
+      category: "鐡风爾",
+      orderNo: "PO-260319-01",
+      materialName: "闄剁摲绮�",
+      materialType: "鍘熸枡",
+      quantity: 980,
+      unit: "kg",
+      unitPrice: 2.9,
+    },
+    {
+      date: "2026-03-19",
+      category: "鐡风爾",
+      orderNo: "PO-260319-01",
+      materialName: "鑹叉枡",
+      materialType: "杈呮枡",
+      quantity: 42,
+      unit: "kg",
+      unitPrice: 15.8,
+    },
+    {
+      date: "2026-03-19",
+      category: "鐮傛祮",
+      orderNo: "PO-260319-03",
+      materialName: "鏈哄埗鐮�",
+      materialType: "鍘熸枡",
+      quantity: 1400,
+      unit: "kg",
+      unitPrice: 0.56,
+    },
+    {
+      date: "2026-03-19",
+      category: "鐮傛祮",
+      orderNo: "PO-260319-03",
+      materialName: "鍑忔按鍓�",
+      materialType: "杈呮枡",
+      quantity: 74,
+      unit: "kg",
+      unitPrice: 7.2,
+    },
+    {
+      date: "2026-03-20",
+      category: "姘存偿",
+      orderNo: "PO-260320-02",
+      materialName: "鐔熸枡",
+      materialType: "鍘熸枡",
+      quantity: 2400,
+      unit: "kg",
+      unitPrice: 1.33,
+    },
+    {
+      date: "2026-03-20",
+      category: "姘存偿",
+      orderNo: "PO-260320-02",
+      materialName: "鐭跨矇",
+      materialType: "杈呮枡",
+      quantity: 380,
+      unit: "kg",
+      unitPrice: 1.08,
+    },
+  ]);
+  const orderList = ref([]);
 
-const timeColumnLabel = computed(() => (statisticsType.value === "day" ? "鏃ユ湡" : "鏈堜唤"));
+  // 鍔犺浇鐢熶骇璁㈠崟鍒楄〃
+  const loadOrders = () => {
+    productOrderListPage({ pageNum: -1, pageSize: -1 })
+      .then(res => {
+        orderList.value = res.data.records || [];
+      })
+      .finally(() => {});
+  };
+  const normalizedRecords = computed(() =>
+    sourceRecords.value.map(item => {
+      const month = item.date.slice(0, 7);
+      const cost = Number(item.quantity) * Number(item.unitPrice);
+      return { ...item, month, cost };
+    })
+  );
 
-const aggregateBy = (list, keyFn) => {
-  const map = new Map();
-  for (const item of list) {
-    const key = keyFn(item);
-    if (!map.has(key)) {
-      map.set(key, {
-        rawCost: 0,
-        auxCost: 0,
-        totalCost: 0,
-        materials: [],
+  const categoryOptions = ref([]);
+  // 鑾峰彇浜у搧绫诲瀷瀛楀吀
+  const getProductTypeOptions = () => {
+    getDicts("product_type")
+      .then(res => {
+        if (res.code === 200) {
+          categoryOptions.value = res.data;
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇浜у搧绫诲瀷瀛楀吀澶辫触锛�", err);
+      });
+  };
+
+  const orderOptions = computed(() =>
+    Array.from(new Set(normalizedRecords.value.map(item => item.orderNo)))
+  );
+
+  const inRange = (value, range) => {
+    if (!Array.isArray(range) || range.length !== 2 || !range[0] || !range[1])
+      return true;
+    return value >= range[0] && value <= range[1];
+  };
+
+  const getMonthRangeDays = monthRange => {
+    if (
+      !Array.isArray(monthRange) ||
+      monthRange.length !== 2 ||
+      !monthRange[0] ||
+      !monthRange[1]
+    ) {
+      return 0;
+    }
+    const [startMonth, endMonth] = monthRange;
+    const startDate = new Date(`${startMonth}-01T00:00:00`);
+    const endDate = new Date(`${endMonth}-01T00:00:00`);
+    if (
+      Number.isNaN(startDate.getTime()) ||
+      Number.isNaN(endDate.getTime()) ||
+      startDate > endDate
+    ) {
+      return 0;
+    }
+    const endMonthLastDay = new Date(
+      endDate.getFullYear(),
+      endDate.getMonth() + 1,
+      0
+    );
+    const diffMs = endMonthLastDay.getTime() - startDate.getTime();
+    return Math.floor(diffMs / (24 * 60 * 60 * 1000)) + 1;
+  };
+
+  const buildQueryParams = () => {
+    const isDay = statisticsType.value === "day";
+    const params = {
+      statisticsType: statisticsType.value,
+      dictCode: searchForm.dictCode || undefined,
+      productOrderId: searchForm.productOrderId || undefined,
+    };
+
+    if (isDay) {
+      const [startDate, endDate] = searchForm.dateRange || [];
+      params.startDate = startDate;
+      params.endDate = endDate;
+    } else {
+      const [startMonth, endMonth] = searchForm.monthRange || [];
+      params.startMonth = startMonth;
+      params.endMonth = endMonth;
+      params.days = getMonthRangeDays(searchForm.monthRange);
+    }
+
+    return params;
+  };
+
+  const filteredRecords = computed(() =>
+    normalizedRecords.value.filter(item => {
+      const hitTime =
+        statisticsType.value === "day"
+          ? inRange(item.date, searchForm.dateRange)
+          : inRange(item.month, searchForm.monthRange);
+      const hitCategory =
+        !searchForm.dictCode || item.dictCode === searchForm.dictCode;
+      const hitOrder =
+        !searchForm.productOrderId ||
+        item.productOrderId === searchForm.productOrderId;
+      return hitTime && hitCategory && hitOrder;
+    })
+  );
+
+  const timeColumnLabel = computed(() =>
+    statisticsType.value === "day" ? "鏃ユ湡" : "鏈堜唤"
+  );
+
+  const aggregateBy = (list, keyFn) => {
+    const map = new Map();
+    for (const item of list) {
+      const key = keyFn(item);
+      if (!map.has(key)) {
+        map.set(key, {
+          totalCost: 0,
+          totalQuantity: 0,
+          materials: [],
+        });
+      }
+      const bucket = map.get(key);
+      bucket.totalCost += item.cost;
+      bucket.totalQuantity += Number(item.quantity) || 0;
+      bucket.materials.push(item);
+    }
+    return map;
+  };
+
+  const groupedMap = computed(() =>
+    aggregateBy(filteredRecords.value, item => {
+      const timeKey = statisticsType.value === "day" ? item.date : item.month;
+      return `${timeKey}__${item.category}__${item.orderNo}`;
+    })
+  );
+
+  const tableData = computed(() => {
+    const rows = [];
+    for (const [key, val] of groupedMap.value) {
+      const [timeLabel, category, orderNo] = key.split("__");
+      rows.push({
+        key,
+        timeLabel,
+        category,
+        orderNo,
+        totalQuantity: val.totalQuantity,
+        unit: val.materials[0]?.unit || "",
+        totalCost: val.totalCost,
+        materials: val.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);
-  }
-  return map;
-};
+    return rows.sort((a, b) => (a.timeLabel > b.timeLabel ? -1 : 1));
+  });
 
-const groupedMap = computed(() =>
-  aggregateBy(filteredRecords.value, (item) => {
-    const timeKey = statisticsType.value === "day" ? item.date : item.month;
-    return `${timeKey}__${item.category}__${item.orderNo}`;
-  })
-);
+  const page = reactive({
+    current: 1,
+    size: 10,
+  });
 
-const tableData = computed(() => {
-  const rows = [];
-  for (const [key, val] of groupedMap.value) {
-    const [timeLabel, category, orderNo] = key.split("__");
-    rows.push({
-      key,
-      timeLabel,
-      category,
-      orderNo,
-      rawCost: val.rawCost,
-      auxCost: val.auxCost,
-      totalCost: val.totalCost,
-      materials: val.materials,
-    });
-  }
-  return rows.sort((a, b) => (a.timeLabel > b.timeLabel ? -1 : 1));
-});
+  const pagedTableData = computed(() => {
+    const start = (page.current - 1) * page.size;
+    return tableData.value.slice(start, start + page.size);
+  });
 
-const page = reactive({
-  current: 1,
-  size: 10,
-});
+  const categorySummary = ref([]);
+  const orderSummary = ref([]);
+  const topOrders = ref([]);
 
-const pagedTableData = computed(() => {
-  const start = (page.current - 1) * page.size;
-  return tableData.value.slice(start, start + page.size);
-});
+  const overview = ref({
+    totalCost: 0,
+    orderCount: 0,
+    avgCostPerOrder: 0,
+  });
 
-const categorySummary = computed(() => {
-  const map = aggregateBy(filteredRecords.value, (item) => item.category);
-  const rows = [];
-  for (const [category, val] of map) {
-    rows.push({
-      category,
-      rawCost: val.rawCost,
-      auxCost: val.auxCost,
-      totalCost: val.totalCost,
-    });
-  }
-  return rows.sort((a, b) => b.totalCost - a.totalCost);
-});
+  // 鍥捐〃鐩稿叧
+  const topOrdersChartRef = ref(null);
+  let topOrdersChartInstance = null;
 
-const orderSummary = computed(() => {
-  const map = aggregateBy(filteredRecords.value, (item) => item.orderNo);
-  const rows = [];
-  for (const [orderNo, val] of map) {
-    rows.push({
-      orderNo,
-      category: val.materials[0]?.category || "-",
-      totalCost: val.totalCost,
-    });
-  }
-  return rows.sort((a, b) => b.totalCost - a.totalCost);
-});
+  const detailVisible = ref(false);
+  const detailRow = ref(null);
 
-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;
-  return {
-    rawCost,
-    auxCost,
-    totalCost: rawCost + auxCost,
-    orderCount,
-  };
-});
+  const detailMaterials = computed(() => detailRow.value?.materials || []);
 
-const detailVisible = ref(false);
-const detailRow = ref(null);
-
-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 openDetail = (row) => {
-  detailRow.value = row;
-  detailVisible.value = true;
-};
-
-const handleTypeChange = () => {
-  handleQuery();
-};
-
-const handleQuery = () => {
-  page.current = 1;
-  const queryParams = buildQueryParams();
-  console.log("[productionCostAccounting] query params:", queryParams);
-  ElMessage.success("宸叉寜鏉′欢瀹屾垚姹囨��");
-};
-
-const handleReset = () => {
-  searchForm.dateRange = getDefaultDateRange();
-  searchForm.monthRange = getDefaultMonthRange();
-  searchForm.category = "";
-  searchForm.orderNo = "";
-  handleQuery();
-};
-
-const handleSizeChange = (val) => {
-  page.size = val;
-  page.current = 1;
-};
-
-const handleCurrentChange = (val) => {
-  page.current = val;
-};
-
-const handleExport = () => {
-  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(",")
+  const detailTotalCost = computed(() =>
+    detailMaterials.value.reduce((sum, item) => sum + item.cost, 0)
   );
-  const csv = [headers.join(","), ...lines].join("\n");
-  const blob = new Blob(["\uFEFF" + csv], { type: "text/csv;charset=utf-8;" });
-  const url = URL.createObjectURL(blob);
-  const link = document.createElement("a");
-  link.href = url;
-  link.download = `鐢熶骇鎴愭湰姹囨�籣${statisticsType.value}_${Date.now()}.csv`;
-  link.click();
-  URL.revokeObjectURL(url);
-  ElMessage.success("瀵煎嚭鎴愬姛");
-};
 
-const formatMoney = (v) => {
-  const n = Number.parseFloat(v);
-  const value = Number.isFinite(n) ? n : 0;
-  return value.toLocaleString("zh-CN", {
-    minimumFractionDigits: 2,
-    maximumFractionDigits: 2,
+  const openDetail = row => {
+    detailRow.value = row;
+    detailVisible.value = true;
+  };
+
+  // 鍒濆鍖栫敓浜ц鍗昑op10鍥捐〃
+  const initTopOrdersChart = () => {
+    nextTick(() => {
+      if (topOrdersChartRef.value) {
+        topOrdersChartInstance = echarts.init(topOrdersChartRef.value);
+        updateTopOrdersChart();
+      }
+    });
+  };
+
+  // 鏇存柊鐢熶骇璁㈠崟Top10鍥捐〃
+  const updateTopOrdersChart = () => {
+    if (!topOrdersChartInstance) return;
+
+    const data = topOrders.value;
+    const xAxisData = data.map(item => item.name);
+    const seriesData = data.map(item => item.totalCost);
+
+    const option = {
+      tooltip: {
+        trigger: "axis",
+        axisPointer: {
+          type: "shadow",
+        },
+        backgroundColor: "rgba(255, 255, 255, 0.95)",
+        borderColor: "#409EFF",
+        borderWidth: 1,
+        textStyle: { color: "#303133" },
+      },
+      grid: {
+        left: "3%",
+        right: "4%",
+        bottom: "15%",
+        top: "3%",
+        containLabel: true,
+      },
+      xAxis: {
+        type: "category",
+        data: xAxisData,
+        axisLabel: {
+          color: "#606266",
+          rotate: 45,
+        },
+        axisLine: { lineStyle: { color: "#ebeef5" } },
+        splitLine: { show: false },
+      },
+      yAxis: {
+        type: "value",
+        name: "鎴愭湰(鍏�)",
+        nameTextStyle: { color: "#606266" },
+        axisLabel: { color: "#606266" },
+        axisLine: { show: false },
+        splitLine: { lineStyle: { color: "#f0f2f5" } },
+      },
+      series: [
+        {
+          name: "鎴愭湰",
+          type: "bar",
+          data: seriesData,
+          itemStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: "#409EFF" },
+              { offset: 1, color: "#66B1FF" },
+            ]),
+          },
+          barWidth: "60%",
+        },
+      ],
+    };
+
+    topOrdersChartInstance.setOption(option);
+  };
+
+  // 绐楀彛澶у皬鍙樺寲鏃堕噸鏂版覆鏌撳浘琛�
+  const handleResize = () => {
+    topOrdersChartInstance && topOrdersChartInstance.resize();
+  };
+
+  const handleTypeChange = () => {
+    handleQuery();
+  };
+
+  const handleQuery = () => {
+    page.current = 1;
+    // 鏋勫缓API璇锋眰鍙傛暟
+    const apiParams = {
+      startDate: searchForm.dateRange?.[0],
+      endDate: searchForm.dateRange?.[1],
+      dictCode: searchForm.dictCode,
+      productOrderId: searchForm.productOrderId,
+      current: -1,
+      size: -1,
+    };
+
+    // 璋冪敤API鑾峰彇姒傝鏁版嵁
+    getProductionCostSummary(apiParams)
+      .then(res => {
+        if (res.code === 200) {
+          const data = res.data;
+          overview.value = {
+            totalCost: parseFloat(data.totalCost) || 0,
+            orderCount: data.orderCount || 0,
+            avgCostPerOrder: parseFloat(data.averageOrderCost) || 0,
+          };
+        } else {
+          ElMessage.error(res.message || "鑾峰彇姒傝鏁版嵁澶辫触");
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鐢熶骇鎴愭湰姹囨�绘暟鎹け璐ワ細", err);
+        ElMessage.error("绯荤粺寮傚父锛岃幏鍙栨瑙堟暟鎹け璐�");
+      });
+    getProductionCostAggregateByOrder;
+    // 璋冪敤API鑾峰彇鎸変骇鍝佺墿鏂欐眹鎬绘暟鎹�
+    getProductionCostAggregateByProduct(apiParams)
+      .then(res => {
+        if (res.code === 200) {
+          // 鎸夌墿鏂欏悕绉板垎缁勮绠�
+
+          // 杩欓噷绠�鍖栧鐞嗭紝orderSummary鏆傛椂浣跨敤鐩稿悓鐨勬暟鎹�
+          // 瀹為檯椤圭洰涓彲鑳介渶瑕佽皟鐢ㄤ笓闂ㄧ殑API鑾峰彇鎸夎鍗曟眹鎬荤殑鏁版嵁
+          categorySummary.value = res.data.records || [];
+        } else {
+          ElMessage.error(res.message || "鑾峰彇鐗╂枡姹囨�绘暟鎹け璐�");
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鎸変骇鍝佺墿鏂欐眹鎬绘暟鎹け璐ワ細", err);
+        ElMessage.error("绯荤粺寮傚父锛岃幏鍙栫墿鏂欐眹鎬绘暟鎹け璐�");
+      });
+    getProductionCostAggregateByOrder(apiParams)
+      .then(res => {
+        if (res.code === 200) {
+          // 鎸夌墿鏂欏悕绉板垎缁勮绠�
+
+          // 杩欓噷绠�鍖栧鐞嗭紝orderSummary鏆傛椂浣跨敤鐩稿悓鐨勬暟鎹�
+          // 瀹為檯椤圭洰涓彲鑳介渶瑕佽皟鐢ㄤ笓闂ㄧ殑API鑾峰彇鎸夎鍗曟眹鎬荤殑鏁版嵁
+          orderSummary.value = res.data.records || [];
+        } else {
+          ElMessage.error(res.message || "鑾峰彇璁㈠崟姹囨�绘暟鎹け璐�");
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鎸夎鍗曟眹鎬绘暟鎹け璐ワ細", err);
+        ElMessage.error("绯荤粺寮傚父锛岃幏鍙栬鍗曟眹鎬绘暟鎹け璐�");
+      });
+
+    // 璋冪敤API鑾峰彇鐢熶骇璁㈠崟Top10鏁版嵁
+    getProductionCostTopOrders(apiParams)
+      .then(res => {
+        if (res.code === 200) {
+          topOrders.value = res.data || [];
+          updateTopOrdersChart();
+        } else {
+          ElMessage.error(res.message || "鑾峰彇鐢熶骇璁㈠崟Top10鏁版嵁澶辫触");
+        }
+      })
+      .catch(err => {
+        console.error("鑾峰彇鐢熶骇璁㈠崟Top10鏁版嵁澶辫触锛�", err);
+        ElMessage.error("绯荤粺寮傚父锛岃幏鍙栫敓浜ц鍗昑op10鏁版嵁澶辫触");
+      });
+  };
+
+  const handleReset = () => {
+    searchForm.dateRange = getDefaultDateRange();
+    searchForm.monthRange = getDefaultMonthRange();
+    searchForm.dictCode = "";
+    searchForm.productOrderId = "";
+    handleQuery();
+  };
+
+  const handleSizeChange = val => {
+    page.size = val;
+    page.current = 1;
+  };
+
+  const handleCurrentChange = val => {
+    page.current = val;
+  };
+  onMounted(() => {
+    getProductTypeOptions();
+    loadOrders();
+    handleQuery();
+    initTopOrdersChart();
+    window.addEventListener("resize", handleResize);
   });
-};
 
-const formatNumber = (v, digits = 2) => {
-  const n = Number.parseFloat(v);
-  if (!Number.isFinite(n)) return "--";
-  return n.toLocaleString("zh-CN", {
-    minimumFractionDigits: digits,
-    maximumFractionDigits: digits,
+  const handleExport = () => {
+    const headers = [
+      timeColumnLabel.value,
+      "浜у搧绫诲埆",
+      "鐢熶骇璁㈠崟",
+      "鐢ㄩ噺",
+      "鍗曚綅",
+      "鎴愭湰(鍏�)",
+    ];
+    const lines = tableData.value.map(row =>
+      [
+        row.timeLabel,
+        row.category,
+        row.orderNo,
+        row.totalQuantity.toFixed(2),
+        row.unit || "",
+        row.totalCost.toFixed(2),
+      ].join(",")
+    );
+    const csv = [headers.join(","), ...lines].join("\n");
+    const blob = new Blob(["\uFEFF" + csv], { type: "text/csv;charset=utf-8;" });
+    const url = URL.createObjectURL(blob);
+    const link = document.createElement("a");
+    link.href = url;
+    link.download = `鐢熶骇鎴愭湰姹囨�籣${statisticsType.value}_${Date.now()}.csv`;
+    link.click();
+    URL.revokeObjectURL(url);
+    ElMessage.success("瀵煎嚭鎴愬姛");
+  };
+
+  const formatMoney = v => {
+    const n = Number.parseFloat(v);
+    const value = Number.isFinite(n) ? n : 0;
+    return value.toLocaleString("zh-CN", {
+      minimumFractionDigits: 2,
+      maximumFractionDigits: 2,
+    });
+  };
+
+  const formatNumber = (v, digits = 2) => {
+    const n = Number.parseFloat(v);
+    if (!Number.isFinite(n)) return "--";
+    return n.toLocaleString("zh-CN", {
+      minimumFractionDigits: digits,
+      maximumFractionDigits: digits,
+    });
+  };
+
+  watch(tableData, () => {
+    const maxPage = Math.max(1, Math.ceil(tableData.value.length / page.size));
+    if (page.current > maxPage) page.current = maxPage;
   });
-};
-
-watch(tableData, () => {
-  const maxPage = Math.max(1, Math.ceil(tableData.value.length / page.size));
-  if (page.current > maxPage) page.current = maxPage;
-});
 </script>
 
 <style scoped lang="scss">
-.production-cost-page {
-  --lux-bg: #f6f7fb;
-  --lux-card: rgba(255, 255, 255, 0.86);
-  --lux-border: rgba(15, 23, 42, 0.08);
-  --lux-text: rgba(15, 23, 42, 0.92);
-  --lux-subtle: rgba(15, 23, 42, 0.58);
-  --lux-muted: rgba(15, 23, 42, 0.38);
-  --lux-primary: #2f6fed;
-  --lux-success: #16a34a;
-  --lux-warning: #f59e0b;
-  --lux-danger: #ef4444;
-  --lux-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
-  --lux-shadow-soft: 0 10px 28px rgba(15, 23, 42, 0.06);
-  --lux-radius: 14px;
+  .production-cost-page {
+    --lux-bg: #f6f7fb;
+    --lux-card: rgba(255, 255, 255, 0.86);
+    --lux-border: rgba(15, 23, 42, 0.08);
+    --lux-text: rgba(15, 23, 42, 0.92);
+    --lux-subtle: rgba(15, 23, 42, 0.58);
+    --lux-muted: rgba(15, 23, 42, 0.38);
+    --lux-primary: #2f6fed;
+    --lux-success: #16a34a;
+    --lux-warning: #f59e0b;
+    --lux-danger: #ef4444;
+    --lux-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
+    --lux-shadow-soft: 0 10px 28px rgba(15, 23, 42, 0.06);
+    --lux-radius: 14px;
 
-  padding: 18px 22px 24px;
-  background: radial-gradient(
-      1200px 420px at 20% 0%,
-      rgba(47, 111, 237, 0.1),
-      transparent 55%
-    ),
-    linear-gradient(180deg, var(--lux-bg) 0%, #ffffff 58%);
-}
+    padding: 18px 22px 24px;
+    background: radial-gradient(
+        1200px 420px at 20% 0%,
+        rgba(47, 111, 237, 0.1),
+        transparent 55%
+      ),
+      linear-gradient(180deg, var(--lux-bg) 0%, #ffffff 58%);
+  }
 
-.filter-card,
-.panel-card,
-.table-card {
-  border-radius: var(--lux-radius);
-  border-color: var(--lux-border);
-  background: var(--lux-card);
-  box-shadow: var(--lux-shadow-soft);
-}
+  .filter-card,
+  .panel-card,
+  .table-card {
+    border-radius: var(--lux-radius);
+    border-color: var(--lux-border);
+    background: var(--lux-card);
+    box-shadow: var(--lux-shadow-soft);
+  }
 
-.filter-card {
-  margin-bottom: 16px;
-}
+  .filter-card {
+    margin-bottom: 16px;
+  }
 
-.panel-card,
-.summary-row {
-  margin-bottom: 14px;
-}
-
-.filter-layout {
-  display: flex;
-  align-items: flex-start;
-  justify-content: space-between;
-  gap: 14px;
-}
-
-.filter-form {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 10px 14px;
-}
-
-.filter-form :deep(.el-form-item) {
-  margin: 0;
-}
-
-.filter-actions {
-  display: flex;
-  gap: 10px;
-}
-
-.card-head,
-.panel-head {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: 12px;
-}
-
-.card-head-left {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-}
-
-.card-head-right {
-  display: flex;
-  align-items: center;
-}
-
-.card-icon {
-  color: var(--lux-primary);
-}
-
-.card-title {
-  font-weight: 760;
-  color: var(--lux-text);
-}
-
-.subtle {
-  color: var(--lux-subtle);
-  font-size: 12px;
-}
-
-.kpi-strip {
-  display: grid;
-  grid-template-columns: repeat(4, minmax(0, 1fr));
-  gap: 12px;
-}
-
-.kpi-item {
-  padding: 12px 14px;
-  border-radius: 12px;
-  border: 1px solid rgba(15, 23, 42, 0.08);
-}
-
-.kpi-total {
-  background: linear-gradient(135deg, rgba(47, 111, 237, 0.1), rgba(255, 255, 255, 0.86));
-}
-
-.kpi-raw {
-  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-order {
-  background: linear-gradient(135deg, rgba(100, 116, 139, 0.1), rgba(255, 255, 255, 0.86));
-}
-
-.kpi-label {
-  font-size: 12px;
-  color: var(--lux-subtle);
-}
-
-.kpi-value {
-  font-size: 22px;
-  margin-top: 6px;
-  font-weight: 780;
-  color: var(--lux-text);
-}
-
-.price-value {
-  font-weight: 700;
-  color: var(--lux-success);
-}
-
-.cost-value {
-  font-weight: 700;
-  color: var(--lux-danger);
-}
-
-.no-wrap-money {
-  display: inline-block;
-  white-space: nowrap;
-}
-
-.drawer-head {
-  display: grid;
-  grid-template-columns: repeat(3, minmax(0, 1fr));
-  gap: 10px;
-  margin-bottom: 12px;
-}
-
-.meta-item {
-  padding: 10px 12px;
-  border-radius: 10px;
-  border: 1px solid var(--lux-border);
-  background: rgba(15, 23, 42, 0.03);
-  display: grid;
-  gap: 4px;
-}
-
-.meta-label {
-  font-size: 12px;
-  color: var(--lux-subtle);
-}
-
-.meta-value {
-  color: var(--lux-text);
-  font-size: 16px;
-  font-weight: 700;
-}
-
-.material-type-tag {
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-  min-width: 46px;
-  height: 24px;
-  padding: 0 8px;
-  border-radius: 999px;
-  font-size: 12px;
-  font-weight: 700;
-}
-
-.material-type-tag.is-raw {
-  color: #15803d;
-  background: rgba(22, 163, 74, 0.12);
-}
-
-.material-type-tag.is-aux {
-  color: #b45309;
-  background: rgba(245, 158, 11, 0.16);
-}
-
-.quantity-value {
-  font-weight: 700;
-  color: var(--lux-text);
-  margin-right: 6px;
-}
-
-.quantity-cell {
-  display: inline-flex;
-  align-items: baseline;
-  white-space: nowrap;
-}
-
-.quantity-unit {
-  color: var(--lux-subtle);
-}
-
-.drawer-foot {
-  display: flex;
-  justify-content: flex-end;
-  gap: 12px;
-  margin-top: 12px;
-  padding-top: 12px;
-  border-top: 1px dashed var(--lux-border);
-}
-
-.foot-item {
-  display: inline-flex;
-  align-items: center;
-  gap: 8px;
-  padding: 7px 16px;
-  border-radius: 999px;
-  border: 1px solid var(--lux-border);
-  background: #fff;
-}
-
-.foot-label {
-  color: var(--lux-subtle);
-  font-size: 14px;
-}
-
-.foot-value {
-  color: var(--lux-text);
-  font-weight: 700;
-  font-size: 16px;
-}
-
-.foot-item.total {
-  border-color: rgba(47, 111, 237, 0.26);
-  background: rgba(47, 111, 237, 0.08);
-}
-
-.foot-item.total .foot-value {
-  color: #1e3a8a;
-  font-size: 18px;
-  font-weight: 800;
-}
-
-.pagination-container {
-  display: flex;
-  justify-content: flex-end;
-  padding-top: 12px;
-}
-
-.strong {
-  font-weight: 800;
-}
-
-.w-260 {
-  width: 260px;
-}
-
-.w-180 {
-  width: 180px;
-}
-
-::deep(.lux-table) {
-  border-radius: 12px;
-  overflow: hidden;
-}
-
-::deep(.lux-table th.el-table__cell) {
-  background: rgba(15, 23, 42, 0.03);
-}
-
-::deep(.lux-table .el-table__row:hover > td.el-table__cell) {
-  background-color: rgba(47, 111, 237, 0.06) !important;
-}
-
-@media (max-width: 1100px) {
-  .kpi-strip {
-    grid-template-columns: repeat(2, minmax(0, 1fr));
+  .panel-card,
+  .summary-row {
+    margin-bottom: 14px;
   }
 
   .filter-layout {
-    flex-direction: column;
+    display: flex;
+    align-items: flex-start;
+    justify-content: space-between;
+    gap: 14px;
+  }
+
+  .filter-form {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px 14px;
+  }
+
+  .filter-form :deep(.el-form-item) {
+    margin: 0;
+  }
+
+  .filter-actions {
+    display: flex;
+    gap: 10px;
+  }
+
+  .card-head,
+  .panel-head {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 12px;
+  }
+
+  .card-head-left {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .card-head-right {
+    display: flex;
+    align-items: center;
+  }
+
+  .card-icon {
+    color: var(--lux-primary);
+  }
+
+  .card-title {
+    font-weight: 760;
+    color: var(--lux-text);
+  }
+
+  .subtle {
+    color: var(--lux-subtle);
+    font-size: 12px;
+  }
+
+  .kpi-strip {
+    display: grid;
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+    gap: 12px;
+  }
+
+  .kpi-item {
+    padding: 12px 14px;
+    border-radius: 12px;
+    border: 1px solid rgba(15, 23, 42, 0.08);
+  }
+
+  .kpi-total {
+    background: linear-gradient(
+      135deg,
+      rgba(47, 111, 237, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
+  }
+
+  .kpi-raw {
+    background: linear-gradient(
+      135deg,
+      rgba(22, 163, 74, 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 {
+    background: linear-gradient(
+      135deg,
+      rgba(100, 116, 139, 0.1),
+      rgba(255, 255, 255, 0.86)
+    );
+  }
+
+  .kpi-label {
+    font-size: 12px;
+    color: var(--lux-subtle);
+  }
+
+  .kpi-value {
+    font-size: 22px;
+    margin-top: 6px;
+    font-weight: 780;
+    color: var(--lux-text);
+  }
+
+  .price-value {
+    font-weight: 700;
+    color: var(--lux-success);
+  }
+
+  .cost-value {
+    font-weight: 700;
+    color: var(--lux-danger);
+  }
+
+  .no-wrap-money {
+    display: inline-block;
+    white-space: nowrap;
   }
 
   .drawer-head {
-    grid-template-columns: 1fr;
+    display: grid;
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+    gap: 10px;
+    margin-bottom: 12px;
+  }
+
+  .meta-item {
+    padding: 10px 12px;
+    border-radius: 10px;
+    border: 1px solid var(--lux-border);
+    background: rgba(15, 23, 42, 0.03);
+    display: grid;
+    gap: 4px;
+  }
+
+  .meta-label {
+    font-size: 12px;
+    color: var(--lux-subtle);
+  }
+
+  .meta-value {
+    color: var(--lux-text);
+    font-size: 16px;
+    font-weight: 700;
+  }
+
+  .material-type-tag {
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    min-width: 46px;
+    height: 24px;
+    padding: 0 8px;
+    border-radius: 999px;
+    font-size: 12px;
+    font-weight: 700;
+  }
+
+  .material-type-tag.is-raw {
+    color: #15803d;
+    background: rgba(22, 163, 74, 0.12);
+  }
+
+  .material-type-tag.is-aux {
+    color: #b45309;
+    background: rgba(245, 158, 11, 0.16);
+  }
+
+  .quantity-value {
+    font-weight: 700;
+    color: var(--lux-text);
+    margin-right: 6px;
+  }
+
+  .quantity-cell {
+    display: inline-flex;
+    align-items: baseline;
+    white-space: nowrap;
+  }
+
+  .quantity-unit {
+    color: var(--lux-subtle);
   }
 
   .drawer-foot {
-    justify-content: flex-start;
-    flex-wrap: wrap;
+    display: flex;
+    justify-content: flex-end;
+    gap: 12px;
+    margin-top: 12px;
+    padding-top: 12px;
+    border-top: 1px dashed var(--lux-border);
   }
-}
+
+  .foot-item {
+    display: inline-flex;
+    align-items: center;
+    gap: 8px;
+    padding: 7px 16px;
+    border-radius: 999px;
+    border: 1px solid var(--lux-border);
+    background: #fff;
+  }
+
+  .foot-label {
+    color: var(--lux-subtle);
+    font-size: 14px;
+  }
+
+  .foot-value {
+    color: var(--lux-text);
+    font-weight: 700;
+    font-size: 16px;
+  }
+
+  .foot-item.total {
+    border-color: rgba(47, 111, 237, 0.26);
+    background: rgba(47, 111, 237, 0.08);
+  }
+
+  .foot-item.total .foot-value {
+    color: #1e3a8a;
+    font-size: 18px;
+    font-weight: 800;
+  }
+
+  .pagination-container {
+    display: flex;
+    justify-content: flex-end;
+    padding-top: 12px;
+  }
+
+  .strong {
+    font-weight: 800;
+  }
+
+  .w-260 {
+    width: 260px;
+  }
+
+  .w-180 {
+    width: 180px;
+  }
+
+  ::deep(.lux-table) {
+    border-radius: 12px;
+    overflow: hidden;
+  }
+
+  ::deep(.lux-table th.el-table__cell) {
+    background: rgba(15, 23, 42, 0.03);
+  }
+
+  ::deep(.lux-table .el-table__row:hover > td.el-table__cell) {
+    background-color: rgba(47, 111, 237, 0.06) !important;
+  }
+
+  @media (max-width: 1100px) {
+    .kpi-strip {
+      grid-template-columns: repeat(2, minmax(0, 1fr));
+    }
+
+    .filter-layout {
+      flex-direction: column;
+    }
+
+    .drawer-head {
+      grid-template-columns: 1fr;
+    }
+
+    .drawer-foot {
+      justify-content: flex-start;
+      flex-wrap: wrap;
+    }
+  }
 </style>

--
Gitblit v1.9.3