Browse Source

feat(经销商库存): 新增经销商库存管理功能模块

yz 2 months ago
parent
commit
e3cd7e1440

+ 92 - 0
src/api/dealer/inventory.js

@@ -0,0 +1,92 @@
+/**
+ * 经销商库存管理API接口
+ * @fileoverview 提供经销商库存列表查询和详情查看功能
+ */
+
+import request from '@/router/axios'
+
+/**
+ * 经销商库存记录类型定义
+ * @typedef {Object} DealerInventoryRecord
+ * @property {string} id - 库存记录ID
+ * @property {string} createUser - 创建用户ID
+ * @property {string} createDept - 创建部门ID
+ * @property {string} createTime - 创建时间
+ * @property {string} updateUser - 更新用户ID
+ * @property {string} updateTime - 更新时间
+ * @property {number} status - 状态 1-正常 0-禁用
+ * @property {number} isDeleted - 是否删除 0-未删除 1-已删除
+ * @property {number} customerId - 客户ID
+ * @property {string} customerCode - 客户编码
+ * @property {string} customerName - 客户名称
+ * @property {number} itemId - 物料ID
+ * @property {string} itemCode - 物料编码
+ * @property {string} itemName - 物料名称
+ * @property {string} specs - 规格型号
+ * @property {string} currentInventory - 当前库存数量
+ */
+
+/**
+ * 分页查询参数类型定义
+ * @typedef {Object} InventoryListParams
+ * @property {number} current - 当前页码
+ * @property {number} size - 每页大小
+ * @property {string} [customerCode] - 客户编码(可选)
+ * @property {string} [customerName] - 客户名称(可选)
+ * @property {string} [itemCode] - 物料编码(可选)
+ * @property {string} [itemName] - 物料名称(可选)
+ */
+
+/**
+ * API响应数据类型定义
+ * @typedef {Object} ApiResponse
+ * @property {number} code - 响应状态码
+ * @property {boolean} success - 是否成功
+ * @property {string} msg - 响应消息
+ * @property {Object} data - 响应数据
+ */
+
+/**
+ * 分页响应数据类型定义
+ * @typedef {Object} PageResponse
+ * @property {DealerInventoryRecord[]} records - 数据记录列表
+ * @property {number} total - 总记录数
+ * @property {number} size - 每页大小
+ * @property {number} current - 当前页码
+ * @property {number} pages - 总页数
+ * @property {boolean} searchCount - 是否查询总数
+ * @property {boolean} optimizeCountSql - 是否优化count查询
+ * @property {boolean} hitCount - 是否命中缓存
+ * @property {Array} orders - 排序信息
+ * @property {string|null} countId - count查询ID
+ * @property {number|null} maxLimit - 最大限制
+ */
+
+/**
+ * 获取经销商库存列表
+ * @param {InventoryListParams} params - 查询参数
+ * @returns {Promise<AxiosResponse<ApiResponse<PageResponse>>>} 返回分页数据
+ */
+export const getInventoryList = (params) => {
+  return request({
+    url: '/api/blade-factory/api/factory/dealer-inventory',
+    method: 'get',
+    params: {
+      current: params.current || 1,
+      size: params.size || 20,
+      ...params
+    }
+  })
+}
+
+/**
+ * 获取经销商库存详情
+ * @param {string} inventoryId - 库存记录ID
+ * @returns {Promise<AxiosResponse<ApiResponse<DealerInventoryRecord>>>} 返回库存详情
+ */
+export const getInventoryDetail = (inventoryId) => {
+  return request({
+    url: `/api/blade-factory/api/factory/dealer-inventory/${inventoryId}`,
+    method: 'get'
+  })
+}

+ 360 - 0
src/mixins/dealer/dealerInventoryIndex.js

