gaoluyang
2025-09-17 28c8c43997baa2dc9301ee75308afa762815890f
采购价格管理前端页面
已添加2个文件
1176 ■■■■■ 文件已修改
src/api/procurementManagement/advancedPriceManagement.js 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/advancedPriceManagement/index.vue 874 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/advancedPriceManagement.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,302 @@
// é«˜çº§é‡‡è´­ä»·æ ¼ç®¡ç†API接口
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢ä»·æ ¼åˆ—表
export function getPriceList(query) {
  return request({
    url: "/procurement/price/list",
    method: "get",
    params: query,
  });
}
// èŽ·å–ä»·æ ¼è¯¦æƒ…
export function getPriceDetail(id) {
  return request({
    url: `/procurement/price/detail/${id}`,
    method: "get",
  });
}
// æ–°å¢žä»·æ ¼
export function addPrice(data) {
  return request({
    url: "/procurement/price/add",
    method: "post",
    data: data,
  });
}
// æ›´æ–°ä»·æ ¼
export function updatePrice(data) {
  return request({
    url: "/procurement/price/update",
    method: "put",
    data: data,
  });
}
// åˆ é™¤ä»·æ ¼
export function deletePrice(id) {
  return request({
    url: `/procurement/price/delete/${id}`,
    method: "delete",
  });
}
// æ‰¹é‡åˆ é™¤ä»·æ ¼
export function batchDeletePrice(ids) {
  return request({
    url: "/procurement/price/batchDelete",
    method: "delete",
    data: { ids },
  });
}
// å¤åˆ¶ä»·æ ¼
export function copyPrice(id) {
  return request({
    url: `/procurement/price/copy/${id}`,
    method: "post",
  });
}
// åº”用价格(将待生效状态改为有效)
export function applyPrice(id) {
  return request({
    url: `/procurement/price/apply/${id}`,
    method: "put",
  });
}
// æš‚停价格
export function suspendPrice(id) {
  return request({
    url: `/procurement/price/suspend/${id}`,
    method: "put",
  });
}
// æ‰¹é‡è®¾ç½®æŠ˜æ‰£
export function batchSetDiscount(data) {
  return request({
    url: "/procurement/price/batchDiscount",
    method: "post",
    data: data,
  });
}
// èŽ·å–æŠ˜æ‰£é…ç½®
export function getDiscountConfig(id) {
  return request({
    url: `/procurement/price/discount/${id}`,
    method: "get",
  });
}
// è®¾ç½®å•个商品折扣
export function setDiscount(data) {
  return request({
    url: "/procurement/price/setDiscount",
    method: "post",
    data: data,
  });
}
// èŽ·å–é˜¶æ¢¯æŠ˜æ‰£é…ç½®
export function getTieredDiscount(id) {
  return request({
    url: `/procurement/price/tieredDiscount/${id}`,
    method: "get",
  });
}
// è®¾ç½®é˜¶æ¢¯æŠ˜æ‰£
export function setTieredDiscount(data) {
  return request({
    url: "/procurement/price/setTieredDiscount",
    method: "post",
    data: data,
  });
}
// èŽ·å–ä»·æ ¼æŽ§åˆ¶è®¾ç½®
export function getPriceControlConfig() {
  return request({
    url: "/procurement/price/controlConfig",
    method: "get",
  });
}
// æ›´æ–°ä»·æ ¼æŽ§åˆ¶è®¾ç½®
export function updatePriceControlConfig(data) {
  return request({
    url: "/procurement/price/controlConfig",
    method: "put",
    data: data,
  });
}
// èŽ·å–ä»·æ ¼é¢„è­¦åˆ—è¡¨
export function getPriceWarnings(query) {
  return request({
    url: "/procurement/price/warnings",
    method: "get",
    params: query,
  });
}
// å¤„理价格预警
export function handlePriceWarning(id, action) {
  return request({
    url: `/procurement/price/warning/${id}`,
    method: "put",
    data: { action },
  });
}
// èŽ·å–ä»·æ ¼åŽ†å²è®°å½•
export function getPriceHistory(id, query) {
  return request({
    url: `/procurement/price/history/${id}`,
    method: "get",
    params: query,
  });
}
// èŽ·å–ä»·æ ¼ç»Ÿè®¡æ•°æ®
export function getPriceStatistics(query) {
  return request({
    url: "/procurement/price/statistics",
    method: "get",
    params: query,
  });
}
// å¯¼å‡ºä»·æ ¼æ•°æ®
export function exportPriceData(query) {
  return request({
    url: "/procurement/price/export",
    method: "get",
    params: query,
    responseType: 'blob',
  });
}
// å¯¼å…¥ä»·æ ¼æ•°æ®
export function importPriceData(file) {
  const formData = new FormData();
  formData.append('file', file);
  return request({
    url: "/procurement/price/import",
    method: "post",
    data: formData,
    headers: {
      'Content-Type': 'multipart/form-data',
    },
  });
}
// èŽ·å–ä»·æ ¼æ¨¡æ¿
export function downloadPriceTemplate() {
  return request({
    url: "/procurement/price/template",
    method: "get",
    responseType: 'blob',
  });
}
// ä»·æ ¼å®¡æ‰¹
export function approvePrice(id, data) {
  return request({
    url: `/procurement/price/approve/${id}`,
    method: "put",
    data: data,
  });
}
// ä»·æ ¼é©³å›ž
export function rejectPrice(id, data) {
  return request({
    url: `/procurement/price/reject/${id}`,
    method: "put",
    data: data,
  });
}
// èŽ·å–ä¾›åº”å•†åˆ—è¡¨ï¼ˆç”¨äºŽä¸‹æ‹‰é€‰æ‹©ï¼‰
export function getSupplierOptions() {
  return request({
    url: "/procurement/price/suppliers",
    method: "get",
  });
}
// èŽ·å–å•†å“åˆ—è¡¨ï¼ˆç”¨äºŽä¸‹æ‹‰é€‰æ‹©ï¼‰
export function getProductOptions(query) {
  return request({
    url: "/procurement/price/products",
    method: "get",
    params: query,
  });
}
// èŽ·å–å•†å“è¯¦ç»†ä¿¡æ¯
export function getProductInfo(productId) {
  return request({
    url: `/procurement/price/productInfo/${productId}`,
    method: "get",
  });
}
// ä»·æ ¼æ¯”较分析
export function comparePrices(data) {
  return request({
    url: "/procurement/price/compare",
    method: "post",
    data: data,
  });
}
// èŽ·å–ä»·æ ¼è¶‹åŠ¿æ•°æ®
export function getPriceTrend(id, period) {
  return request({
    url: `/procurement/price/trend/${id}`,
    method: "get",
    params: { period },
  });
}
// ä»·æ ¼é¢„测
export function predictPrice(id, data) {
  return request({
    url: `/procurement/price/predict/${id}`,
    method: "post",
    data: data,
  });
}
// èŽ·å–å¸‚åœºä»·æ ¼å‚è€ƒ
export function getMarketPriceReference(productCode) {
  return request({
    url: `/procurement/price/marketRef/${productCode}`,
    method: "get",
  });
}
// ä»·æ ¼å˜åŠ¨é€šçŸ¥è®¾ç½®
export function updateNotificationSettings(data) {
  return request({
    url: "/procurement/price/notifications",
    method: "put",
    data: data,
  });
}
// èŽ·å–ä»·æ ¼å˜åŠ¨é€šçŸ¥è®¾ç½®
export function getNotificationSettings() {
  return request({
    url: "/procurement/price/notifications",
    method: "get",
  });
}
src/views/procurementManagement/advancedPriceManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,874 @@
<template>
  <div class="app-container">
    <!-- æœç´¢åŒºåŸŸ -->
    <el-card class="search-card" shadow="never">
      <el-form :model="searchForm" :inline="true" label-width="100px">
        <el-form-item label="商品名称:">
          <el-input v-model="searchForm.productName" placeholder="请输入商品名称" clearable style="width: 200px" />
        </el-form-item>
        <el-form-item label="供应商:">
          <el-select v-model="searchForm.supplierId" placeholder="请选择供应商" clearable style="width: 200px">
            <el-option v-for="supplier in supplierList" :key="supplier.id" :label="supplier.name" :value="supplier.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="价格状态:">
          <el-select v-model="searchForm.priceStatus" placeholder="请选择状态" clearable style="width: 150px">
            <el-option label="有效" value="active" />
            <el-option label="待生效" value="pending" />
            <el-option label="已过期" value="expired" />
            <el-option label="已暂停" value="suspended" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch" :loading="loading">
            <el-icon><Search /></el-icon>
            æœç´¢
          </el-button>
          <el-button @click="resetSearch">
            <el-icon><Refresh /></el-icon>
            é‡ç½®
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- åŠŸèƒ½æŒ‰é’®åŒºåŸŸ -->
    <el-card class="action-card" shadow="never">
      <div class="action-buttons">
        <el-button type="primary" @click="openDialog('add')">
          <el-icon><Plus /></el-icon>
          æ–°å¢žä»·æ ¼
        </el-button>
        <el-button type="success" @click="openBatchDiscountDialog">
          <el-icon><Discount /></el-icon>
          æ‰¹é‡æŠ˜æ‰£
        </el-button>
        <el-button type="warning" @click="openPriceControlDialog">
          <el-icon><Setting /></el-icon>
          ä»·æ ¼æŽ§åˆ¶
        </el-button>
        <el-button type="info" @click="exportData">
          <el-icon><Download /></el-icon>
          å¯¼å‡ºæ•°æ®
        </el-button>
        <el-button type="danger" @click="handleBatchDelete" :disabled="selectedRows.length === 0">
          <el-icon><Delete /></el-icon>
          æ‰¹é‡åˆ é™¤
        </el-button>
      </div>
    </el-card>
    <!-- ä¸»è¡¨æ ¼ -->
    <el-card class="table-card" shadow="never">
      <el-table
        :data="tableData"
        border
        v-loading="loading"
        @selection-change="handleSelectionChange"
        :default-sort="{ prop: 'updateTime', order: 'descending' }"
      >
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="商品信息" min-width="200">
          <template #default="{ row }">
            <div class="product-info">
              <div class="product-name">{{ row.productName }}</div>
              <div class="product-spec">{{ row.specification }}</div>
              <div class="product-code">编码: {{ row.productCode }}</div>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="供应商" prop="supplierName" width="150" />
        <el-table-column label="基础价格" width="120" align="right">
          <template #default="{ row }">
            <span class="price-text">Â¥{{ row.basePrice.toFixed(2) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="折扣信息" width="150">
          <template #default="{ row }">
            <div v-if="row.discountType">
              <el-tag :type="getDiscountTagType(row.discountType)" size="small">
                {{ getDiscountText(row.discountType) }}
              </el-tag>
              <div class="discount-value">{{ row.discountValue }}{{ row.discountType === 'percentage' ? '%' : '元' }}</div>
            </div>
            <span v-else class="no-discount">无折扣</span>
          </template>
        </el-table-column>
        <el-table-column label="实际价格" width="120" align="right">
          <template #default="{ row }">
            <span class="final-price">Â¥{{ calculateFinalPrice(row).toFixed(2) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="价格控制" width="120">
          <template #default="{ row }">
            <div class="price-control">
              <div v-if="row.priceControl?.minPrice" class="control-item">
                æœ€ä½Ž: Â¥{{ row.priceControl.minPrice.toFixed(2) }}
              </div>
              <div v-if="row.priceControl?.maxPrice" class="control-item">
                æœ€é«˜: Â¥{{ row.priceControl.maxPrice.toFixed(2) }}
              </div>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="100" align="center">
          <template #default="{ row }">
            <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag>
            <div v-if="isPriceWarning(row)" class="warning-indicator">
              <el-icon color="#F56C6C"><Warning /></el-icon>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="生效时间" prop="effectiveTime" width="180" />
        <el-table-column label="更新时间" prop="updateTime" width="180" sortable />
        <el-table-column label="操作" width="250" align="center" fixed="right">
          <template #default="{ row }">
            <el-button type="primary" link @click="openDialog('edit', row)">
              <el-icon><Edit /></el-icon>
              ç¼–辑
            </el-button>
            <el-button type="success" link @click="openDiscountDialog(row)">
              <el-icon><Discount /></el-icon>
              æŠ˜æ‰£
            </el-button>
            <el-button type="danger" link @click="handleDelete(row)">
              <el-icon><Delete /></el-icon>
              åˆ é™¤
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- åˆ†é¡µ -->
      <div class="pagination-wrapper">
        <el-pagination
          v-model:current-page="pagination.currentPage"
          v-model:page-size="pagination.pageSize"
          :page-sizes="[10, 20, 50, 100]"
          :total="pagination.total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </el-card>
    <!-- æ–°å¢ž/编辑对话框 -->
    <el-dialog v-model="dialogVisible" :title="dialogType === 'add' ? '新增价格' : '编辑价格'" width="800px">
      <el-form :model="formData" :rules="formRules" ref="formRef" label-width="120px">
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="商品名称" prop="productName">
              <el-select v-model="formData.productName" placeholder="请选择商品" style="width: 100%" filterable>
                <el-option v-for="product in productList" :key="product.id" :label="product.name" :value="product.name" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="商品编码" prop="productCode">
              <el-input v-model="formData.productCode" placeholder="请输入商品编码" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="规格型号" prop="specification">
              <el-input v-model="formData.specification" placeholder="请输入规格型号" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="供应商" prop="supplierName">
              <el-select v-model="formData.supplierName" placeholder="请选择供应商" style="width: 100%">
                <el-option v-for="supplier in supplierList" :key="supplier.id" :label="supplier.name" :value="supplier.name" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="基础价格" prop="basePrice">
              <el-input-number v-model="formData.basePrice" :min="0" :precision="2" placeholder="请输入基础价格" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="单位">
              <el-input v-model="formData.unit" placeholder="请输入单位" />
            </el-form-item>
          </el-col>
        </el-row>
        <!-- æŠ˜æ‰£è®¾ç½® -->
        <el-divider content-position="left">折扣设置</el-divider>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="折扣类型">
              <el-select v-model="formData.discountType" placeholder="请选择折扣类型" style="width: 100%">
                <el-option label="无折扣" value="" />
                <el-option label="百分比折扣" value="percentage" />
                <el-option label="固定金额" value="fixed" />
                <el-option label="阶梯折扣" value="tiered" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="折扣值" v-if="formData.discountType && formData.discountType !== 'tiered'">
              <el-input-number
                v-model="formData.discountValue"
                :min="0"
                :max="formData.discountType === 'percentage' ? 100 : undefined"
                :precision="2"
                placeholder="请输入折扣值"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="折扣有效期">
              <el-date-picker
                v-model="formData.discountEndTime"
                type="datetime"
                placeholder="选择结束时间"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <!-- é˜¶æ¢¯æŠ˜æ‰£è®¾ç½® -->
        <div v-if="formData.discountType === 'tiered'">
          <el-form-item label="阶梯折扣">
            <el-table :data="formData.tieredDiscount" border size="small">
              <el-table-column label="最小数量" width="120">
                <template #default="{ row, $index }">
                  <el-input-number v-model="row.minQty" :min="0" size="small" />
                </template>
              </el-table-column>
              <el-table-column label="最大数量" width="120">
                <template #default="{ row, $index }">
                  <el-input-number v-model="row.maxQty" :min="0" size="small" />
                </template>
              </el-table-column>
              <el-table-column label="折扣率(%)" width="120">
                <template #default="{ row, $index }">
                  <el-input-number v-model="row.discount" :min="0" :max="100" :precision="2" size="small" />
                </template>
              </el-table-column>
              <el-table-column label="操作" width="80">
                <template #default="{ row, $index }">
                  <el-button type="danger" link @click="removeTieredRow($index)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
            <el-button type="primary" link @click="addTieredRow" class="mt-2">添加阶梯</el-button>
          </el-form-item>
        </div>
        <!-- ä»·æ ¼æŽ§åˆ¶ -->
        <el-divider content-position="left">价格控制</el-divider>
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="最低价格">
              <el-input-number v-model="formData.minPrice" :min="0" :precision="2" placeholder="最低价格" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="最高价格">
              <el-input-number v-model="formData.maxPrice" :min="0" :precision="2" placeholder="最高价格" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="预警阈值(%)">
              <el-input-number v-model="formData.warningThreshold" :min="0" :max="100" :precision="1" placeholder="预警阈值" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="生效时间" prop="effectiveTime">
              <el-date-picker v-model="formData.effectiveTime" type="datetime" placeholder="选择生效时间" style="width: 100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="失效时间">
              <el-date-picker v-model="formData.expireTime" type="datetime" placeholder="选择失效时间" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="调价原因" prop="reason">
          <el-select v-model="formData.reason" placeholder="请选择调价原因" style="width: 100%">
            <el-option label="市场价格变动" value="market" />
            <el-option label="成本变化" value="cost" />
            <el-option label="供应商调整" value="supplier" />
            <el-option label="季节性调整" value="seasonal" />
            <el-option label="促销活动" value="promotion" />
            <el-option label="其他原因" value="other" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注信息" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
      </template>
    </el-dialog>
    <!-- æ‰¹é‡æŠ˜æ‰£å¯¹è¯æ¡† -->
    <el-dialog v-model="batchDiscountVisible" title="批量设置折扣" width="600px">
      <el-form :model="batchDiscountForm" label-width="120px">
        <el-form-item label="折扣类型">
          <el-select v-model="batchDiscountForm.discountType" placeholder="请选择折扣类型" style="width: 100%">
            <el-option label="百分比折扣" value="percentage" />
            <el-option label="固定金额" value="fixed" />
          </el-select>
        </el-form-item>
        <el-form-item label="折扣值">
          <el-input-number
            v-model="batchDiscountForm.discountValue"
            :min="0"
            :max="batchDiscountForm.discountType === 'percentage' ? 100 : undefined"
            :precision="2"
            placeholder="请输入折扣值"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item label="生效时间">
          <el-date-picker v-model="batchDiscountForm.effectiveTime" type="datetime" placeholder="选择生效时间" style="width: 100%" />
        </el-form-item>
        <el-form-item label="失效时间">
          <el-date-picker v-model="batchDiscountForm.expireTime" type="datetime" placeholder="选择失效时间" style="width: 100%" />
        </el-form-item>
        <el-form-item label="适用商品">
          <div class="selected-items">
            å·²é€‰æ‹© {{ selectedRows.length }} ä¸ªå•†å“
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="batchDiscountVisible = false">取消</el-button>
        <el-button type="primary" @click="handleBatchDiscount">确定</el-button>
      </template>
    </el-dialog>
    <!-- ä»·æ ¼æŽ§åˆ¶å¯¹è¯æ¡† -->
    <el-dialog v-model="priceControlVisible" title="价格控制设置" width="700px">
      <el-form :model="priceControlForm" label-width="120px">
        <el-form-item label="默认最低价格">
          <el-input-number v-model="priceControlForm.defaultMinPrice" :min="0" :precision="2" style="width: 200px" />
        </el-form-item>
        <el-form-item label="默认最高价格">
          <el-input-number v-model="priceControlForm.defaultMaxPrice" :min="0" :precision="2" style="width: 200px" />
        </el-form-item>
        <el-form-item label="价格变动阈值">
          <el-input-number v-model="priceControlForm.changeThreshold" :min="0" :max="100" :precision="1" style="width: 200px" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="priceControlVisible = false">取消</el-button>
        <el-button type="primary" @click="handlePriceControl">保存设置</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  Search, Refresh, Plus, Discount, Setting, Download, Delete, Edit,
  Warning
} from '@element-plus/icons-vue'
// å“åº”式数据
const loading = ref(false)
const submitLoading = ref(false)
const dialogVisible = ref(false)
const batchDiscountVisible = ref(false)
const priceControlVisible = ref(false)
const dialogType = ref('add')
const selectedRows = ref([])
const formRef = ref()
// æœç´¢è¡¨å•
const searchForm = reactive({
  productName: '',
  supplierId: '',
  priceStatus: ''
})
// åˆ†é¡µ
const pagination = reactive({
  currentPage: 1,
  pageSize: 20,
  total: 0
})
// è¡¨å•数据
const formData = reactive({
  productName: '',
  productCode: '',
  specification: '',
  supplierName: '',
  basePrice: 0,
  unit: '',
  discountType: '',
  discountValue: 0,
  discountEndTime: '',
  tieredDiscount: [],
  minPrice: null,
  maxPrice: null,
  warningThreshold: 10,
  effectiveTime: '',
  expireTime: '',
  reason: '',
  remark: ''
})
// æ‰¹é‡æŠ˜æ‰£è¡¨å•
const batchDiscountForm = reactive({
  discountType: 'percentage',
  discountValue: 0,
  effectiveTime: '',
  expireTime: ''
})
// ä»·æ ¼æŽ§åˆ¶è¡¨å•
const priceControlForm = reactive({
  defaultMinPrice: 0,
  defaultMaxPrice: 0,
  changeThreshold: 10,
})
// è¡¨å•验证规则
const formRules = {
  productName: [{ required: true, message: '请选择商品名称', trigger: 'change' }],
  productCode: [{ required: true, message: '请输入商品编码', trigger: 'blur' }],
  supplierName: [{ required: true, message: '请选择供应商', trigger: 'change' }],
  basePrice: [{ required: true, message: '请输入基础价格', trigger: 'blur' }],
  effectiveTime: [{ required: true, message: '请选择生效时间', trigger: 'change' }],
  reason: [{ required: true, message: '请选择调价原因', trigger: 'change' }]
}
// æ¨¡æ‹Ÿæ•°æ®
const tableData = ref([
  {
    id: 1,
    productName: '高强度螺栓',
    productCode: 'HQ001',
    specification: 'M12×80',
    supplierName: '优质五金供应商',
    basePrice: 2.50,
    discountType: 'percentage',
    discountValue: 10,
    priceControl: { minPrice: 2.00, maxPrice: 3.00 },
    status: 'active',
    effectiveTime: '2025-01-01 00:00:00',
    updateTime: '2025-09-17 10:30:00',
    unit: '个',
    reason: 'market',
    remark: '市场价格调整'
  },
  {
    id: 2,
    productName: '不锈钢管',
    productCode: 'BXG002',
    specification: 'Φ25×2.0',
    supplierName: '钢材贸易公司',
    basePrice: 45.80,
    discountType: 'fixed',
    discountValue: 5,
    priceControl: { minPrice: 40.00, maxPrice: 50.00 },
    status: 'pending',
    effectiveTime: '2025-10-01 00:00:00',
    updateTime: '2025-09-16 14:20:00',
    unit: 'ç±³',
    reason: 'cost',
    remark: '原材料成本上涨'
  }
])
const supplierList = ref([
  { id: 1, name: '优质五金供应商' },
  { id: 2, name: '钢材贸易公司' },
  { id: 3, name: '建材批发商' }
])
const productList = ref([
  { id: 1, name: '高强度螺栓' },
  { id: 2, name: '不锈钢管' },
  { id: 3, name: '铝合金型材' }
])
// è®¡ç®—属性
const finalTableData = computed(() => {
  return tableData.value.filter(item => {
    if (searchForm.productName && !item.productName.includes(searchForm.productName)) return false
    if (searchForm.supplierId && item.supplierId !== searchForm.supplierId) return false
    if (searchForm.priceStatus && item.status !== searchForm.priceStatus) return false
    return true
  })
})
// æ–¹æ³•
const calculateFinalPrice = (row) => {
  let finalPrice = row.basePrice
  if (row.discountType === 'percentage') {
    finalPrice = row.basePrice * (1 - row.discountValue / 100)
  } else if (row.discountType === 'fixed') {
    finalPrice = row.basePrice - row.discountValue
  }
  return Math.max(finalPrice, 0)
}
const getDiscountTagType = (discountType) => {
  const typeMap = {
    percentage: 'success',
    fixed: 'warning',
    tiered: 'info'
  }
  return typeMap[discountType] || 'info'
}
const getDiscountText = (discountType) => {
  const textMap = {
    percentage: '百分比',
    fixed: '固定金额',
    tiered: '阶梯折扣'
  }
  return textMap[discountType] || '未知'
}
const getStatusType = (status) => {
  const statusMap = {
    active: 'success',
    pending: 'warning',
    expired: 'info',
    suspended: 'danger'
  }
  return statusMap[status] || 'info'
}
const getStatusText = (status) => {
  const statusMap = {
    active: '有效',
    pending: '待生效',
    expired: '已过期',
    suspended: '已暂停'
  }
  return statusMap[status] || '未知'
}
const isPriceWarning = (row) => {
  if (!row.priceControl) return false
  const finalPrice = calculateFinalPrice(row)
  return finalPrice < row.priceControl.minPrice || finalPrice > row.priceControl.maxPrice
}
const handleSearch = () => {
  loading.value = true
  // æ¨¡æ‹ŸAPI调用
  setTimeout(() => {
    loading.value = false
  }, 500)
}
const resetSearch = () => {
  Object.assign(searchForm, {
    productName: '',
    supplierId: '',
    priceStatus: ''
  })
  handleSearch()
}
const openDialog = (type, row = {}) => {
  dialogType.value = type
  if (type === 'edit' && row.id) {
    Object.assign(formData, {
      ...row,
      minPrice: row.priceControl?.minPrice,
      maxPrice: row.priceControl?.maxPrice,
      tieredDiscount: row.tieredDiscount || []
    })
  } else {
    resetFormData()
  }
  dialogVisible.value = true
}
const resetFormData = () => {
  Object.assign(formData, {
    productName: '',
    productCode: '',
    specification: '',
    supplierName: '',
    basePrice: 0,
    unit: '',
    discountType: '',
    discountValue: 0,
    discountEndTime: '',
    tieredDiscount: [],
    minPrice: null,
    maxPrice: null,
    warningThreshold: 10,
    effectiveTime: '',
    expireTime: '',
    reason: '',
    remark: ''
  })
}
const addTieredRow = () => {
  formData.tieredDiscount.push({
    minQty: 0,
    maxQty: 0,
    discount: 0
  })
}
const removeTieredRow = (index) => {
  formData.tieredDiscount.splice(index, 1)
}
const handleSubmit = async () => {
  if (!formRef.value) return
  try {
    await formRef.value.validate()
    submitLoading.value = true
    // æ¨¡æ‹ŸAPI调用
    setTimeout(() => {
      if (dialogType.value === 'add') {
        const newItem = {
          id: Date.now(),
          ...formData,
          priceControl: {
            minPrice: formData.minPrice,
            maxPrice: formData.maxPrice
          },
          status: 'pending',
          updateTime: new Date().toLocaleString()
        }
        tableData.value.unshift(newItem)
        ElMessage.success('新增成功')
      } else {
        // ç¼–辑逻辑
        ElMessage.success('编辑成功')
      }
      dialogVisible.value = false
      submitLoading.value = false
    }, 1000)
  } catch (error) {
    console.error('表单验证失败:', error)
  }
}
const openBatchDiscountDialog = () => {
  if (selectedRows.value.length === 0) {
    ElMessage.warning('请先选择要设置折扣的商品')
    return
  }
  batchDiscountVisible.value = true
}
const handleBatchDiscount = () => {
  // æ‰¹é‡è®¾ç½®æŠ˜æ‰£é€»è¾‘
  selectedRows.value.forEach(row => {
    row.discountType = batchDiscountForm.discountType
    row.discountValue = batchDiscountForm.discountValue
  })
  ElMessage.success(`已为 ${selectedRows.value.length} ä¸ªå•†å“è®¾ç½®æŠ˜æ‰£`)
  batchDiscountVisible.value = false
}
const openPriceControlDialog = () => {
  priceControlVisible.value = true
}
const handlePriceControl = () => {
  ElMessage.success('价格控制设置已保存')
  priceControlVisible.value = false
}
const openDiscountDialog = (row) => {
  // å•个商品折扣设置
  openDialog('edit', row)
}
const handleDelete = (row) => {
  ElMessageBox.confirm('确定要删除这条记录吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    const index = tableData.value.findIndex(item => item.id === row.id)
    if (index !== -1) {
      tableData.value.splice(index, 1)
      ElMessage.success('删除成功')
    }
  })
}
const handleBatchDelete = () => {
  if (selectedRows.value.length === 0) {
    ElMessage.warning('请先选择要删除的记录')
    return
  }
  ElMessageBox.confirm(`确定要删除选中的 ${selectedRows.value.length} æ¡è®°å½•吗?`, '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    selectedRows.value.forEach(row => {
      const index = tableData.value.findIndex(item => item.id === row.id)
      if (index !== -1) {
        tableData.value.splice(index, 1)
      }
    })
    ElMessage.success('批量删除成功')
    selectedRows.value = []
  })
}
const handleSelectionChange = (rows) => {
  selectedRows.value = rows
}
const handleSizeChange = (size) => {
  pagination.pageSize = size
  handleSearch()
}
const handleCurrentChange = (page) => {
  pagination.currentPage = page
  handleSearch()
}
const exportData = () => {
  ElMessage.success('数据导出功能开发中...')
}
// ç”Ÿå‘½å‘¨æœŸ
onMounted(() => {
  handleSearch()
})
</script>
<style scoped>
.app-container {
  padding: 20px;
}
.search-card, .action-card, .table-card {
  margin-bottom: 20px;
}
.action-buttons {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.product-info {
  line-height: 1.4;
}
.product-name {
  font-weight: bold;
  color: #303133;
}
.product-spec, .product-code {
  font-size: 12px;
  color: #909399;
}
.price-text {
  font-weight: bold;
  color: #409EFF;
}
.final-price {
  font-weight: bold;
  color: #67C23A;
  font-size: 16px;
}
.discount-value {
  font-size: 12px;
  color: #E6A23C;
  margin-top: 2px;
}
.no-discount {
  color: #C0C4CC;
  font-size: 12px;
}
.price-control {
  font-size: 12px;
  line-height: 1.3;
}
.control-item {
  color: #909399;
}
.warning-indicator {
  margin-top: 2px;
}
.pagination-wrapper {
  display: flex;
  justify-content: end;
  margin-top: 20px;
}
.selected-items {
  color: #409EFF;
  font-weight: bold;
}
.mt-2 {
  margin-top: 8px;
}
.ml-2 {
  margin-left: 8px;
}
:deep(.el-table) {
  font-size: 13px;
}
:deep(.el-table th) {
  background-color: #fafafa;
}
:deep(.el-card__body) {
  padding: 15px;
}
:deep(.el-divider__text) {
  font-weight: bold;
  color: #409EFF;
}
</style>