Browse Source

refactor(forecast): 重构预测列表页面,使用主从表结构展示数据

yz 2 weeks ago
parent
commit
d18cb76b3d
2 changed files with 113 additions and 116 deletions
  1. 101 105
      src/views/forecast/forecastIndex.js
  2. 12 11
      src/views/forecast/index.vue

+ 101 - 105
src/views/forecast/forecastIndex.js

@@ -1,7 +1,7 @@
 import { getForecastList, addForecast, updateForecast } from '@/api/forecast'
 import { getCustomerList } from '@/api/common'
 import { getItemList } from '@/api/common'
-import { getSalesForecastSummaryPage } from '@/api/forecast/forecast-summary'
+import { getSalesForecastMainList } from '@/api/forecast/forecast-summary'
 import {
   APPROVAL_STATUS,
   APPROVAL_STATUS_CONFIG,
@@ -10,7 +10,9 @@ import {
   getApprovalStatusType,
   canEdit,
   FORECAST_FORM_RULES,
-  DEFAULT_FORECAST_FORM
+  DEFAULT_FORECAST_FORM,
+  // 数字格式化
+  formatNumber as formatNum
 } from '@/constants/forecast'
 import { mapGetters } from 'vuex'
 import ForecastFormAvue from '@/components/forecast-form/index'
@@ -100,7 +102,11 @@ export default {
         addBtnText: '新增预测申报',
         editBtnText: '编辑',
         // 添加这个配置来完全隐藏操作列
+        // 并启用行展开功能以展示子表
         menu: false,
+        expand: true,
+        expandRowKeys: [],
+        defaultExpandAll: false,
         column: [
           {
             label: '年份',
@@ -134,51 +140,11 @@ export default {
             width: 100
           },
           {
-            label: '物料名称',
-            prop: 'itemName',
-            search: false,
-            width: 200,
-            overHidden: true
-          },
-          {
-            label: '物料编码',
-            prop: 'itemCode',
-            search: false,
-            width: 150,
-            overHidden: true
-          },
-          {
-            label: '规格',
-            prop: 'specs',
-            search: false,
-            width: 150,
-            overHidden: true
-          },
-          {
-            label: '预测数量',
-            prop: 'forecastQuantity',
-            type: 'number',
-            precision: 0,
-            search: false,
-            width: 120,
-            align: 'right',
-            slot: true
-          },
-          {
-            label: '当前库存',
-            prop: 'currentInventory',
-            type: 'number',
-            precision: 0,
-            search: false,
-            width: 120,
-            align: 'right',
-            slot: true
-          },
-          {
-            label: '品牌名称',
-            prop: 'brandName',
-            search: false,
-            width: 120,
+            label: '客户名称',
+            prop: 'customerName',
+            search: true,
+            searchSpan: 6,
+            width: 180,
             overHidden: true
           },
           {
@@ -207,29 +173,6 @@ export default {
             width: 160
           },
           {
-            label: '预测编码',
-            prop: 'forecastCode',
-            search: false,
-            searchSpan: 6,
-            width: 150,
-            overHidden: true
-          },
-          {
-            label: '客户名称',
-            prop: 'customerName',
-            search: true,
-            searchSpan: 6,
-            width: 180,
-            overHidden: true
-          },
-          {
-            label: '客户编码',
-            prop: 'customerCode',
-            search: false,
-            width: 150,
-            overHidden: true
-          },
-          {
             label: '创建时间',
             prop: 'createTime',
             type: 'datetime',
@@ -237,7 +180,7 @@ export default {
             search: false,
             width: 160
           },
-          // 添加自定义编辑按钮列
+          // 自定义操作列(保持占位,不可编辑)
           {
             label: '操作',
             prop: 'editBtn',
@@ -247,6 +190,30 @@ export default {
           }
         ]
       },
+      // 子表(展开区)表格配置:展示 pcBladeSalesForecastSummaryList
+      childOption: {
+        height: 'auto',
+        calcHeight: 0,
+        tip: false,
+        searchShow: false,
+        border: true,
+        index: true,
+        viewBtn: false,
+        editBtn: false,
+        delBtn: false,
+        addBtn: false,
+        selection: false,
+        menu: false,
+        expand: false,
+        column: [
+          { label: '商品编码', prop: 'itemCode', minWidth: 120 },
+          { label: '商品名称', prop: 'itemName', minWidth: 180, overHidden: true },
+          { label: '规格型号', prop: 'specs', minWidth: 140, overHidden: true },
+          { label: '花型/图案', prop: 'pattern', minWidth: 120, overHidden: true },
+          { label: '品牌名称', prop: 'brandName', minWidth: 120, overHidden: true },
+          { label: '预测数量', prop: 'forecastQuantity', minWidth: 120, align: 'right', slot: true }
+        ]
+      },
       /** @type {Record<string, Array<ValidationRule>>} 表单验证规则 */
       formRules: FORECAST_FORM_RULES
     }
@@ -470,6 +437,25 @@ export default {
      */
     getApprovalStatusType,
 
+    // 数字格式化(用于子表数量显示)
+    formatNumber(value) {
+      return formatNum(value)
+    },
+
+    /**
+     * 安全将值转换为BigInt
+     * @param {string|number|null|undefined} v
+     * @returns {bigint|null}
+     */
+    safeBigInt(v) {
+      try {
+        if (v === null || v === undefined || v === '') return null
+        return BigInt(v)
+      } catch (e) {
+        return null
+      }
+    },
+
     /**
      * 检查是否可以编辑
      * @param {ForecastRecord|ForecastItem} row - 行数据
@@ -533,8 +519,8 @@ export default {
       },
 
     /**
-     * 加载数据
-     * @this {Vue & {loading: boolean, page: {pageSize: number, currentPage: number, total: number}, query: Record<string, any>, data: Array<ForecastRecord>, $message: any}}
+     * 加载数据(切换为主表 main-list)
+     * @this {Vue & {loading: boolean, page: {pageSize: number, currentPage: number, total: number}, query: Record<string, any>, data: Array<any>, $message: any}}
      * @param {{currentPage: number, pageSize: number}} page - 分页参数
      * @param {Record<string, any>} params - 查询参数
      * @returns {Promise<void>}
@@ -542,44 +528,54 @@ export default {
     async onLoad(page, params = {}) {
       this.loading = true
       try {
-        // 将 year/month 搜索条件转换为 startMonth/endMonth
-        const q = { ...this.query, ...params }
-        const year = q.year
-        const month = q.month
-        const pad = (n) => String(n).padStart(2, '0')
-        /** @type {Record<string, any>} */
-        const filterParams = {}
-        if (year && month) {
-          filterParams.startMonth = `${year}-${pad(month)}`
-          filterParams.endMonth = `${year}-${pad(month)}`
-        } else if (year && !month) {
-          filterParams.startMonth = `${year}-01`
-          filterParams.endMonth = `${year}-12`
+        // 仅挑选 main-list 支持的查询参数
+        const merged = { ...this.query, ...params }
+        const safeParams = {
+          year: merged.year,
+          month: merged.month,
+          customerName: merged.customerName
         }
-        if (q.startDate) filterParams.startDate = q.startDate
-        if (q.endDate) filterParams.endDate = q.endDate
-        if (q.brandName) filterParams.brandName = q.brandName
-
-        const res = await getSalesForecastSummaryPage(page.currentPage, page.pageSize, filterParams)
-        if (res.data && (res.data.success || res.data.code === 200)) {
-          const data = res.data.data || {}
-          const records = Array.isArray(data.records) ? data.records : []
-          this.page.total = Number(data.total || 0)
-          // 字段兼容转换:确保页面所需字段存在
-          this.data = records.map(r => ({
-            ...r,
-            // 兼容旧列表字段:部分接口无此字段则回退
-            forecastCode: r.forecastCode || '',
-            currentInventory: r.currentInventory != null ? r.currentInventory : 0
-          }))
+
+        const response = await getSalesForecastMainList(
+          page.currentPage || 1,
+          page.pageSize || 10,
+          safeParams
+        )
+
+        if (response && response.data && response.data.code === 200 && response.data.data) {
+          const pageData = response.data.data
+          const records = Array.isArray(pageData.records) ? pageData.records : []
+          // 字段类型转换与BigInt处理
+          this.data = records.map(r => {
+            const children = Array.isArray(r.pcBladeSalesForecastSummaryList)
+              ? r.pcBladeSalesForecastSummaryList.map(it => ({
+                  ...it,
+                  idBigint: this.safeBigInt(it.id),
+                  forecastMainIdBigint: it.forecastMainId != null ? this.safeBigInt(it.forecastMainId) : null,
+                  year: Number(it.year),
+                  month: Number(it.month),
+                  forecastQuantity: typeof it.forecastQuantity === 'string' ? Number(it.forecastQuantity) : Number(it.forecastQuantity)
+                }))
+              : []
+            return {
+              ...r,
+              idBigint: this.safeBigInt(r.id),
+              year: Number(r.year),
+              month: Number(r.month),
+              pcBladeSalesForecastSummaryList: children
+            }
+          })
+          this.page.total = Number(pageData.total) || 0
+          this.page.currentPage = Number(pageData.current) || 1
+          this.page.pageSize = Number(pageData.size) || 10
         } else {
-          this.$message.error(res.data?.msg || '加载数据失败')
+          this.$message.error(response?.data?.message || '获取数据失败')
           this.data = []
           this.page.total = 0
         }
       } catch (error) {
-        console.error('加载数据失败:', error)
-        this.$message.error('加载数据失败,请稍后重试')
+        console.error('获取预测主表分页列表失败:', error)
+        this.$message.error('获取数据失败,请稍后重试')
         this.data = []
         this.page.total = 0
       } finally {

+ 12 - 11
src/views/forecast/index.vue

@@ -34,16 +34,6 @@
           </el-button>
         </template>
 
-        <!-- 自定义预测数量显示 -->
-        <template slot-scope="{row}" slot="forecastQuantity">
-          <span>{{ parseInt(row.forecastQuantity || 0) }}</span>
-        </template>
-
-        <!-- 自定义当前库存显示 -->
-        <template slot-scope="{row}" slot="currentInventory">
-          <span>{{ parseInt(row.currentInventory || 0) }}</span>
-        </template>
-
         <!-- 自定义审批状态显示 -->
         <template slot-scope="{row}" slot="approvalStatus">
           <el-tag
@@ -54,11 +44,22 @@
           </el-tag>
         </template>
 
+        <!-- 行展开插槽 - 显示主表对应的子表(pcBladeSalesForecastSummaryList) -->
+        <template slot="expand" slot-scope="{row}">
+          <avue-crud
+            :option="childOption"
+            :data="row.pcBladeSalesForecastSummaryList || []"
+          >
+            <template slot-scope="{row}" slot="forecastQuantity">
+              <span>{{ formatNumber(row.forecastQuantity || 0) }}</span>
+            </template>
+          </avue-crud>
+        </template>
+
         <!-- 自定义操作列:不可编辑按钮 -->
         <template slot="editBtn" slot-scope="{ row, index }">
           <el-button type="text" size="small" disabled>不可编辑</el-button>
         </template>
-
       </avue-crud>
     </div>