@@ -0,0 +1,360 @@
+/**
+ * 经销商库存管理页面 Mixin
+ * @fileoverview 提供经销商库存列表查询、详情查看等功能的混入
+ */
+
+import { getInventoryList, getInventoryDetail } from '@/api/dealer/inventory'
+import { mapGetters } from 'vuex'
+
+/**
+ * 经销商库存管理mixin
+ * 提供库存列表查询、详情查看等功能
+ */
+export default {
+  data() {
+    return {
+      // 表格数据
+      /** @type {import('@/api/dealer/inventory').DealerInventoryRecord[]} */
+      tableData: [],
+      loading: false,
+
+      // 分页信息
+      /** @type {{currentPage: number, pageSize: number, total: number}} */
+      pagination: {
+        currentPage: 1,
+        pageSize: 20,
+        total: 0
+      },
+
+      // 搜索表单
+      /** @type {{customerCode: string, customerName: string, itemCode: string, itemName: string}} */
+      searchForm: {
+        customerCode: '',
+        customerName: '',
+        itemCode: '',
+        itemName: ''
+      },
+
+      // 详情对话框控制
+      detailDialogVisible: false,
+      detailLoading: false,
+
+      // 当前查看的库存详情
+      /** @type {import('@/api/dealer/inventory').DealerInventoryRecord|null} */
+      currentInventoryDetail: null,
+
+      // avue-crud配置
+      option: {
+        height: 'auto',
+        calcHeight: 30,
+        tip: false,
+        searchShow: true,
+        searchMenuSpan: 6,
+        border: true,
+        index: true,
+        selection: false,
+        viewBtn: true,
+        addBtn: false,
+        editBtn: false,
+        delBtn: false,
+        dialogClickModal: false,
+        dialogWidth: 800,
+        labelWidth: 120,
+        column: [
+          {
+            label: '客户编码',
+            prop: 'customerCode',
+            search: true,
+            minWidth: 120,
+            overHidden: true
+          },
+          {
+            label: '客户名称',
+            prop: 'customerName',
+            search: true,
+            minWidth: 180,
+            overHidden: true
+          },
+          {
+            label: '物料编码',
+            prop: 'itemCode',
+            search: true,
+            minWidth: 140,
+            overHidden: true
+          },
+          {
+            label: '物料名称',
+            prop: 'itemName',
+            search: true,
+            minWidth: 200,
+            overHidden: true
+          },
+          {
+            label: '规格型号',
+            prop: 'specs',
+            minWidth: 150,
+            overHidden: true
+          },
+          {
+            label: '当前库存',
+            prop: 'currentInventory',
+            minWidth: 120,
+            align: 'right',
+            sortable: true
+          },
+          {
+            label: '创建时间',
+            prop: 'createTime',
+            minWidth: 160,
+            type: 'datetime',
+            format: 'yyyy-MM-dd HH:mm:ss',
+            valueFormat: 'yyyy-MM-dd HH:mm:ss'
+          },
+          {
+            label: '更新时间',
+            prop: 'updateTime',
+            minWidth: 160,
+            type: 'datetime',
+            format: 'yyyy-MM-dd HH:mm:ss',
+            valueFormat: 'yyyy-MM-dd HH:mm:ss'
+          }
+        ]
+      }
+    }
+  },
+
+  computed: {
+    ...mapGetters(['permission', 'userInfo'])
+  },
+
+  mounted() {
+    this.loadTableData()
+  },
+
+  methods: {
+    /**
+     * 加载表格数据
+     * @returns {Promise<void>}
+     */
+    async loadTableData() {
+      try {
+        this.loading = true
+
+        const params = {
+          current: this.pagination.currentPage,
+          size: this.pagination.pageSize,
+          ...this.searchForm
+        }
+
+        const response= await getInventoryList(params)
+
+        if (response.data && response.data.success) {
+          const { records, total } = response.data.data
+          this.tableData = records || []
+          this.pagination.total = total || 0
+        } else {
+          this.$message.error(response.data?.msg || '获取库存列表失败')
+          this.tableData = []
+          this.pagination.total = 0
+        }
+        this.loading = false
+      } catch (error) {
+        this.loading = false
+        console.error('加载库存列表失败:', error)
+        this.$message.error('获取库存列表失败,请稍后重试')
+        this.tableData = []
+        this.pagination.total = 0
+      } finally {
+        this.loading = false
+      }
+    },
+
+    /**
+     * 搜索处理
+     * @returns {void}
+     */
+    handleSearch() {
+      this.pagination.currentPage = 1
+      this.loadTableData()
+    },
+
+    /**
+     * 重置搜索
+     * @returns {void}
+     */
+    handleResetSearch() {
+      this.searchForm = {
+        customerCode: '',
+        customerName: '',
+        itemCode: '',
+        itemName: ''
+      }
+      this.pagination.currentPage = 1
+      this.loadTableData()
+    },
+
+    /**
+     * 每页大小改变
+     * @param {number} size - 新的每页大小
+     * @returns {void}
+     */
+    handleSizeChange(size) {
+      this.pagination.pageSize = size
+      this.pagination.currentPage = 1
+      this.loadTableData()
+    },
+
+    /**
+     * 当前页改变
+     * @param {number} page - 新的页码
+     * @returns {void}
+     */
+    handleCurrentChange(page) {
+      this.pagination.currentPage = page
+      this.loadTableData()
+    },
+
+    /**
+     * 查看库存详情
+     * @param {import('@/api/dealer/inventory').DealerInventoryRecord} row - 库存记录
+     * @returns {Promise<void>}
+     */
+    async handleViewDetail(row) {
+      try {
+        this.detailLoading = true
+        this.detailDialogVisible = true
+
+        const response = await getInventoryDetail(row.id)
+
+        if (response.data && response.data.success) {
+          this.currentInventoryDetail = response.data.data
+        } else {
+          this.$message.error(response.data?.msg || '获取库存详情失败')
+          this.detailDialogVisible = false
+        }
+      } catch (error) {
+        console.error('获取库存详情失败:', error)
+        this.$message.error('获取库存详情失败,请稍后重试')
+        this.detailDialogVisible = false
+      } finally {
+        this.detailLoading = false
+      }
+    },
+
+    /**
+     * 关闭详情对话框
+     * @returns {void}
+     */
+    handleCloseDetail() {
+      this.detailDialogVisible = false
+      this.currentInventoryDetail = null
+    },
+
+    /**
+     * avue-crud的onLoad事件处理
+     * @param {Object} page - 分页信息
+     * @param {Object} params - 查询参数
+     * @returns {void}
+     */
+    onLoad(page, params = {}) {
+      this.pagination.currentPage = page.currentPage
+      this.pagination.pageSize = page.pageSize
+      Object.assign(this.searchForm, params)
+      this.loadTableData()
+    },
+
+    /**
+     * avue-crud的搜索改变事件处理
+     * @param {Object} params - 搜索参数
+     * @returns {void}
+     */
+    searchChange(params) {
+    //   Object.assign(this.searchForm, params)
+    //   this.handleSearch()
+      Object.assign(this.searchForm, params)
+      this.pagination.currentPage = 1
+      this.loadTableData().finally(() => {
+        // 调用done回调函数,通知avue-crud搜索完成
+        if (typeof done === 'function') {
+          done()
+        }
+      })
+    },
+
+    /**
+     * avue-crud的搜索重置事件处理
+     * @returns {void}
+     */
+    searchReset() {
+    //   this.handleResetSearch()
+      this.searchForm = {
+        customerCode: '',
+        customerName: '',
+        itemCode: '',
+        itemName: ''
+      }
+      this.pagination.currentPage = 1
+      this.loadTableData().finally(() => {
+        // 调用done回调函数,通知avue-crud重置完成
+        if (typeof done === 'function') {
+          done()
+        }
+      })
+    },
+
+    /**
+     * avue-crud的当前页改变事件处理
+     * @param {number} currentPage - 当前页
+     * @returns {void}
+     */
+    currentChange(currentPage) {
+      this.handleCurrentChange(currentPage)
+    },
+
+    /**
+     * avue-crud的每页大小改变事件处理
+     * @param {number} pageSize - 每页大小
+     * @returns {void}
+     */
+    sizeChange(pageSize) {
+      this.handleSizeChange(pageSize)
+    },
+
+    /**
+     * avue-crud的刷新事件处理
+     * @returns {void}
+     */
+    refreshChange() {
+      this.loadTableData()
+    },
+
+    /**
+     * 格式化库存数量显示
+     * @param {string|number} inventory - 库存数量
+     * @returns {string} 格式化后的库存数量
+     */
+    formatInventory(inventory) {
+      if (inventory === null || inventory === undefined || inventory === '') {
+        return '0'
+      }
+      const num = parseFloat(inventory)
+      return isNaN(num) ? '0' : num.toFixed(4).replace(/\.?0+$/, '')
+    },
+
+    /**
+     * 获取库存状态样式
+     * @param {string|number} inventory - 库存数量
+     * @returns {string} CSS类名
+     */
+    getInventoryClass(inventory) {
+      const num = parseFloat(inventory)
+      if (isNaN(num) || num <= 0) {
+        return 'inventory-zero'
+      } else if (num < 10) {
+        return 'inventory-low'
+      } else {
+        return 'inventory-normal'
+      }
+    }
+  }
+}

+ 22 - 0
src/router/views/index.js

@@ -103,6 +103,28 @@ export default [
         ]
     },
     {
+        path: "/dealer-inventory",
+        component: Layout,
+        redirect: "/dealer-inventory/index",
+        meta: {
+            icon: "el-icon-goods",
+            title: "经销商库存管理",
+            keepAlive: true
+        },
+        children: [
+            {
+                path: "index",
+                name: "经销商库存管理",
+                component: () => import("@/views/dealer/inventory/index"),
+                meta: {
+                    keepAlive: true,
+                    isAuth: true,
+                    title: "经销商库存管理"
+                }
+            }
+        ]
+    },
+    {
         path: "/survey",
         component: Layout,
         redirect: "/survey/index",

+ 79 - 0
src/views/dealer/inventory/index.scss

@@ -0,0 +1,79 @@
+/**
+ * 经销商库存管理页面样式
+ */
+
+.detail-container {
+  min-height: 200px;
+  
+  .el-descriptions {
+    margin-top: 20px;
+  }
+}
+
+.dialog-footer {
+  text-align: right;
+  
+  .el-button {
+    margin-left: 10px;
+  }
+}
+
+// 库存数量状态样式
+.inventory-zero {
+  color: #f56c6c;
+  font-weight: bold;
+}
+
+.inventory-low {
+  color: #e6a23c;
+  font-weight: bold;
+}
+
+.inventory-normal {
+  color: #67c23a;
+  font-weight: bold;
+}
+
+// 表格样式优化
+::v-deep .avue-crud {
+  .el-table {
+    .el-table__row {
+      cursor: pointer;
+      
+      &:hover {
+        background-color: #f5f7fa;
+      }
+    }
+  }
+  
+  // 搜索区域样式
+  .avue-crud__search {
+    padding: 20px;
+    background-color: #fff;
+    border-radius: 4px;
+    margin-bottom: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+  
+  // 表格区域样式
+  .avue-crud__main {
+    background-color: #fff;
+    border-radius: 4px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .detail-container {
+    .el-descriptions {
+      ::v-deep .el-descriptions__body {
+        .el-descriptions__table {
+          .el-descriptions__cell {
+            padding: 8px;
+          }
+        }
+      }
+    }
+  }
+}

+ 105 - 0
src/views/dealer/inventory/index.vue

@@ -0,0 +1,105 @@
+<template>
+  <basic-container>
+    <avue-crud
+      ref="crud"
+      :option="option"
+      :table-loading="loading"
+      :data="tableData"
+      :page.sync="pagination"
+      @search-change="searchChange"
+      @search-reset="searchReset"
+      @current-change="currentChange"
+      @size-change="sizeChange"
+      @refresh-change="refreshChange"
+      @on-load="onLoad"
+      @row-click="handleViewDetail"
+    >
+      <!-- 自定义库存数量列 -->
+      <template slot="currentInventory" slot-scope="{row}">
+        <span :class="getInventoryClass(row.currentInventory)">
+          {{ formatInventory(row.currentInventory) }}
+        </span>
+      </template>
+      
+      <!-- 自定义操作列 -->
+      <!-- <template slot-scope="scope" slot="menu">
+        <el-button
+          type="text"
+          size="small"
+          plain
+          class="none-border"
+          @click.stop="handleViewDetail(scope.row)"
+        >
+          详情
+        </el-button>
+      </template> -->
+    </avue-crud>
+    
+    <!-- 库存详情对话框 -->
+    <el-dialog
+      title="库存详情"
+      :visible.sync="detailDialogVisible"
+      width="600px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <div v-loading="detailLoading" class="detail-container">
+        <el-descriptions
+          v-if="currentInventoryDetail"
+          :column="2"
+          border
+          size="medium"
+        >
+          <el-descriptions-item label="客户编码">
+            {{ currentInventoryDetail.customerCode }}
+          </el-descriptions-item>
+          <el-descriptions-item label="客户名称">
+            {{ currentInventoryDetail.customerName }}
+          </el-descriptions-item>
+          <el-descriptions-item label="物料编码">
+            {{ currentInventoryDetail.itemCode }}
+          </el-descriptions-item>
+          <el-descriptions-item label="物料名称">
+            {{ currentInventoryDetail.itemName }}
+          </el-descriptions-item>
+          <el-descriptions-item label="规格型号" :span="2">
+            {{ currentInventoryDetail.specs }}
+          </el-descriptions-item>
+          <el-descriptions-item label="当前库存">
+            <span :class="getInventoryClass(currentInventoryDetail.currentInventory)">
+              {{ formatInventory(currentInventoryDetail.currentInventory) }}
+            </span>
+          </el-descriptions-item>
+          <el-descriptions-item label="状态">
+            <el-tag :type="currentInventoryDetail.status === 1 ? 'success' : 'danger'">
+              {{ currentInventoryDetail.status === 1 ? '正常' : '禁用' }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="创建时间">
+            {{ currentInventoryDetail.createTime }}
+          </el-descriptions-item>
+          <el-descriptions-item label="更新时间">
+            {{ currentInventoryDetail.updateTime }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+      
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="handleCloseDetail">关闭</el-button>
+      </div>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+import dealerInventoryIndexMixin from '@/mixins/dealer/dealerInventoryIndex'
+
+export default {
+  name: 'DealerInventory',
+  mixins: [dealerInventoryIndexMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+@import './index.scss';
+</style>