9
0

2 Ревизии 73b49bbc9a ... a7654911e9

Автор SHA1 Съобщение Дата
  肖路 a7654911e9 Merge remote-tracking branch 'origin/master' into master преди 4 дни
  肖路 f12478d5ff feat(product): 添加商品描述字段并优化表单验证 преди 4 дни

+ 1 - 1
src/api/external/product/types.ts

@@ -414,7 +414,7 @@ export interface ThirdProductVO {
   unitName?: string;
   unitName?: string;
 
 
   /**
   /**
-   * 可用库存数
+   * 现有库存数
    */
    */
   availableStock?: number;
   availableStock?: number;
 
 

+ 7 - 2
src/api/product/base/types.ts

@@ -590,12 +590,17 @@ export interface BaseForm extends BaseEntity {
   supplyPrice?: number;
   supplyPrice?: number;
 
 
   /**
   /**
-   * 供应有效时间
+   * 供应天数
+   */
+  supplyDays?: number;
+
+  /**
+   * 供应有效时间(到期时间)
    */
    */
   supplyValidityPeriod?: string;
   supplyValidityPeriod?: string;
 
 
   /**
   /**
-   * 是否包邮 0=不包邮,1=包邮
+   * 是否支持一件代发 0=不支持,1=支持
    */
    */
   supplyPostStatus?: number;
   supplyPostStatus?: number;
 }
 }

+ 3 - 3
src/api/product/priceInventory/types.ts

@@ -35,7 +35,7 @@ export interface PriceInventoryVO {
   totalInventory: number;
   totalInventory: number;
 
 
   /**
   /**
-   * 当前可用库存
+   * 当前现有库存
    */
    */
   nowInventory: number;
   nowInventory: number;
 
 
@@ -103,7 +103,7 @@ export interface PriceInventoryForm extends BaseEntity {
   totalInventory?: number;
   totalInventory?: number;
 
 
   /**
   /**
-   * 当前可用库存
+   * 当前现有库存
    */
    */
   nowInventory?: number;
   nowInventory?: number;
 
 
@@ -167,7 +167,7 @@ export interface PriceInventoryQuery extends PageQuery {
   totalInventory?: number;
   totalInventory?: number;
 
 
   /**
   /**
-   * 当前可用库存
+   * 当前现有库存
    */
    */
   nowInventory?: number;
   nowInventory?: number;
 
 

+ 3 - 3
src/api/product/warehouseInventory/types.ts

@@ -35,7 +35,7 @@ export interface WarehouseInventoryVO {
   warehouseName: string;
   warehouseName: string;
 
 
   /**
   /**
-   * 可用库存
+   * 现有库存
    */
    */
   nowInventory: number;
   nowInventory: number;
 
 
@@ -93,7 +93,7 @@ export interface WarehouseInventoryForm extends BaseEntity {
   warehouseName?: string;
   warehouseName?: string;
 
 
   /**
   /**
-   * 可用库存
+   * 现有库存
    */
    */
   nowInventory?: number;
   nowInventory?: number;
 
 
@@ -147,7 +147,7 @@ export interface WarehouseInventoryQuery extends PageQuery {
   warehouseName?: string;
   warehouseName?: string;
 
 
   /**
   /**
-   * 可用库存
+   * 现有库存
    */
    */
   nowInventory?: number;
   nowInventory?: number;
 
 

+ 18 - 3
src/components/TaxCodeSelect/index.vue

@@ -68,9 +68,16 @@
                 <el-link :type="isRowDisabled(row) ? 'info' : 'primary'" :disabled="isRowDisabled(row)" :underline="false">{{ row.abbreviation }}</el-link>
                 <el-link :type="isRowDisabled(row) ? 'info' : 'primary'" :disabled="isRowDisabled(row)" :underline="false">{{ row.abbreviation }}</el-link>
               </template>
               </template>
             </el-table-column>
             </el-table-column>
-            <!-- <el-table-column label="说明" align="center" prop="remark" min-width="150" show-overflow-tooltip />
-            <el-table-column label="税率" align="center" prop="taxRate" width="80" />
-            <el-table-column label="用户选择比例" align="center" prop="selectRatio" width="110" /> -->
+            <el-table-column label="说明" align="center" prop="remark" min-width="150" show-overflow-tooltip>
+              <template #default="{ row }">
+                <el-link :type="isRowDisabled(row) ? 'info' : 'primary'" :disabled="isRowDisabled(row)" :underline="false">{{ row.remark }}</el-link>
+              </template>
+            </el-table-column>
+            <el-table-column label="税率" align="center" prop="explain" width="90">
+              <template #default="{ row }">
+                <el-link :type="isRowDisabled(row) ? 'info' : 'primary'" :disabled="isRowDisabled(row)" :underline="false">{{ formatTaxRate(row.taxrate) }}</el-link>
+              </template>
+            </el-table-column>
           </el-table>
           </el-table>
 
 
           <!-- 分页 -->
           <!-- 分页 -->
@@ -203,6 +210,14 @@ const handleSearch = () => {
   getList();
   getList();
 };
 };
 
 
+/** 格式化税率为百分制显示 */
+const formatTaxRate = (val: any): string => {
+  if (val === null || val === undefined || val === '') return '';
+  const num = Number(val);
+  if (isNaN(num)) return String(val);
+  return `${Math.round(num * 100)}%`;
+};
+
 /** 判断行是否禁用:非叶子节点(isBottom === 0)不可选 */
 /** 判断行是否禁用:非叶子节点(isBottom === 0)不可选 */
 const isRowDisabled = (row: TaxCodeVO): boolean => {
 const isRowDisabled = (row: TaxCodeVO): boolean => {
   return Number((row as any)?.isBottom) === 0;
   return Number((row as any)?.isBottom) === 0;

+ 5 - 5
src/components/upload-image/index.vue

@@ -20,8 +20,8 @@
             </div>
             </div>
           </div>
           </div>
           <div class="w-full h-full flex items-center justify-center flex-col content-wrap" v-else @click="openDialog">
           <div class="w-full h-full flex items-center justify-center flex-col content-wrap" v-else @click="openDialog">
-            <icon name="element Plus" size="20px" color="var(--el-text-color-secondary)" />
-            <div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || '上传图片' }}</div>
+            <el-icon :size="24" color="var(--el-text-color-secondary)"><Plus /></el-icon>
+            <div v-if="imageText !== ''" class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || '上传图片' }}</div>
           </div>
           </div>
         </div>
         </div>
       </template>
       </template>
@@ -68,8 +68,8 @@
             v-if="imagesData.length < limit"
             v-if="imagesData.length < limit"
           >
           >
             <div class="w-full h-full flex items-center justify-center flex-col content-wrap" @click="openDialog">
             <div class="w-full h-full flex items-center justify-center flex-col content-wrap" @click="openDialog">
-              <icon name="element Plus" size="20px" color="var(--el-text-color-secondary)" />
-              <div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || '上传图片' }}</div>
+              <el-icon :size="24" color="var(--el-text-color-secondary)"><Plus /></el-icon>
+              <div v-if="imageText !== ''" class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || '上传图片' }}</div>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
@@ -355,7 +355,7 @@
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
+import { ArrowLeft, ArrowRight, Plus } from '@element-plus/icons-vue';
 import { img } from '@/utils/common';
 import { img } from '@/utils/common';
 import { listFileInfo, delFileInfo, addFileInfo, updateDownloadCount, updateFileInfo } from '@/api/file/info';
 import { listFileInfo, delFileInfo, addFileInfo, updateDownloadCount, updateFileInfo } from '@/api/file/info';
 import { listFileCategoryTree, addFileCategory, updateFileCategory, delFileCategory } from '@/api/file/category';
 import { listFileCategoryTree, addFileCategory, updateFileCategory, delFileCategory } from '@/api/file/category';

+ 237 - 70
src/views/product/base/add.vue

@@ -188,6 +188,18 @@
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
             </el-form-item>
             </el-form-item>
 
 
+                        <!-- 商品描述 -->
+            <el-form-item label="商品描述:">
+              <el-input
+                v-model="productForm.productDescription"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品描述"
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+
             <!-- 规格型号 和 UPC(69)条码 -->
             <!-- 规格型号 和 UPC(69)条码 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
@@ -235,7 +247,7 @@
               </el-col>
               </el-col>
 
 
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="单位:">
+                <el-form-item label="单位:" required>
                   <el-select
                   <el-select
                     v-model="productForm.unitId"
                     v-model="productForm.unitId"
                     placeholder="请选择"
                     placeholder="请选择"
@@ -252,7 +264,7 @@
             <!-- 税率编码 、税率 和 币种 -->
             <!-- 税率编码 、税率 和 币种 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="税率编码:">
+                <el-form-item label="税率编码:" required>
                   <el-input
                   <el-input
                     v-model="taxCodeNo"
                     v-model="taxCodeNo"
                     placeholder="点击选择税率编码"
                     placeholder="点击选择税率编码"
@@ -269,9 +281,7 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="税率:" required>
                 <el-form-item label="税率:" required>
-                  <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
-                    <el-option v-for="option in taxRateOptions" :key="option.id" :label="`${option.taxrateNo},${option.taxrateName}`" :value="option.taxrate" />
-                  </el-select>
+                  <el-input :model-value="formatTaxRateDisplay(productForm.taxRate)" placeholder="由税率编码带出" readonly disabled class="w-full" />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -308,19 +318,32 @@
 
 
             <!-- 促销标题 -->
             <!-- 促销标题 -->
             <el-form-item label="促销标题:">
             <el-form-item label="促销标题:">
-              <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
             </el-form-item>
 
 
-            <!-- 商品简介 -->
-            <el-form-item label="商品简介:">
-              <el-input v-model="productForm.productDescription" type="textarea" :rows="3" placeholder="请输入商品简介" maxlength="500" show-word-limit />
+                        <!-- 商品说明 -->
+            <el-form-item label="商品说明:">
+              <el-input
+                v-model="productForm.productExplain"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品说明"
+                maxlength="500"
+                show-word-limit
+              />
             </el-form-item>
             </el-form-item>
 
 
             <!-- 重量 和 体积 -->
             <!-- 重量 和 体积 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品重量:">
                 <el-form-item label="商品重量:">
-                  <el-input v-model="productForm.productWeight" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productWeight"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleWeightInput"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                         <el-option label="kg" value="kg" />
                         <el-option label="kg" value="kg" />
@@ -333,7 +356,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品体积:">
                 <el-form-item label="商品体积:">
-                  <el-input v-model="productForm.productVolume" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productVolume"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleVolumeInput"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                         <el-option label="m³" value="m3" />
                         <el-option label="m³" value="m3" />
@@ -347,12 +376,14 @@
             </el-row>
             </el-row>
 
 
             <!-- 参考链接 -->
             <!-- 参考链接 -->
-            <el-form-item label="参考链接">
+            <el-form-item label="参考链接" prop="referenceLink" required>
               <el-input
               <el-input
+                ref="referenceLinkRef"
                 v-model="productForm.referenceLink"
                 v-model="productForm.referenceLink"
                 type="textarea"
                 type="textarea"
                 :rows="3"
                 :rows="3"
                 placeholder="请输入参考链接"
                 placeholder="请输入参考链接"
+                @input="handleReferenceLinkInput"
               />
               />
             </el-form-item>
             </el-form-item>
 
 
@@ -389,17 +420,25 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="市场价:" prop="marketPrice" required>
                 <el-form-item label="市场价:" prop="marketPrice" required>
-                  <el-input v-model="productForm.marketPrice" type="number" placeholder="请输入市场价" :min="0" @blur="formatPrice('marketPrice')" />
+                  <el-input
+                    ref="marketPriceRef"
+                    v-model="productForm.marketPrice"
+                    type="number"
+                    placeholder="请输入市场价"
+                    :min="0"
+                    @blur="handlePriceBlur('marketPrice')"
+                  />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="官网价:" prop="memberPrice" required>
                 <el-form-item label="官网价:" prop="memberPrice" required>
                   <el-input
                   <el-input
+                    ref="memberPriceRef"
                     v-model="productForm.memberPrice"
                     v-model="productForm.memberPrice"
                     type="number"
                     type="number"
                     placeholder="请输入平台售价"
                     placeholder="请输入平台售价"
                     :min="0"
                     :min="0"
-                    @blur="formatPrice('memberPrice')"
+                    @blur="handlePriceBlur('memberPrice')"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
@@ -434,26 +473,33 @@
                     type="number"
                     type="number"
                     placeholder="请输入供应价"
                     placeholder="请输入供应价"
                     :min="0"
                     :min="0"
-                    @blur="formatPrice('supplyPrice')"
+                    @blur="handlePriceBlur('supplyPrice')"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
-                <el-form-item label="供应有效时间:">
-                  <el-date-picker
-                    v-model="productForm.supplyValidityPeriod"
-                    type="date"
-                    placeholder="请选择供应有效时间"
-                    value-format="YYYY-MM-DD"
-                    class="w-full"
+                <el-form-item label="供应时间(天):">
+                  <el-input
+                    v-model="productForm.supplyDays"
+                    type="number"
+                    placeholder="请输入供应天数"
+                    :min="1"
+                    @blur="calcSupplyExpireTime"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
-                <el-form-item label="是否包邮:">
+                <el-form-item label="到期时间:">
+                  <el-input v-model="productForm.supplyValidityPeriod" disabled placeholder="自动计算" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="一件代发:">
                   <el-radio-group v-model="productForm.supplyPostStatus">
                   <el-radio-group v-model="productForm.supplyPostStatus">
-                    <el-radio :value="0">不包邮</el-radio>
-                    <el-radio :value="1">包邮</el-radio>
+                    <el-radio :value="0">不支持</el-radio>
+                    <el-radio :value="1">支持</el-radio>
                   </el-radio-group>
                   </el-radio-group>
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
@@ -559,14 +605,14 @@
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
             <!-- 商品主图 -->
             <!-- 商品主图 -->
             <el-form-item label="商品主图:" required>
             <el-form-item label="商品主图:" required>
-              <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
-              <div class="form-item-tip">从图片库选择,建议尺寸300*300px</div>
+              <image-upload v-model="productForm.productImage" :limit="1" />
+              <div class="form-item-tip">建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
             <!-- 商品轮播图 -->
             <!-- 商品轮播图 -->
             <el-form-item label="商品轮播图:" required>
             <el-form-item label="商品轮播图:" required>
-              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
-              <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
+              <image-upload v-model="carouselImages" :limit="20" />
+              <div class="form-item-tip">支持多张上传,建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
             <!-- 商品详情 -->
             <!-- 商品详情 -->
@@ -714,9 +760,9 @@ import { useRoute, useRouter } from 'vue-router';
 import { ElMessage } from 'element-plus';
 import { ElMessage } from 'element-plus';
 import { Warning, ArrowRight, Check, Plus, CircleCheck, Search } from '@element-plus/icons-vue';
 import { Warning, ArrowRight, Check, Plus, CircleCheck, Search } from '@element-plus/icons-vue';
 import Editor from '@/components/Editor/index.vue';
 import Editor from '@/components/Editor/index.vue';
-import UploadImage from '@/components/upload-image/index.vue';
 import TaxCodeSelect from '@/components/TaxCodeSelect/index.vue';
 import TaxCodeSelect from '@/components/TaxCodeSelect/index.vue';
 import { categoryTreeVO, CategoryVO } from '@/api/product/category/types';
 import { categoryTreeVO, CategoryVO } from '@/api/product/category/types';
+import { getCategory } from '@/api/product/category';
 import { BrandVO } from '@/api/product/brand/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { BaseForm } from '@/api/product/base/types';
 import { BaseForm } from '@/api/product/base/types';
 import { ClassificationDiyForm } from '@/api/product/classificationDiy/types';
 import { ClassificationDiyForm } from '@/api/product/classificationDiy/types';
@@ -730,8 +776,7 @@ import {
   categoryAttributeList,
   categoryAttributeList,
   getAfterSaleList,
   getAfterSaleList,
   getServiceList,
   getServiceList,
-  getUnitList,
-  getTaxRateList
+  getUnitList
 } from '@/api/product/base';
 } from '@/api/product/base';
 import {
 import {
   addBaseAudit,
   addBaseAudit,
@@ -754,6 +799,11 @@ const loading = ref(false);
 const submitLoading = ref(false);
 const submitLoading = ref(false);
 const productFormRef = ref();
 const productFormRef = ref();
 
 
+// 关键输入框 refs,用于校验失败时聚焦
+const referenceLinkRef = ref();
+const marketPriceRef = ref();
+const memberPriceRef = ref();
+
 // 服务保障和安装服务的多选框
 // 服务保障和安装服务的多选框
 const serviceGuarantees = ref<(string | number)[]>([]);
 const serviceGuarantees = ref<(string | number)[]>([]);
 const installationServices = ref<string[]>([]);
 const installationServices = ref<string[]>([]);
@@ -761,24 +811,37 @@ const installationServices = ref<string[]>([]);
 // 商品详情选项卡
 // 商品详情选项卡
 const activeDetailTab = ref('pc');
 const activeDetailTab = ref('pc');
 
 
-// 轮播图URL数组(UI管理用)
-const carouselImages = ref<string[]>([]);
-
-// 税率选项
-const taxRateOptions = ref<any[]>([]);
+// 轮播图(逗号分隔的 ossId 字符串,由 ImageUpload 管理)
+const carouselImages = ref<string>('');
 
 
 // 税率编码选择组件
 // 税率编码选择组件
 const taxCodeSelectRef = ref();
 const taxCodeSelectRef = ref();
 // 已选的税率编码(显示用)
 // 已选的税率编码(显示用)
 const taxCodeNo = ref('');
 const taxCodeNo = ref('');
 
 
+// 格式化税率显示(小数转百分比)
+const formatTaxRateDisplay = (val: any): string => {
+  if (val === null || val === undefined || val === '') return '';
+  const num = Number(val);
+  if (isNaN(num)) return String(val);
+  return `${Math.round(num * 100)}%`;
+};
+
 // 处理税率编码选择
 // 处理税率编码选择
 const handleTaxCodeSelect = async (row: any) => {
 const handleTaxCodeSelect = async (row: any) => {
   (productForm as any).taxationId = row.id;
   (productForm as any).taxationId = row.id;
+  // 选择税率编码时自动带出税率
+  if (row.taxrate !== undefined && row.taxrate !== null) {
+    productForm.taxRate = Number(row.taxrate);
+  }
   try {
   try {
     const taxRes = await getTaxCode(row.id);
     const taxRes = await getTaxCode(row.id);
     if (taxRes.data) {
     if (taxRes.data) {
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
+      // 使用详情接口返回的税率值(更准确)
+      if ((taxRes.data as any).taxrate !== undefined && (taxRes.data as any).taxrate !== null) {
+        productForm.taxRate = Number((taxRes.data as any).taxrate);
+      }
     } else {
     } else {
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
     }
     }
@@ -966,10 +1029,11 @@ const productForm = reactive<BaseForm>({
   purchasingPrice: undefined,
   purchasingPrice: undefined,
   maxPurchasePrice: undefined,
   maxPurchasePrice: undefined,
   supplyPrice: undefined,
   supplyPrice: undefined,
+  supplyDays: undefined,
   supplyValidityPeriod: undefined,
   supplyValidityPeriod: undefined,
   supplyPostStatus: undefined,
   supplyPostStatus: undefined,
-  productNature: '1',
-  purchasingPersonnel: '1',
+  productNature: '',
+  purchasingPersonnel: '',
   pcDetail: undefined,
   pcDetail: undefined,
   mobileDetail: undefined,
   mobileDetail: undefined,
   taxRate: undefined,
   taxRate: undefined,
@@ -984,9 +1048,23 @@ const productRules = {
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
-  memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
+  memberPrice: [{ required: true, message: '官网价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
-  // purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  maxPurchasePrice: [{ required: true, message: '最高采购价不能为空', trigger: 'blur' }],
+  referenceLink: [
+    { required: true, message: '参考链接不能为空', trigger: 'blur' },
+    {
+      validator: (_rule: any, value: any, callback: any) => {
+        if (value && /\u3000/.test(String(value))) {
+          callback(new Error('参考链接不能包含中文空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
@@ -1091,6 +1169,39 @@ const handleLevel3Search = async (keyword: string) => {
   }
   }
 };
 };
 
 
+// 从三级分类联动填充采购信息
+const fillPurchaseFromCategory = async (categoryId: string | number, category?: CategoryVO) => {
+  try {
+    let detail: CategoryVO | undefined = category;
+    if (!detail) {
+      const res = await getCategory(categoryId);
+      detail = res.data;
+    }
+    if (!detail) return;
+    (productForm as any).purchaseNo = (detail as any).purchaseNo || undefined;
+    (productForm as any).purchaseName = (detail as any).purchaseName || undefined;
+    (productForm as any).purchaseManagerNo = (detail as any).purchaseManagerNo || undefined;
+    (productForm as any).purchaseManagerName = (detail as any).purchaseManagerName || undefined;
+
+    // 联动产品经理下拉:通过 purchaseManagerNo 匹配 staffCode
+    if ((detail as any).purchaseManagerNo) {
+      const matchedManager = staffOptions.value.find((s) => s.staffCode === (detail as any).purchaseManagerNo);
+      if (matchedManager) {
+        productForm.productNature = String(matchedManager.staffId);
+      }
+    }
+    // 联动采购人员下拉:通过 purchaseNo 匹配 staffCode
+    if ((detail as any).purchaseNo) {
+      const matchedPurchase = staffOptions.value.find((s) => s.staffCode === (detail as any).purchaseNo);
+      if (matchedPurchase) {
+        productForm.purchasingPersonnel = String(matchedPurchase.staffId);
+      }
+    }
+  } catch (e) {
+    console.error('获取三级分类采购信息失败:', e);
+  }
+};
+
 // 选择三级分类搜索结果后,自动在树中定位
 // 选择三级分类搜索结果后,自动在树中定位
 const handleLevel3SearchSelect = async (categoryId: string | number) => {
 const handleLevel3SearchSelect = async (categoryId: string | number) => {
   if (!categoryId) return;
   if (!categoryId) return;
@@ -1123,10 +1234,12 @@ const handleLevel3SearchSelect = async (categoryId: string | number) => {
   if (level3Node) {
   if (level3Node) {
     categoryForm.bottomCategoryId = level3Node.id;
     categoryForm.bottomCategoryId = level3Node.id;
     selectedLevel3Name.value = level3Node.label;
     selectedLevel3Name.value = level3Node.label;
+    await fillPurchaseFromCategory(level3Node.id, selectedCategory);
     await loadCategoryAttributes(level3Node.id);
     await loadCategoryAttributes(level3Node.id);
   } else {
   } else {
     categoryForm.bottomCategoryId = selectedCategory.id;
     categoryForm.bottomCategoryId = selectedCategory.id;
     selectedLevel3Name.value = selectedCategory.categoryName;
     selectedLevel3Name.value = selectedCategory.categoryName;
+    await fillPurchaseFromCategory(selectedCategory.id, selectedCategory);
     await loadCategoryAttributes(selectedCategory.id);
     await loadCategoryAttributes(selectedCategory.id);
   }
   }
 
 
@@ -1176,6 +1289,9 @@ const selectLevel3 = async (item: categoryTreeVO) => {
   categoryForm.bottomCategoryId = item.id;
   categoryForm.bottomCategoryId = item.id;
   selectedLevel3Name.value = item.label;
   selectedLevel3Name.value = item.label;
 
 
+  // 联动填充产品经理与采购人员(从三级分类详情获取)
+  await fillPurchaseFromCategory(item.id);
+
   // 加载该分类下的属性列表
   // 加载该分类下的属性列表
   await loadCategoryAttributes(item.id);
   await loadCategoryAttributes(item.id);
 };
 };
@@ -1257,7 +1373,7 @@ const handleSubmit = async () => {
       submitLoading.value = false;
       submitLoading.value = false;
       return;
       return;
     }
     }
-    if (!carouselImages.value || carouselImages.value.length === 0) {
+    if (!carouselImages.value) {
       ElMessage.warning('请上传商品轮播图');
       ElMessage.warning('请上传商品轮播图');
       submitLoading.value = false;
       submitLoading.value = false;
       return;
       return;
@@ -1302,8 +1418,8 @@ const handleSubmit = async () => {
       ...productForm,
       ...productForm,
       // 将服务保障ID数组转换为逗号分隔字符串
       // 将服务保障ID数组转换为逗号分隔字符串
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
-      // 轮播图URL逗号分隔
-      imageUrl: carouselImages.value.join(','),
+      // 轮播图(ImageUpload 已是逗号分隔字符串)
+      imageUrl: carouselImages.value,
       // 将商品属性值转换为JSON字符串
       // 将商品属性值转换为JSON字符串
       attributesList: JSON.stringify(productAttributesValues.value),
       attributesList: JSON.stringify(productAttributesValues.value),
       isCustomize: customForm.isCustomize ? 1 : 0,
       isCustomize: customForm.isCustomize ? 1 : 0,
@@ -1355,6 +1471,41 @@ const handleUpcInput = () => {
   }
   }
 };
 };
 
 
+// 商品重量只允许数字和小数点(过滤中文及其他非法字符)
+const handleWeightInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    let v = String(val).replace(/[^\d.]/g, '');
+    // 只保留第一个小数点
+    const firstDot = v.indexOf('.');
+    if (firstDot !== -1) {
+      v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm.productWeight = v;
+  }
+};
+
+// 商品体积只允许数字和小数点
+const handleVolumeInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    let v = String(val).replace(/[^\d.]/g, '');
+    const firstDot = v.indexOf('.');
+    if (firstDot !== -1) {
+      v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm.productVolume = v;
+  }
+};
+
+// 参考链接过滤中文空格(全角空格 U+3000)
+const handleReferenceLinkInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    const filtered = String(val).replace(/\u3000/g, '');
+    if (filtered !== val) {
+      productForm.referenceLink = filtered;
+    }
+  }
+};
+
 // 销量人气只允许输入整数
 // 销量人气只允许输入整数
 const handleSalesVolumeInput = (val: string) => {
 const handleSalesVolumeInput = (val: string) => {
   if (val !== undefined && val !== null && val !== '') {
   if (val !== undefined && val !== null && val !== '') {
@@ -1388,6 +1539,44 @@ const formatPrice = (field: string) => {
   }
   }
 };
 };
 
 
+// 价格失焦校验:供应价 < 官网价 < 市场价
+const handlePriceBlur = (field: string) => {
+  formatPrice(field);
+  const supplyPrice = parseFloat(String(productForm.supplyPrice));
+  const memberPrice = parseFloat(String(productForm.memberPrice));
+  const marketPrice = parseFloat(String(productForm.marketPrice));
+
+  if (field === 'supplyPrice' && !isNaN(supplyPrice) && !isNaN(memberPrice) && supplyPrice >= memberPrice) {
+    ElMessage.warning('供应价必须小于官网价');
+  }
+  if (field === 'memberPrice') {
+    if (!isNaN(memberPrice) && !isNaN(supplyPrice) && memberPrice <= supplyPrice) {
+      ElMessage.warning('官网价必须大于供应价');
+    }
+    if (!isNaN(memberPrice) && !isNaN(marketPrice) && memberPrice >= marketPrice) {
+      ElMessage.warning('官网价必须小于市场价');
+    }
+  }
+  if (field === 'marketPrice' && !isNaN(marketPrice) && !isNaN(memberPrice) && marketPrice <= memberPrice) {
+    ElMessage.warning('市场价必须大于官网价');
+  }
+};
+
+// 根据供应天数自动计算到期时间
+const calcSupplyExpireTime = () => {
+  const days = parseInt(String(productForm.supplyDays));
+  if (!isNaN(days) && days > 0) {
+    const now = new Date();
+    now.setDate(now.getDate() + days);
+    const y = now.getFullYear();
+    const m = String(now.getMonth() + 1).padStart(2, '0');
+    const d = String(now.getDate()).padStart(2, '0');
+    productForm.supplyValidityPeriod = `${y}-${m}-${d}`;
+  } else {
+    productForm.supplyValidityPeriod = undefined;
+  }
+};
+
 // 格式化表格行中的价格为两位小数(不允许负数)
 // 格式化表格行中的价格为两位小数(不允许负数)
 const formatRowPrice = (row: any, field: string) => {
 const formatRowPrice = (row: any, field: string) => {
   const val = row[field];
   const val = row[field];
@@ -1524,16 +1713,6 @@ const getStaffOptions = async () => {
   }
   }
 };
 };
 
 
-// 获取税率列表
-const getTaxRateOptions = async () => {
-  try {
-    const res = await getTaxRateList();
-    taxRateOptions.value = res.rows || [];
-  } catch (error) {
-    console.error('获取税率列表失败:', error);
-  }
-};
-
 // 加载分类属性列表
 // 加载分类属性列表
 const loadCategoryAttributes = async (categoryId: string | number) => {
 const loadCategoryAttributes = async (categoryId: string | number) => {
   try {
   try {
@@ -1620,16 +1799,9 @@ const loadProductDetail = async () => {
         }
         }
       }
       }
 
 
-      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题
+      // 回显税率(直接使用接口返回值,由税率编码带出,无需下拉匹配
       if (res.data.taxRate !== undefined && res.data.taxRate !== null) {
       if (res.data.taxRate !== undefined && res.data.taxRate !== null) {
-        const apiTaxRate = Number(res.data.taxRate);
-        // 使用精度容差比较浮点数
-        const matchedOption = taxRateOptions.value.find((opt) => Math.abs(Number(opt.taxrate) - apiTaxRate) < 0.0001);
-        if (matchedOption) {
-          productForm.taxRate = matchedOption.taxrate;
-        } else {
-          productForm.taxRate = apiTaxRate;
-        }
+        productForm.taxRate = Number(res.data.taxRate);
       }
       }
 
 
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
@@ -1656,15 +1828,11 @@ const loadProductDetail = async () => {
 
 
       // 回显售后服务 - 确保类型与下拉选项的id一致(数字类型)
       // 回显售后服务 - 确保类型与下拉选项的id一致(数字类型)
       if (res.data.afterSalesService !== undefined && res.data.afterSalesService !== null) {
       if (res.data.afterSalesService !== undefined && res.data.afterSalesService !== null) {
-        productForm.afterSalesService = String(res.data.afterSalesService);
+        productForm.afterSalesService = Number(res.data.afterSalesService);
       }
       }
 
 
       // 回显轮播图
       // 回显轮播图
-      if (res.data.imageUrl) {
-        carouselImages.value = res.data.imageUrl.split(',').filter((url: string) => url.trim());
-      } else {
-        carouselImages.value = [];
-      }
+      carouselImages.value = res.data.imageUrl || '';
 
 
       // 回显分类选择
       // 回显分类选择
       categoryForm.topCategoryId = res.data.topCategoryId;
       categoryForm.topCategoryId = res.data.topCategoryId;
@@ -1809,7 +1977,6 @@ onMounted(async () => {
   await getUnitOptions();
   await getUnitOptions();
   await getAfterSalesOptions();
   await getAfterSalesOptions();
   await getServiceGuaranteeOptions();
   await getServiceGuaranteeOptions();
-  await getTaxRateOptions();
   // 先加载商品详情(如果是编辑模式)
   // 先加载商品详情(如果是编辑模式)
   await loadProductDetail();
   await loadProductDetail();
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个

+ 274 - 82
src/views/product/base/add1.vue

@@ -188,6 +188,19 @@
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
             </el-form-item>
             </el-form-item>
 
 
+            
+            <!-- 商品描述 -->
+            <el-form-item label="商品描述:">
+              <el-input
+                v-model="productForm.productDescription"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品描述"
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+
             <!-- 规格型号 和 UPC(69)条码 -->
             <!-- 规格型号 和 UPC(69)条码 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
@@ -235,13 +248,14 @@
               </el-col>
               </el-col>
 
 
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="单位:">
+                <el-form-item label="单位:" required>
                   <el-select
                   <el-select
                     v-model="productForm.unitId"
                     v-model="productForm.unitId"
                     placeholder="请选择"
                     placeholder="请选择"
                     clearable
                     clearable
                     class="w-full"
                     class="w-full"
                     :disabled="productForm.productReviewStatus === 1"
                     :disabled="productForm.productReviewStatus === 1"
+
                   >
                   >
                     <el-option v-for="option in unitOptions" :key="option.id" :label="`${option.unitNo},${option.unitName}`" :value="option.id" />
                     <el-option v-for="option in unitOptions" :key="option.id" :label="`${option.unitNo},${option.unitName}`" :value="option.id" />
                   </el-select>
                   </el-select>
@@ -252,7 +266,7 @@
             <!-- 税率编码 、税率 和 币种 -->
             <!-- 税率编码 、税率 和 币种 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="税率编码:">
+                <el-form-item label="税率编码:" required>
                   <el-input
                   <el-input
                     v-model="taxCodeNo"
                     v-model="taxCodeNo"
                     placeholder="点击选择税率编码"
                     placeholder="点击选择税率编码"
@@ -269,9 +283,7 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="税率:" required>
                 <el-form-item label="税率:" required>
-                  <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
-                    <el-option v-for="option in taxRateOptions" :key="option.id" :label="`${option.taxrateNo},${option.taxrateName}`" :value="option.taxrate" />
-                  </el-select>
+                  <el-input :model-value="formatTaxRateDisplay(productForm.taxRate)" placeholder="由税率编码带出" readonly disabled class="w-full" />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -308,16 +320,17 @@
 
 
             <!-- 促销标题 -->
             <!-- 促销标题 -->
             <el-form-item label="促销标题:">
             <el-form-item label="促销标题:">
-              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+              <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
             </el-form-item>
 
 
-            <!-- 商品简介 -->
-            <el-form-item label="商品简介:">
+
+                        <!-- 商品说明 -->
+            <el-form-item label="商品说明:">
               <el-input
               <el-input
-                v-model="productForm.productDescription"
+                v-model="productForm.productExplain"
                 type="textarea"
                 type="textarea"
                 :rows="3"
                 :rows="3"
-                placeholder="请输入商品简介"
+                placeholder="请输入商品说明"
                 maxlength="500"
                 maxlength="500"
                 show-word-limit
                 show-word-limit
               />
               />
@@ -327,7 +340,13 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品重量:">
                 <el-form-item label="商品重量:">
-                  <el-input v-model="productForm.productWeight" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productWeight"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleWeightInput"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                         <el-option label="kg" value="kg" />
                         <el-option label="kg" value="kg" />
@@ -340,7 +359,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品体积:">
                 <el-form-item label="商品体积:">
-                  <el-input v-model="productForm.productVolume" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productVolume"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleVolumeInput"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                         <el-option label="m³" value="m3" />
                         <el-option label="m³" value="m3" />
@@ -354,8 +379,15 @@
             </el-row>
             </el-row>
 
 
             <!-- 参考链接 -->
             <!-- 参考链接 -->
-            <el-form-item label="参考链接">
-              <el-input v-model="productForm.referenceLink" type="textarea" :rows="3" placeholder="请输入参考链接" />
+            <el-form-item label="参考链接" prop="referenceLink" required>
+              <el-input
+                ref="referenceLinkRef"
+                v-model="productForm.referenceLink"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入参考链接"
+                @input="handleReferenceLinkInput"
+              />
             </el-form-item>
             </el-form-item>
 
 
             <!-- 主供应商 -->
             <!-- 主供应商 -->
@@ -403,12 +435,20 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="市场价:" prop="marketPrice" required>
                 <el-form-item label="市场价:" prop="marketPrice" required>
-                  <el-input v-model="productForm.marketPrice" type="number" placeholder="请输入市场价" :min="0" @blur="formatPrice('marketPrice')" />
+                  <el-input
+                    ref="marketPriceRef"
+                    v-model="productForm.marketPrice"
+                    type="number"
+                    placeholder="请输入市场价"
+                    :min="0"
+                    @blur="formatPrice('marketPrice')"
+                  />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="官网价:" prop="memberPrice" required>
                 <el-form-item label="官网价:" prop="memberPrice" required>
                   <el-input
                   <el-input
+                    ref="memberPriceRef"
                     v-model="productForm.memberPrice"
                     v-model="productForm.memberPrice"
                     type="number"
                     type="number"
                     placeholder="请输入平台售价"
                     placeholder="请输入平台售价"
@@ -420,6 +460,7 @@
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="最低售价:" prop="minSellingPrice" required>
                 <el-form-item label="最低售价:" prop="minSellingPrice" required>
                   <el-input
                   <el-input
+                    ref="minSellingPriceRef"
                     v-model="productForm.minSellingPrice"
                     v-model="productForm.minSellingPrice"
                     type="number"
                     type="number"
                     placeholder="请输入最低售价"
                     placeholder="请输入最低售价"
@@ -437,7 +478,7 @@
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="备注:">
                 <el-form-item label="备注:">
-                  <span class="currency-text">市场价>官网价>最低售价</span>
+                  <span class="currency-text">市场价&gt;官网价&ge;最低售价&ge;最高采购价&ge;采购价</span>
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -455,6 +496,7 @@
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="采购价:" prop="purchasingPrice" required>
                 <el-form-item label="采购价:" prop="purchasingPrice" required>
                   <el-input
                   <el-input
+                    ref="purchasingPriceRef"
                     v-model="productForm.purchasingPrice"
                     v-model="productForm.purchasingPrice"
                     type="number"
                     type="number"
                     placeholder="请输入采购价"
                     placeholder="请输入采购价"
@@ -464,8 +506,9 @@
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="最高采购价:">
+                <el-form-item label="最高采购价:" prop="maxPurchasePrice" required>
                   <el-input
                   <el-input
+                    ref="maxPurchasePriceRef"
                     v-model="productForm.maxPurchasePrice"
                     v-model="productForm.maxPurchasePrice"
                     type="number"
                     type="number"
                     placeholder="请输入最高采购价"
                     placeholder="请输入最高采购价"
@@ -611,14 +654,14 @@
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
             <!-- 商品主图 -->
             <!-- 商品主图 -->
             <el-form-item label="商品主图:" required>
             <el-form-item label="商品主图:" required>
-              <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
-              <div class="form-item-tip">从图片库选择,建议尺寸300*300px</div>
+              <image-upload v-model="productForm.productImage" :limit="1" />
+              <div class="form-item-tip">建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
             <!-- 商品轮播图 -->
             <!-- 商品轮播图 -->
             <el-form-item label="商品轮播图:" required>
             <el-form-item label="商品轮播图:" required>
-              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
-              <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
+              <image-upload v-model="carouselImages" :limit="20" />
+              <div class="form-item-tip">支持多张上传,建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
             <!-- 商品详情 -->
             <!-- 商品详情 -->
@@ -627,9 +670,6 @@
                 <el-tab-pane label="电脑端详情" name="pc">
                 <el-tab-pane label="电脑端详情" name="pc">
                   <Editor v-model="productForm.pcDetail" :height="400" />
                   <Editor v-model="productForm.pcDetail" :height="400" />
                 </el-tab-pane>
                 </el-tab-pane>
-                <el-tab-pane label="移动端详情" name="mobile">
-                  <Editor v-model="productForm.mobileDetail" :height="400" />
-                </el-tab-pane>
               </el-tabs>
               </el-tabs>
             </el-form-item>
             </el-form-item>
           </el-form>
           </el-form>
@@ -766,9 +806,9 @@ import { useRoute, useRouter } from 'vue-router';
 import { ElMessage } from 'element-plus';
 import { ElMessage } from 'element-plus';
 import { Warning, ArrowRight, Check, Plus, CircleCheck, Search } from '@element-plus/icons-vue';
 import { Warning, ArrowRight, Check, Plus, CircleCheck, Search } from '@element-plus/icons-vue';
 import Editor from '@/components/Editor/index.vue';
 import Editor from '@/components/Editor/index.vue';
-import UploadImage from '@/components/upload-image/index.vue';
 import TaxCodeSelect from '@/components/TaxCodeSelect/index.vue';
 import TaxCodeSelect from '@/components/TaxCodeSelect/index.vue';
 import { categoryTreeVO, CategoryVO } from '@/api/product/category/types';
 import { categoryTreeVO, CategoryVO } from '@/api/product/category/types';
+import { getCategory } from '@/api/product/category';
 import { BrandVO } from '@/api/product/brand/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { BaseForm } from '@/api/product/base/types';
 import { BaseForm } from '@/api/product/base/types';
 import { ClassificationDiyForm } from '@/api/product/classificationDiy/types';
 import { ClassificationDiyForm } from '@/api/product/classificationDiy/types';
@@ -782,8 +822,7 @@ import {
   categoryAttributeList,
   categoryAttributeList,
   getAfterSaleList,
   getAfterSaleList,
   getServiceList,
   getServiceList,
-  getUnitList,
-  getTaxRateList
+  getUnitList
 } from '@/api/product/base';
 } from '@/api/product/base';
 import { addBaseAudit, updateBaseAudit, getBaseAudit } from '@/api/product/baseAudit';
 import { addBaseAudit, updateBaseAudit, getBaseAudit } from '@/api/product/baseAudit';
 import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
 import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
@@ -802,6 +841,14 @@ const loading = ref(false);
 const submitLoading = ref(false);
 const submitLoading = ref(false);
 const productFormRef = ref();
 const productFormRef = ref();
 
 
+// 关键输入框 refs,用于校验失败时聚焦
+const referenceLinkRef = ref();
+const marketPriceRef = ref();
+const memberPriceRef = ref();
+const minSellingPriceRef = ref();
+const maxPurchasePriceRef = ref();
+const purchasingPriceRef = ref();
+
 // 服务保障和安装服务的多选框
 // 服务保障和安装服务的多选框
 const serviceGuarantees = ref<(string | number)[]>([]);
 const serviceGuarantees = ref<(string | number)[]>([]);
 const installationServices = ref<string[]>([]);
 const installationServices = ref<string[]>([]);
@@ -809,24 +856,37 @@ const installationServices = ref<string[]>([]);
 // 商品详情选项卡
 // 商品详情选项卡
 const activeDetailTab = ref('pc');
 const activeDetailTab = ref('pc');
 
 
-// 轮播图URL数组(UI管理用)
-const carouselImages = ref<string[]>([]);
-
-// 税率选项
-const taxRateOptions = ref<any[]>([]);
+// 轮播图(逗号分隔的 ossId 字符串,由 ImageUpload 管理)
+const carouselImages = ref<string>('');
 
 
 // 税率编码选择组件
 // 税率编码选择组件
 const taxCodeSelectRef = ref();
 const taxCodeSelectRef = ref();
 // 已选的税率编码(显示用)
 // 已选的税率编码(显示用)
 const taxCodeNo = ref('');
 const taxCodeNo = ref('');
 
 
+// 格式化税率显示(小数转百分比)
+const formatTaxRateDisplay = (val: any): string => {
+  if (val === null || val === undefined || val === '') return '';
+  const num = Number(val);
+  if (isNaN(num)) return String(val);
+  return `${Math.round(num * 100)}%`;
+};
+
 // 处理税率编码选择
 // 处理税率编码选择
 const handleTaxCodeSelect = async (row: any) => {
 const handleTaxCodeSelect = async (row: any) => {
   (productForm as any).taxationId = row.id;
   (productForm as any).taxationId = row.id;
+  // 选择税率编码时自动带出税率
+  if (row.taxrate !== undefined && row.taxrate !== null) {
+    productForm.taxRate = Number(row.taxrate);
+  }
   try {
   try {
     const taxRes = await getTaxCode(row.id);
     const taxRes = await getTaxCode(row.id);
     if (taxRes.data) {
     if (taxRes.data) {
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
+      // 使用详情接口返回的税率值(更准确)
+      if (taxRes.data.taxrate !== undefined && taxRes.data.taxrate !== null) {
+        productForm.taxRate = Number(taxRes.data.taxrate);
+      }
     } else {
     } else {
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
     }
     }
@@ -1012,8 +1072,12 @@ const productForm = reactive<BaseForm>({
   minSellingPrice: undefined,
   minSellingPrice: undefined,
   purchasingPrice: undefined,
   purchasingPrice: undefined,
   maxPurchasePrice: undefined,
   maxPurchasePrice: undefined,
-  productNature: '1',
-  purchasingPersonnel: '1',
+  productNature: '',
+  purchasingPersonnel: '',
+  purchaseNo: undefined,
+  purchaseName: undefined,
+  purchaseManagerNo: undefined,
+  purchaseManagerName: undefined,
   pcDetail: undefined,
   pcDetail: undefined,
   mobileDetail: undefined,
   mobileDetail: undefined,
   taxRate: undefined,
   taxRate: undefined,
@@ -1029,9 +1093,23 @@ const productRules = {
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   supplierNo: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
   supplierNo: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
-  memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
+  memberPrice: [{ required: true, message: '官网价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  maxPurchasePrice: [{ required: true, message: '最高采购价不能为空', trigger: 'blur' }],
+  referenceLink: [
+    { required: true, message: '参考链接不能为空', trigger: 'blur' },
+    {
+      validator: (_rule: any, value: any, callback: any) => {
+        if (value && /\u3000/.test(String(value))) {
+          callback(new Error('参考链接不能包含中文空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
@@ -1168,10 +1246,12 @@ const handleLevel3SearchSelect = async (categoryId: string | number) => {
   if (level3Node) {
   if (level3Node) {
     categoryForm.bottomCategoryId = level3Node.id;
     categoryForm.bottomCategoryId = level3Node.id;
     selectedLevel3Name.value = level3Node.label;
     selectedLevel3Name.value = level3Node.label;
+    await fillPurchaseFromCategory(level3Node.id, selectedCategory);
     await loadCategoryAttributes(level3Node.id);
     await loadCategoryAttributes(level3Node.id);
   } else {
   } else {
     categoryForm.bottomCategoryId = selectedCategory.id;
     categoryForm.bottomCategoryId = selectedCategory.id;
     selectedLevel3Name.value = selectedCategory.categoryName;
     selectedLevel3Name.value = selectedCategory.categoryName;
+    await fillPurchaseFromCategory(selectedCategory.id, selectedCategory);
     await loadCategoryAttributes(selectedCategory.id);
     await loadCategoryAttributes(selectedCategory.id);
   }
   }
 
 
@@ -1221,10 +1301,46 @@ const selectLevel3 = async (item: categoryTreeVO) => {
   categoryForm.bottomCategoryId = item.id;
   categoryForm.bottomCategoryId = item.id;
   selectedLevel3Name.value = item.label;
   selectedLevel3Name.value = item.label;
 
 
+  // 联动填充产品经理与采购人员(从三级分类详情获取)
+  await fillPurchaseFromCategory(item.id);
+
   // 加载该分类下的属性列表
   // 加载该分类下的属性列表
   await loadCategoryAttributes(item.id);
   await loadCategoryAttributes(item.id);
 };
 };
 
 
+// 从三级分类联动填充采购信息
+const fillPurchaseFromCategory = async (categoryId: string | number, category?: CategoryVO) => {
+  try {
+    let detail: CategoryVO | undefined = category;
+    if (!detail) {
+      const res = await getCategory(categoryId);
+      detail = res.data;
+    }
+    if (!detail) return;
+    productForm.purchaseNo = detail.purchaseNo || undefined;
+    productForm.purchaseName = detail.purchaseName || undefined;
+    productForm.purchaseManagerNo = detail.purchaseManagerNo || undefined;
+    productForm.purchaseManagerName = detail.purchaseManagerName || undefined;
+
+    // 联动产品经理下拉:通过 purchaseManagerNo 匹配 staffCode
+    if (detail.purchaseManagerNo) {
+      const matchedManager = staffOptions.value.find((s) => s.staffCode === detail!.purchaseManagerNo);
+      if (matchedManager) {
+        productForm.productNature = String(matchedManager.staffId);
+      }
+    }
+    // 联动采购人员下拉:通过 purchaseNo 匹配 staffCode
+    if (detail.purchaseNo) {
+      const matchedPurchase = staffOptions.value.find((s) => s.staffCode === detail!.purchaseNo);
+      if (matchedPurchase) {
+        productForm.purchasingPersonnel = String(matchedPurchase.staffId);
+      }
+    }
+  } catch (e) {
+    console.error('获取三级分类采购信息失败:', e);
+  }
+};
+
 // 获取分类路径
 // 获取分类路径
 const getCategoryPath = () => {
 const getCategoryPath = () => {
   const parts = [];
   const parts = [];
@@ -1302,7 +1418,7 @@ const handleSubmit = async () => {
       submitLoading.value = false;
       submitLoading.value = false;
       return;
       return;
     }
     }
-    if (!carouselImages.value || carouselImages.value.length === 0) {
+    if (!carouselImages.value) {
       ElMessage.warning('请上传商品轮播图');
       ElMessage.warning('请上传商品轮播图');
       submitLoading.value = false;
       submitLoading.value = false;
       return;
       return;
@@ -1313,21 +1429,88 @@ const handleSubmit = async () => {
       return;
       return;
     }
     }
 
 
-    // 校验价格关系:市场价 > 官网价 > 最低售价
-    const midRange = parseFloat(String(productForm.marketPrice));
-    const standard = parseFloat(String(productForm.memberPrice));
-    const certificate = parseFloat(String(productForm.minSellingPrice));
-    if (!isNaN(midRange) && !isNaN(standard) && !isNaN(certificate)) {
-      if (!(midRange > standard)) {
-        ElMessage.warning('市场价必须大于官网价');
-        submitLoading.value = false;
-        return;
-      }
-      if (!(standard > certificate)) {
-        ElMessage.warning('官网价必须大于最低售价');
-        submitLoading.value = false;
-        return;
-      }
+    // 校验价格关系:市场价 > 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价,且均不能为 0
+    const market = parseFloat(String(productForm.marketPrice ?? ''));
+    const member = parseFloat(String(productForm.memberPrice ?? ''));
+    const minSell = parseFloat(String(productForm.minSellingPrice ?? ''));
+    const maxPurch = parseFloat(String(productForm.maxPurchasePrice ?? ''));
+    const purch = parseFloat(String(productForm.purchasingPrice ?? ''));
+
+    const focusField = (refObj: any) => {
+      nextTick(() => {
+        refObj.value?.focus?.();
+      });
+    };
+
+    // 均必须大于 0
+    if (isNaN(market) || market <= 0) {
+      ElMessage.warning('市场价必须大于 0');
+      focusField(marketPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (isNaN(member) || member <= 0) {
+      ElMessage.warning('官网价必须大于 0');
+      focusField(memberPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (isNaN(minSell) || minSell <= 0) {
+      ElMessage.warning('最低售价必须大于 0');
+      focusField(minSellingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (isNaN(maxPurch) || maxPurch <= 0) {
+      ElMessage.warning('最高采购价必须大于 0');
+      focusField(maxPurchasePriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (isNaN(purch) || purch <= 0) {
+      ElMessage.warning('采购价必须大于 0');
+      focusField(purchasingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+
+    // 链式大小校验
+    if (!(market > member)) {
+      ElMessage.warning('市场价必须大于官网价');
+      focusField(marketPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(member >= minSell)) {
+      ElMessage.warning('官网价必须大于等于最低售价');
+      focusField(minSellingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(minSell >= maxPurch)) {
+      ElMessage.warning('最低售价必须大于等于最高采购价');
+      focusField(maxPurchasePriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(maxPurch >= purch)) {
+      ElMessage.warning('最高采购价必须大于等于采购价');
+      focusField(purchasingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    // 采购类价格需低于官网价
+    if (!(maxPurch < member)) {
+      ElMessage.warning('最高采购价需低于官网价');
+      focusField(maxPurchasePriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(purch < member)) {
+      ElMessage.warning('采购价需低于官网价');
+      focusField(purchasingPriceRef);
+      submitLoading.value = false;
+      return;
     }
     }
 
 
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
@@ -1335,8 +1518,8 @@ const handleSubmit = async () => {
       ...productForm,
       ...productForm,
       // 将服务保障ID数组转换为逗号分隔字符串
       // 将服务保障ID数组转换为逗号分隔字符串
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
-      // 轮播图URL逗号分隔
-      imageUrl: carouselImages.value.join(','),
+      // 轮播图(ImageUpload 已是逗号分隔字符串)
+      imageUrl: carouselImages.value,
       // 将商品属性值转换为JSON字符串
       // 将商品属性值转换为JSON字符串
       attributesList: JSON.stringify(productAttributesValues.value),
       attributesList: JSON.stringify(productAttributesValues.value),
       isCustomize: customForm.isCustomize ? 1 : 0,
       isCustomize: customForm.isCustomize ? 1 : 0,
@@ -1388,6 +1571,41 @@ const handleUpcInput = () => {
   }
   }
 };
 };
 
 
+// 商品重量只允许数字和小数点(过滤中文及其他非法字符)
+const handleWeightInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    let v = String(val).replace(/[^\d.]/g, '');
+    // 只保留第一个小数点
+    const firstDot = v.indexOf('.');
+    if (firstDot !== -1) {
+      v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm.productWeight = v;
+  }
+};
+
+// 商品体积只允许数字和小数点
+const handleVolumeInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    let v = String(val).replace(/[^\d.]/g, '');
+    const firstDot = v.indexOf('.');
+    if (firstDot !== -1) {
+      v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm.productVolume = v;
+  }
+};
+
+// 参考链接过滤中文空格(全角空格 U+3000)
+const handleReferenceLinkInput = (val: string) => {
+  if (val !== undefined && val !== null) {
+    const filtered = String(val).replace(/\u3000/g, '');
+    if (filtered !== val) {
+      productForm.referenceLink = filtered;
+    }
+  }
+};
+
 // 销量人气只允许输入整数
 // 销量人气只允许输入整数
 const handleSalesVolumeInput = (val: string) => {
 const handleSalesVolumeInput = (val: string) => {
   if (val !== undefined && val !== null && val !== '') {
   if (val !== undefined && val !== null && val !== '') {
@@ -1516,10 +1734,6 @@ const getUnitOptions = async () => {
   try {
   try {
     const res = await getUnitList();
     const res = await getUnitList();
     unitOptions.value = res.data || [];
     unitOptions.value = res.data || [];
-    // 如果是新增模式且有选项,设置第一个为默认值
-    if (!route.params.id && unitOptions.value.length > 0 && !productForm.unitId) {
-      productForm.unitId = unitOptions.value[0].id;
-    }
   } catch (error) {
   } catch (error) {
     console.error('获取单位列表失败:', error);
     console.error('获取单位列表失败:', error);
   }
   }
@@ -1561,16 +1775,6 @@ const getStaffOptions = async () => {
   }
   }
 };
 };
 
 
-// 获取税率列表
-const getTaxRateOptions = async () => {
-  try {
-    const res = await getTaxRateList();
-    taxRateOptions.value = res.rows || [];
-  } catch (error) {
-    console.error('获取税率列表失败:', error);
-  }
-};
-
 // 加载分类属性列表
 // 加载分类属性列表
 const loadCategoryAttributes = async (categoryId: string | number) => {
 const loadCategoryAttributes = async (categoryId: string | number) => {
   try {
   try {
@@ -1657,16 +1861,9 @@ const loadProductDetail = async () => {
         }
         }
       }
       }
 
 
-      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题
+      // 回显税率(直接使用接口返回值,由税率编码带出,无需下拉匹配
       if (res.data.taxRate !== undefined && res.data.taxRate !== null) {
       if (res.data.taxRate !== undefined && res.data.taxRate !== null) {
-        const apiTaxRate = Number(res.data.taxRate);
-        // 使用精度容差比较浮点数
-        const matchedOption = taxRateOptions.value.find((opt) => Math.abs(Number(opt.taxrate) - apiTaxRate) < 0.0001);
-        if (matchedOption) {
-          productForm.taxRate = matchedOption.taxrate;
-        } else {
-          productForm.taxRate = apiTaxRate;
-        }
+        productForm.taxRate = Number(res.data.taxRate);
       }
       }
 
 
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
@@ -1697,11 +1894,7 @@ const loadProductDetail = async () => {
       }
       }
 
 
       // 回显轮播图
       // 回显轮播图
-      if (res.data.imageUrl) {
-        carouselImages.value = res.data.imageUrl.split(',').filter((url: string) => url.trim());
-      } else {
-        carouselImages.value = [];
-      }
+      carouselImages.value = res.data.imageUrl || '';
 
 
       // 回显分类选择
       // 回显分类选择
       categoryForm.topCategoryId = res.data.topCategoryId;
       categoryForm.topCategoryId = res.data.topCategoryId;
@@ -1846,7 +2039,6 @@ onMounted(async () => {
   await getUnitOptions();
   await getUnitOptions();
   await getAfterSalesOptions();
   await getAfterSalesOptions();
   await getServiceGuaranteeOptions();
   await getServiceGuaranteeOptions();
-  await getTaxRateOptions();
   // 先加载商品详情(如果是编辑模式)
   // 先加载商品详情(如果是编辑模式)
   await loadProductDetail();
   await loadProductDetail();
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个

+ 2 - 2
src/views/product/base/index.vue

@@ -174,7 +174,7 @@
 <!--                <span>{{ scope.row.totalInventory ?? '-' }}</span>-->
 <!--                <span>{{ scope.row.totalInventory ?? '-' }}</span>-->
 <!--              </div>-->
 <!--              </div>-->
 <!--              <div>-->
 <!--              <div>-->
-<!--                <span class="text-gray-500">可用库存:</span>-->
+<!--                <span class="text-gray-500">现有库存:</span>-->
 <!--                <span>{{ scope.row.nowInventory ?? '-' }}</span>-->
 <!--                <span>{{ scope.row.nowInventory ?? '-' }}</span>-->
 <!--              </div>-->
 <!--              </div>-->
 <!--              <div>-->
 <!--              <div>-->
@@ -638,7 +638,7 @@ const inventoryForm = reactive<PriceInventoryForm>({
 
 
 const inventoryRules = {
 const inventoryRules = {
   totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
   totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
-  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前现有库存不能为空', trigger: 'blur' }],
   virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
   virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
 };
 };
 
 

+ 236 - 66
src/views/product/baseAudit/add.vue

@@ -174,6 +174,18 @@
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
             </el-form-item>
             </el-form-item>
 
 
+                        <!-- 商品描述 -->
+            <el-form-item label="商品描述:">
+              <el-input
+                v-model="productForm.productDescription"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品描述"
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+
             <!-- 规格型号 和 UPC(69)条码 -->
             <!-- 规格型号 和 UPC(69)条码 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
@@ -255,9 +267,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="税率:" required>
                 <el-form-item label="税率:" required>
-                  <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
-                    <el-option v-for="option in taxRateOptions" :key="option.id" :label="`${option.taxrateNo},${option.taxrateName}`" :value="option.taxrate" />
-                  </el-select>
+                  <el-input
+                    :model-value="formatTaxRateDisplay(productForm.taxRate)"
+                    placeholder="由税率编码自动带出"
+                    readonly
+                    disabled
+                    class="w-full"
+                  />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -297,16 +313,29 @@
               <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
               <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
             </el-form-item>
 
 
-            <!-- 商品简介 -->
-            <el-form-item label="商品简介:">
-              <el-input v-model="productForm.productDescription" type="textarea" :rows="3" placeholder="请输入商品简介" maxlength="500" show-word-limit />
+                        <!-- 商品说明 -->
+            <el-form-item label="商品说明:">
+              <el-input
+                v-model="productForm.productExplain"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品说明"
+                maxlength="500"
+                show-word-limit
+              />
             </el-form-item>
             </el-form-item>
 
 
             <!-- 重量 和 体积 -->
             <!-- 重量 和 体积 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品重量:">
                 <el-form-item label="商品重量:">
-                  <el-input v-model="productForm.productWeight" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productWeight"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleNumericInput('productWeight')"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                         <el-option label="kg" value="kg" />
                         <el-option label="kg" value="kg" />
@@ -319,7 +348,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品体积:">
                 <el-form-item label="商品体积:">
-                  <el-input v-model="productForm.productVolume" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productVolume"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleNumericInput('productVolume')"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                         <el-option label="m³" value="m3" />
                         <el-option label="m³" value="m3" />
@@ -333,8 +368,15 @@
             </el-row>
             </el-row>
 
 
             <!-- 参考链接 -->
             <!-- 参考链接 -->
-            <el-form-item label="参考链接">
-              <el-input v-model="productForm.referenceLink" type="textarea" :rows="3" placeholder="请输入参考链接" />
+            <el-form-item label="参考链接" prop="referenceLink" required>
+              <el-input
+                ref="referenceLinkRef"
+                v-model="productForm.referenceLink"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入参考链接(不能包含中文空格)"
+                @input="handleReferenceLinkInput"
+              />
             </el-form-item>
             </el-form-item>
 
 
             <!-- 售后服务 -->
             <!-- 售后服务 -->
@@ -370,17 +412,25 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="市场价:" prop="marketPrice" required>
                 <el-form-item label="市场价:" prop="marketPrice" required>
-                  <el-input v-model="productForm.marketPrice" type="number" placeholder="请输入市场价" :min="0" @blur="formatPrice('marketPrice')" />
+                  <el-input
+                    ref="marketPriceRef"
+                    v-model="productForm.marketPrice"
+                    type="number"
+                    placeholder="请输入市场价"
+                    :min="0"
+                    @blur="handlePriceBlur('marketPrice')"
+                  />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="官网价:" prop="memberPrice" required>
                 <el-form-item label="官网价:" prop="memberPrice" required>
                   <el-input
                   <el-input
+                    ref="memberPriceRef"
                     v-model="productForm.memberPrice"
                     v-model="productForm.memberPrice"
                     type="number"
                     type="number"
                     placeholder="请输入平台售价"
                     placeholder="请输入平台售价"
                     :min="0"
                     :min="0"
-                    @blur="formatPrice('memberPrice')"
+                    @blur="handlePriceBlur('memberPrice')"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
@@ -388,7 +438,7 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="最低起订量:" prop="minOrderQuantity" required>
                 <el-form-item label="最低起订量:" prop="minOrderQuantity" required>
-                  <el-input v-model="productForm.minOrderQuantity" min="1" type="number" placeholder="请输入最低起订量" />
+                  <el-input v-model="productForm.minOrderQuantity" type="number" placeholder="请输入最低起订量" />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
@@ -411,30 +461,38 @@
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="供应价:">
                 <el-form-item label="供应价:">
                   <el-input
                   <el-input
+                    ref="supplyPriceRef"
                     v-model="productForm.supplyPrice"
                     v-model="productForm.supplyPrice"
                     type="number"
                     type="number"
                     placeholder="请输入供应价"
                     placeholder="请输入供应价"
                     :min="0"
                     :min="0"
-                    @blur="formatPrice('supplyPrice')"
+                    @blur="handlePriceBlur('supplyPrice')"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
-                <el-form-item label="供应有效时间:">
-                  <el-date-picker
+                <el-form-item label="供应时间(天):">
+                  <el-input
                     v-model="productForm.supplyValidityPeriod"
                     v-model="productForm.supplyValidityPeriod"
-                    type="date"
-                    placeholder="请选择供应有效时间"
-                    value-format="YYYY-MM-DD"
-                    class="w-full"
+                    type="number"
+                    placeholder="请输入供应天数"
+                    :min="0"
+                    @input="calcSupplyExpiryDate"
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
-                <el-form-item label="是否包邮:">
+                <el-form-item label="到期时间:">
+                  <el-input v-model="supplyExpiryDate" disabled placeholder="自动计算" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="一件代发:">
                   <el-radio-group v-model="productForm.supplyPostStatus">
                   <el-radio-group v-model="productForm.supplyPostStatus">
-                    <el-radio :value="0">不包邮</el-radio>
-                    <el-radio :value="1">包邮</el-radio>
+                    <el-radio :value="0">不支持</el-radio>
+                    <el-radio :value="1">支持</el-radio>
                   </el-radio-group>
                   </el-radio-group>
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
@@ -539,13 +597,13 @@
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
             <!-- 商品主图 -->
             <!-- 商品主图 -->
             <el-form-item label="商品主图:" required>
             <el-form-item label="商品主图:" required>
-              <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
+              <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="" />
               <div class="form-item-tip">从图片库选择,建议尺寸300*300px</div>
               <div class="form-item-tip">从图片库选择,建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
             <!-- 商品轮播图 -->
             <!-- 商品轮播图 -->
             <el-form-item label="商品轮播图:" required>
             <el-form-item label="商品轮播图:" required>
-              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
+              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="" />
               <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
               <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
             </el-form-item>
             </el-form-item>
 
 
@@ -710,8 +768,7 @@ import {
   categoryAttributeList,
   categoryAttributeList,
   getAfterSaleList,
   getAfterSaleList,
   getServiceList,
   getServiceList,
-  getUnitList,
-  getTaxRateList
+  getUnitList
 } from '@/api/product/base';
 } from '@/api/product/base';
 import {
 import {
   addBaseAudit,
   addBaseAudit,
@@ -734,18 +791,30 @@ const loading = ref(false);
 const submitLoading = ref(false);
 const submitLoading = ref(false);
 const productFormRef = ref();
 const productFormRef = ref();
 
 
+// 价格与参考链接输入框引用,用于校验失败时聚焦
+const marketPriceRef = ref();
+const memberPriceRef = ref();
+const supplyPriceRef = ref();
+const referenceLinkRef = ref();
+
 // 服务保障和安装服务的多选框
 // 服务保障和安装服务的多选框
 const serviceGuarantees = ref<(string | number)[]>([]);
 const serviceGuarantees = ref<(string | number)[]>([]);
 const installationServices = ref<string[]>([]);
 const installationServices = ref<string[]>([]);
 
 
+// 供应到期时间(根据供应天数自动计算)
+const supplyExpiryDate = ref('');
+
 // 商品详情选项卡
 // 商品详情选项卡
 const activeDetailTab = ref('pc');
 const activeDetailTab = ref('pc');
 
 
 // 轮播图URL数组(UI管理用)
 // 轮播图URL数组(UI管理用)
 const carouselImages = ref<string[]>([]);
 const carouselImages = ref<string[]>([]);
 
 
-// 税率选项
-const taxRateOptions = ref<any[]>([]);
+// 税率显示格式化
+const formatTaxRateDisplay = (val: any) => {
+  if (val === undefined || val === null || val === '') return '';
+  return `${(Number(val) * 100).toFixed(0)}%`;
+};
 
 
 // 税率编码选择组件
 // 税率编码选择组件
 const taxCodeSelectRef = ref();
 const taxCodeSelectRef = ref();
@@ -759,12 +828,16 @@ const handleTaxCodeSelect = async (row: any) => {
     const taxRes = await getTaxCode(row.id);
     const taxRes = await getTaxCode(row.id);
     if (taxRes.data) {
     if (taxRes.data) {
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
+      // 自动带出税率(只读,不可手动修改)
+      productForm.taxRate = (taxRes.data as any).taxrate;
     } else {
     } else {
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
+      productForm.taxRate = row.taxrate;
     }
     }
   } catch (e) {
   } catch (e) {
     console.error('获取税率编码详情失败:', e);
     console.error('获取税率编码详情失败:', e);
     taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
     taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
+    productForm.taxRate = row.taxrate;
   }
   }
   // 同时将显示值存入 form,方便编辑回显时直接读取
   // 同时将显示值存入 form,方便编辑回显时直接读取
   (productForm as any).taxationNo = taxCodeNo.value;
   (productForm as any).taxationNo = taxCodeNo.value;
@@ -963,10 +1036,24 @@ const productRules = {
   // productNo: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
   // productNo: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
+  referenceLink: [
+    { required: true, message: '参考链接不能为空', trigger: 'blur' },
+    {
+      validator: (_rule: any, value: string, callback: any) => {
+        if (value && /[\u3000\u4e00-\u9fa5]/.test(value)) {
+          callback(new Error('参考链接不能包含中文或中文空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
   memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
-  // purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  maxPurchasePrice: [{ required: true, message: '最高采购价不能为空', trigger: 'blur' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
@@ -1248,32 +1335,68 @@ const handleSubmit = async () => {
       return;
       return;
     }
     }
 
 
-    // 校验价格关系:供应价 < 官网价 < 市场价
-    const marketPriceNum = parseFloat(String(productForm.marketPrice));
-    const memberPriceNum = parseFloat(String(productForm.memberPrice));
-    const supplyPriceNum = parseFloat(String(productForm.supplyPrice));
-    if (!isNaN(marketPriceNum) && !isNaN(memberPriceNum)) {
-      if (!(memberPriceNum < marketPriceNum)) {
-        ElMessage.warning('官网价必须小于市场价');
+    // 校验价格链:市场价 > 官网价,且均不为 0
+    const focusInput = async (refObj: any) => {
+      await nextTick();
+      try {
+        refObj?.value?.focus?.();
+      } catch (e) {
+        // 忽略聚焦异常
+      }
+    };
+    const priceFields: Array<{ key: string; label: string; ref: any }> = [
+      { key: 'marketPrice', label: '市场价', ref: marketPriceRef },
+      { key: 'memberPrice', label: '官网价', ref: memberPriceRef }
+    ];
+    // 非空与非零校验
+    for (const f of priceFields) {
+      const raw = (productForm as any)[f.key];
+      if (raw === undefined || raw === null || raw === '') {
+        ElMessage.warning(`${f.label}不能为空`);
+        await focusInput(f.ref);
         submitLoading.value = false;
         submitLoading.value = false;
         return;
         return;
       }
       }
-    }
-    if (!isNaN(supplyPriceNum) && !isNaN(memberPriceNum)) {
-      if (!(supplyPriceNum < memberPriceNum)) {
-        ElMessage.warning('供应价必须小于官网价');
+      const num = parseFloat(String(raw));
+      if (isNaN(num) || num <= 0) {
+        ElMessage.warning(`${f.label}不能为 0`);
+        await focusInput(f.ref);
         submitLoading.value = false;
         submitLoading.value = false;
         return;
         return;
       }
       }
     }
     }
-    if (!isNaN(supplyPriceNum) && !isNaN(marketPriceNum)) {
-      if (!(supplyPriceNum < marketPriceNum)) {
-        ElMessage.warning('供应价必须小于市场价');
+    const marketP = parseFloat(String(productForm.marketPrice));
+    const memberP = parseFloat(String(productForm.memberPrice));
+    if (!(marketP > memberP)) {
+      ElMessage.warning('市场价必须大于官网价');
+      await focusInput(marketPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    // 供应价校验(如果填写了)
+    const supplyPriceNum = parseFloat(String(productForm.supplyPrice));
+    if (!isNaN(supplyPriceNum) && supplyPriceNum > 0) {
+      if (!(supplyPriceNum < memberP)) {
+        ElMessage.warning('供应价必须小于官网价');
         submitLoading.value = false;
         submitLoading.value = false;
         return;
         return;
       }
       }
     }
     }
 
 
+    // 校验参考链接:必填且不能含中文或中文空格
+    if (!productForm.referenceLink || !String(productForm.referenceLink).trim()) {
+      ElMessage.warning('参考链接不能为空');
+      await focusInput(referenceLinkRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (/[\u3000\u4e00-\u9fa5]/.test(String(productForm.referenceLink))) {
+      ElMessage.warning('参考链接不能包含中文或中文空格');
+      await focusInput(referenceLinkRef);
+      submitLoading.value = false;
+      return;
+    }
+
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     const submitProductData: any = {
     const submitProductData: any = {
       ...productForm,
       ...productForm,
@@ -1333,6 +1456,27 @@ const handleUpcInput = () => {
   }
   }
 };
 };
 
 
+// 参考链接输入过滤:移除中文字符与中文全角空格(U+3000)
+const handleReferenceLinkInput = () => {
+  if (productForm.referenceLink) {
+    productForm.referenceLink = productForm.referenceLink.replace(/[\u3000\u4e00-\u9fa5]/g, '');
+  }
+};
+
+// 重量/体积输入过滤:仅保留数字与小数点
+const handleNumericInput = (field: 'productWeight' | 'productVolume') => {
+  const val = productForm[field];
+  if (val !== undefined && val !== null && val !== '') {
+    let str = String(val).replace(/[^\d.]/g, '');
+    // 仅保留首个小数点
+    const firstDot = str.indexOf('.');
+    if (firstDot !== -1) {
+      str = str.slice(0, firstDot + 1) + str.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm[field] = str;
+  }
+};
+
 // 销量人气只允许输入整数
 // 销量人气只允许输入整数
 const handleSalesVolumeInput = (val: string) => {
 const handleSalesVolumeInput = (val: string) => {
   if (val !== undefined && val !== null && val !== '') {
   if (val !== undefined && val !== null && val !== '') {
@@ -1366,6 +1510,45 @@ const formatPrice = (field: string) => {
   }
   }
 };
 };
 
 
+// 价格链校验:供应价 < 官网价 < 市场价,失焦时触发
+const handlePriceBlur = (field: string) => {
+  formatPrice(field);
+  const supply = parseFloat(String(productForm.supplyPrice));
+  const member = parseFloat(String(productForm.memberPrice));
+  const market = parseFloat(String(productForm.marketPrice));
+
+  // 只有当对应字段有值时才校验
+  if (!isNaN(member) && member > 0 && !isNaN(market) && market > 0) {
+    if (member >= market) {
+      ElMessage.warning('官网价必须小于市场价');
+      nextTick(() => memberPriceRef.value?.focus?.());
+      return;
+    }
+  }
+  if (!isNaN(supply) && supply > 0 && !isNaN(member) && member > 0) {
+    if (supply >= member) {
+      ElMessage.warning('供应价必须小于官网价');
+      nextTick(() => supplyPriceRef.value?.focus?.());
+      return;
+    }
+  }
+};
+
+// 计算供应到期时间
+const calcSupplyExpiryDate = () => {
+  const days = parseInt(String(productForm.supplyValidityPeriod));
+  if (!isNaN(days) && days > 0) {
+    const now = new Date();
+    now.setDate(now.getDate() + days);
+    const y = now.getFullYear();
+    const m = String(now.getMonth() + 1).padStart(2, '0');
+    const d = String(now.getDate()).padStart(2, '0');
+    supplyExpiryDate.value = `${y}-${m}-${d}`;
+  } else {
+    supplyExpiryDate.value = '';
+  }
+};
+
 // 格式化表格行中的价格为两位小数(不允许负数)
 // 格式化表格行中的价格为两位小数(不允许负数)
 const formatRowPrice = (row: any, field: string) => {
 const formatRowPrice = (row: any, field: string) => {
   const val = row[field];
   const val = row[field];
@@ -1461,6 +1644,10 @@ const getUnitOptions = async () => {
   try {
   try {
     const res = await getUnitList();
     const res = await getUnitList();
     unitOptions.value = res.data || [];
     unitOptions.value = res.data || [];
+    // 如果是新增模式且有选项,设置第一个为默认值
+    if (!route.params.id && unitOptions.value.length > 0 && !productForm.unitId) {
+      productForm.unitId = unitOptions.value[0].id;
+    }
   } catch (error) {
   } catch (error) {
     console.error('获取单位列表失败:', error);
     console.error('获取单位列表失败:', error);
   }
   }
@@ -1502,16 +1689,6 @@ const getStaffOptions = async () => {
   }
   }
 };
 };
 
 
-// 获取税率列表
-const getTaxRateOptions = async () => {
-  try {
-    const res = await getTaxRateList();
-    taxRateOptions.value = res.rows || [];
-  } catch (error) {
-    console.error('获取税率列表失败:', error);
-  }
-};
-
 // 加载分类属性列表
 // 加载分类属性列表
 const loadCategoryAttributes = async (categoryId: string | number) => {
 const loadCategoryAttributes = async (categoryId: string | number) => {
   try {
   try {
@@ -1527,13 +1704,13 @@ const loadCategoryAttributes = async (categoryId: string | number) => {
           // 下拉选择
           // 下拉选择
           const options = parseAttributesList(attr.attributesList);
           const options = parseAttributesList(attr.attributesList);
           if (options.length > 0) {
           if (options.length > 0) {
-            productAttributesValues.value[attr.productAttributesName] = options[0];
+            productAttributesValues.value[attr.id] = options[0];
           }
           }
         } else if (attr.entryMethod === '3' && attr.attributesList) {
         } else if (attr.entryMethod === '3' && attr.attributesList) {
           // 多选
           // 多选
           const options = parseAttributesList(attr.attributesList);
           const options = parseAttributesList(attr.attributesList);
           if (options.length > 0) {
           if (options.length > 0) {
-            productAttributesValues.value[attr.productAttributesName] = [options[0]];
+            productAttributesValues.value[attr.id] = [options[0]];
           }
           }
         }
         }
       });
       });
@@ -1598,16 +1775,9 @@ const loadProductDetail = async () => {
         }
         }
       }
       }
 
 
-      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题)
+      // 回显税率 - 直接设置数值
       if (res.data.productBaseVo.taxRate !== undefined && res.data.productBaseVo.taxRate !== null) {
       if (res.data.productBaseVo.taxRate !== undefined && res.data.productBaseVo.taxRate !== null) {
-        const apiTaxRate = Number(res.data.productBaseVo.taxRate);
-        // 使用精度容差比较浮点数
-        const matchedOption = taxRateOptions.value.find((opt) => Math.abs(Number(opt.taxrate) - apiTaxRate) < 0.0001);
-        if (matchedOption) {
-          productForm.taxRate = matchedOption.taxrate;
-        } else {
-          productForm.taxRate = apiTaxRate;
-        }
+        productForm.taxRate = Number(res.data.productBaseVo.taxRate);
       }
       }
 
 
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
@@ -1824,7 +1994,7 @@ onMounted(async () => {
   await getUnitOptions();
   await getUnitOptions();
   await getAfterSalesOptions();
   await getAfterSalesOptions();
   await getServiceGuaranteeOptions();
   await getServiceGuaranteeOptions();
-  await getTaxRateOptions();
+
   // 先加载商品详情(如果是编辑模式)
   // 先加载商品详情(如果是编辑模式)
   await loadProductDetail();
   await loadProductDetail();
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个

+ 197 - 39
src/views/product/baseAudit/add1.vue

@@ -188,6 +188,18 @@
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
               <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
             </el-form-item>
             </el-form-item>
 
 
+             <!-- 商品描述 -->
+            <el-form-item label="商品描述:">
+              <el-input
+                v-model="productForm.productDescription"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品描述"
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+
             <!-- 规格型号 和 UPC(69)条码 -->
             <!-- 规格型号 和 UPC(69)条码 -->
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
@@ -269,9 +281,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="税率:" required>
                 <el-form-item label="税率:" required>
-                  <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
-                    <el-option v-for="option in taxRateOptions" :key="option.id" :label="`${option.taxrateNo},${option.taxrateName}`" :value="option.taxrate" />
-                  </el-select>
+                  <el-input
+                    :model-value="formatTaxRateDisplay(productForm.taxRate)"
+                    placeholder="由税率编码自动带出"
+                    readonly
+                    disabled
+                    class="w-full"
+                  />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -308,12 +324,19 @@
 
 
             <!-- 促销标题 -->
             <!-- 促销标题 -->
             <el-form-item label="促销标题:">
             <el-form-item label="促销标题:">
-              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+              <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
             </el-form-item>
 
 
-            <!-- 商品简介 -->
-            <el-form-item label="商品简介:">
-              <el-input v-model="productForm.productDescription" type="textarea" :rows="3" placeholder="请输入商品简介" maxlength="500" show-word-limit />
+                        <!-- 商品说明 -->
+            <el-form-item label="商品说明:">
+              <el-input
+                v-model="productForm.productExplain"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入商品说明"
+                maxlength="500"
+                show-word-limit
+              />
             </el-form-item>
             </el-form-item>
 
 
 
 
@@ -321,7 +344,13 @@
             <el-row :gutter="20">
             <el-row :gutter="20">
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品重量:">
                 <el-form-item label="商品重量:">
-                  <el-input v-model="productForm.productWeight" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productWeight"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleNumericInput('productWeight')"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                       <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
                         <el-option label="kg" value="kg" />
                         <el-option label="kg" value="kg" />
@@ -334,7 +363,13 @@
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="商品体积:">
                 <el-form-item label="商品体积:">
-                  <el-input v-model="productForm.productVolume" placeholder="0" maxlength="10" show-word-limit>
+                  <el-input
+                    v-model="productForm.productVolume"
+                    placeholder="0"
+                    maxlength="10"
+                    show-word-limit
+                    @input="handleNumericInput('productVolume')"
+                  >
                     <template #append>
                     <template #append>
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                       <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
                         <el-option label="m³" value="m3" />
                         <el-option label="m³" value="m3" />
@@ -348,8 +383,15 @@
             </el-row>
             </el-row>
 
 
             <!-- 参考链接 -->
             <!-- 参考链接 -->
-            <el-form-item label="参考链接">
-              <el-input v-model="productForm.referenceLink" type="textarea" :rows="3" placeholder="请输入参考链接" />
+            <el-form-item label="参考链接" prop="referenceLink" required>
+              <el-input
+                ref="referenceLinkRef"
+                v-model="productForm.referenceLink"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入参考链接(不能包含中文空格)"
+                @input="handleReferenceLinkInput"
+              />
             </el-form-item>
             </el-form-item>
 
 
 
 
@@ -399,6 +441,7 @@
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="市场价:" prop="marketPrice" required>
                 <el-form-item label="市场价:" prop="marketPrice" required>
                   <el-input
                   <el-input
+                    ref="marketPriceRef"
                     v-model="productForm.marketPrice"
                     v-model="productForm.marketPrice"
                     type="number"
                     type="number"
                     placeholder="请输入市场价"
                     placeholder="请输入市场价"
@@ -410,6 +453,7 @@
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="官网价:" prop="memberPrice" required>
                 <el-form-item label="官网价:" prop="memberPrice" required>
                   <el-input
                   <el-input
+                    ref="memberPriceRef"
                     v-model="productForm.memberPrice"
                     v-model="productForm.memberPrice"
                     type="number"
                     type="number"
                     placeholder="请输入平台售价"
                     placeholder="请输入平台售价"
@@ -421,6 +465,7 @@
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="最低售价:" prop="minSellingPrice" required>
                 <el-form-item label="最低售价:" prop="minSellingPrice" required>
                   <el-input
                   <el-input
+                    ref="minSellingPriceRef"
                     v-model="productForm.minSellingPrice"
                     v-model="productForm.minSellingPrice"
                     type="number"
                     type="number"
                     placeholder="请输入最低售价"
                     placeholder="请输入最低售价"
@@ -438,7 +483,7 @@
               </el-col>
               </el-col>
               <el-col :span="8">
               <el-col :span="8">
                 <el-form-item label="备注:">
                 <el-form-item label="备注:">
-                  <span class="currency-text">市场价>官网价>最低售价</span>
+                  <span class="currency-text">市场价 &gt; 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价</span>
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
@@ -456,6 +501,7 @@
               <el-col :span="12">
               <el-col :span="12">
                 <el-form-item label="采购价:" prop="purchasingPrice" required>
                 <el-form-item label="采购价:" prop="purchasingPrice" required>
                   <el-input
                   <el-input
+                    ref="purchasingPriceRef"
                     v-model="productForm.purchasingPrice"
                     v-model="productForm.purchasingPrice"
                     type="number"
                     type="number"
                     placeholder="请输入采购价"
                     placeholder="请输入采购价"
@@ -465,8 +511,9 @@
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
               <el-col :span="12">
               <el-col :span="12">
-                <el-form-item label="最高采购价:">
+                <el-form-item label="最高采购价:" prop="maxPurchasePrice" required>
                   <el-input
                   <el-input
+                    ref="maxPurchasePriceRef"
                     v-model="productForm.maxPurchasePrice"
                     v-model="productForm.maxPurchasePrice"
                     type="number"
                     type="number"
                     placeholder="请输入最高采购价"
                     placeholder="请输入最高采购价"
@@ -628,9 +675,6 @@
                 <el-tab-pane label="电脑端详情" name="pc">
                 <el-tab-pane label="电脑端详情" name="pc">
                   <Editor v-model="productForm.pcDetail" :height="400" />
                   <Editor v-model="productForm.pcDetail" :height="400" />
                 </el-tab-pane>
                 </el-tab-pane>
-                <el-tab-pane label="移动端详情" name="mobile">
-                  <Editor v-model="productForm.mobileDetail" :height="400" />
-                </el-tab-pane>
               </el-tabs>
               </el-tabs>
             </el-form-item>
             </el-form-item>
           </el-form>
           </el-form>
@@ -783,8 +827,7 @@ import {
   categoryAttributeList,
   categoryAttributeList,
   getAfterSaleList,
   getAfterSaleList,
   getServiceList,
   getServiceList,
-  getUnitList,
-  getTaxRateList
+  getUnitList
 } from '@/api/product/base';
 } from '@/api/product/base';
 import {
 import {
   addBaseAudit,
   addBaseAudit,
@@ -807,6 +850,14 @@ const loading = ref(false);
 const submitLoading = ref(false);
 const submitLoading = ref(false);
 const productFormRef = ref();
 const productFormRef = ref();
 
 
+// 价格与参考链接输入框引用,用于校验失败时聚焦
+const marketPriceRef = ref();
+const memberPriceRef = ref();
+const minSellingPriceRef = ref();
+const maxPurchasePriceRef = ref();
+const purchasingPriceRef = ref();
+const referenceLinkRef = ref();
+
 // 服务保障和安装服务的多选框
 // 服务保障和安装服务的多选框
 const serviceGuarantees = ref<(string | number)[]>([]);
 const serviceGuarantees = ref<(string | number)[]>([]);
 const installationServices = ref<string[]>([]);
 const installationServices = ref<string[]>([]);
@@ -817,8 +868,11 @@ const activeDetailTab = ref('pc');
 // 轮播图URL数组(UI管理用)
 // 轮播图URL数组(UI管理用)
 const carouselImages = ref<string[]>([]);
 const carouselImages = ref<string[]>([]);
 
 
-// 税率选项
-const taxRateOptions = ref<any[]>([]);
+// 税率显示格式化
+const formatTaxRateDisplay = (val: any) => {
+  if (val === undefined || val === null || val === '') return '';
+  return `${(Number(val) * 100).toFixed(0)}%`;
+};
 
 
 // 税率编码选择组件
 // 税率编码选择组件
 const taxCodeSelectRef = ref();
 const taxCodeSelectRef = ref();
@@ -832,12 +886,16 @@ const handleTaxCodeSelect = async (row: any) => {
     const taxRes = await getTaxCode(row.id);
     const taxRes = await getTaxCode(row.id);
     if (taxRes.data) {
     if (taxRes.data) {
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
       taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
+      // 自动带出税率(只读,不可手动修改)
+      productForm.taxRate = taxRes.data.taxrate;
     } else {
     } else {
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
       taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
+      productForm.taxRate = row.taxrate;
     }
     }
   } catch (e) {
   } catch (e) {
     console.error('获取税率编码详情失败:', e);
     console.error('获取税率编码详情失败:', e);
     taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
     taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
+    productForm.taxRate = row.taxrate;
   }
   }
   // 同时将显示值存入 form,方便编辑回显时直接读取
   // 同时将显示值存入 form,方便编辑回显时直接读取
   (productForm as any).taxationNo = taxCodeNo.value;
   (productForm as any).taxationNo = taxCodeNo.value;
@@ -1034,10 +1092,24 @@ const productRules = {
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
   // mainLibraryIntro: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
   // mainLibraryIntro: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
+  referenceLink: [
+    { required: true, message: '参考链接不能为空', trigger: 'blur' },
+    {
+      validator: (_rule: any, value: string, callback: any) => {
+        if (value && /[\u3000\u4e00-\u9fa5]/.test(value)) {
+          callback(new Error('参考链接不能包含中文或中文空格'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
   memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
   memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
+  maxPurchasePrice: [{ required: true, message: '最高采购价不能为空', trigger: 'blur' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
@@ -1319,22 +1391,95 @@ const handleSubmit = async () => {
       return;
       return;
     }
     }
 
 
-    // 校验价格关系:市场价 > 官网价 > 最低售价
-    const midRange = parseFloat(String(productForm.marketPrice));
-    const standard = parseFloat(String(productForm.memberPrice));
-    const certificate = parseFloat(String(productForm.minSellingPrice));
-    if (!isNaN(midRange) && !isNaN(standard) && !isNaN(certificate)) {
-      if (!(midRange > standard)) {
-        ElMessage.warning('市场价必须大于官网价');
+    // 校验价格链:市场价 > 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价,且均不为 0
+    const focusInput = async (refObj: any) => {
+      await nextTick();
+      try {
+        refObj?.value?.focus?.();
+      } catch (e) {
+        // 忽略聚焦异常
+      }
+    };
+    const priceFields: Array<{ key: string; label: string; ref: any }> = [
+      { key: 'marketPrice', label: '市场价', ref: marketPriceRef },
+      { key: 'memberPrice', label: '官网价', ref: memberPriceRef },
+      { key: 'minSellingPrice', label: '最低售价', ref: minSellingPriceRef },
+      { key: 'maxPurchasePrice', label: '最高采购价', ref: maxPurchasePriceRef },
+      { key: 'purchasingPrice', label: '采购价', ref: purchasingPriceRef }
+    ];
+    // 非空与非零校验
+    for (const f of priceFields) {
+      const raw = (productForm as any)[f.key];
+      if (raw === undefined || raw === null || raw === '') {
+        ElMessage.warning(`${f.label}不能为空`);
+        await focusInput(f.ref);
         submitLoading.value = false;
         submitLoading.value = false;
         return;
         return;
       }
       }
-      if (!(standard > certificate)) {
-        ElMessage.warning('官网价必须大于最低售价');
+      const num = parseFloat(String(raw));
+      if (isNaN(num) || num <= 0) {
+        ElMessage.warning(`${f.label}不能为 0`);
+        await focusInput(f.ref);
         submitLoading.value = false;
         submitLoading.value = false;
         return;
         return;
       }
       }
     }
     }
+    const marketP = parseFloat(String(productForm.marketPrice));
+    const memberP = parseFloat(String(productForm.memberPrice));
+    const minSellP = parseFloat(String(productForm.minSellingPrice));
+    const maxPurP = parseFloat(String(productForm.maxPurchasePrice));
+    const purP = parseFloat(String(productForm.purchasingPrice));
+    if (!(marketP > memberP)) {
+      ElMessage.warning('市场价必须大于官网价');
+      await focusInput(marketPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(memberP >= minSellP)) {
+      ElMessage.warning('官网价必须大于或等于最低售价');
+      await focusInput(memberPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(minSellP >= maxPurP)) {
+      ElMessage.warning('最低售价必须大于或等于最高采购价');
+      await focusInput(minSellingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(maxPurP >= purP)) {
+      ElMessage.warning('最高采购价必须大于或等于采购价');
+      await focusInput(maxPurchasePriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    // 采购价与最高采购价均须低于官网价
+    if (!(maxPurP < memberP)) {
+      ElMessage.warning('最高采购价必须低于官网价');
+      await focusInput(maxPurchasePriceRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (!(purP < memberP)) {
+      ElMessage.warning('采购价必须低于官网价');
+      await focusInput(purchasingPriceRef);
+      submitLoading.value = false;
+      return;
+    }
+
+    // 校验参考链接:必填且不能含中文或中文空格
+    if (!productForm.referenceLink || !String(productForm.referenceLink).trim()) {
+      ElMessage.warning('参考链接不能为空');
+      await focusInput(referenceLinkRef);
+      submitLoading.value = false;
+      return;
+    }
+    if (/[\u3000\u4e00-\u9fa5]/.test(String(productForm.referenceLink))) {
+      ElMessage.warning('参考链接不能包含中文或中文空格');
+      await focusInput(referenceLinkRef);
+      submitLoading.value = false;
+      return;
+    }
 
 
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     const submitProductData: any = {
     const submitProductData: any = {
@@ -1395,6 +1540,27 @@ const handleUpcInput = () => {
   }
   }
 };
 };
 
 
+// 参考链接输入过滤:移除中文字符与中文全角空格(U+3000)
+const handleReferenceLinkInput = () => {
+  if (productForm.referenceLink) {
+    productForm.referenceLink = productForm.referenceLink.replace(/[\u3000\u4e00-\u9fa5]/g, '');
+  }
+};
+
+// 重量/体积输入过滤:仅保留数字与小数点
+const handleNumericInput = (field: 'productWeight' | 'productVolume') => {
+  const val = productForm[field];
+  if (val !== undefined && val !== null && val !== '') {
+    let str = String(val).replace(/[^\d.]/g, '');
+    // 仅保留首个小数点
+    const firstDot = str.indexOf('.');
+    if (firstDot !== -1) {
+      str = str.slice(0, firstDot + 1) + str.slice(firstDot + 1).replace(/\./g, '');
+    }
+    productForm[field] = str;
+  }
+};
+
 // 销量人气只允许输入整数
 // 销量人气只允许输入整数
 const handleSalesVolumeInput = (val: string) => {
 const handleSalesVolumeInput = (val: string) => {
   if (val !== undefined && val !== null && val !== '') {
   if (val !== undefined && val !== null && val !== '') {
@@ -1568,15 +1734,7 @@ const getStaffOptions = async () => {
   }
   }
 };
 };
 
 
-// 获取税率列表
-const getTaxRateOptions = async () => {
-  try {
-    const res = await getTaxRateList();
-    taxRateOptions.value = res.rows || [];
-  } catch (error) {
-    console.error('获取税率列表失败:', error);
-  }
-};
+
 
 
 // 加载分类属性列表
 // 加载分类属性列表
 const loadCategoryAttributes = async (categoryId: string | number) => {
 const loadCategoryAttributes = async (categoryId: string | number) => {
@@ -1853,7 +2011,7 @@ onMounted(async () => {
   await getUnitOptions();
   await getUnitOptions();
   await getAfterSalesOptions();
   await getAfterSalesOptions();
   await getServiceGuaranteeOptions();
   await getServiceGuaranteeOptions();
-  await getTaxRateOptions();
+
   // 先加载商品详情(如果是编辑模式)
   // 先加载商品详情(如果是编辑模式)
   await loadProductDetail();
   await loadProductDetail();
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
   // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个

+ 14 - 2
src/views/product/baseAudit/view.vue

@@ -1,6 +1,6 @@
 <template>
 <template>
-  <div class="app-container">
-    <el-card shadow="never" class="mb-3">
+  <div class="app-container view-scroll-container">
+    <el-card shadow="never" class="mb-3 view-header-card">
       <div class="flex items-center justify-between">
       <div class="flex items-center justify-between">
         <div class="flex items-center">
         <div class="flex items-center">
           <el-button icon="ArrowLeft" @click="handleBack">返回</el-button>
           <el-button icon="ArrowLeft" @click="handleBack">返回</el-button>
@@ -1672,6 +1672,18 @@ onMounted(async () => {
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
+.view-scroll-container {
+  height: calc(100vh - 84px);
+  overflow-y: auto;
+  overflow-x: hidden;
+}
+
+.view-header-card {
+  position: sticky;
+  top: 0;
+  z-index: 10;
+}
+
 .product-wizard-page {
 .product-wizard-page {
   .category-selection {
   .category-selection {
     margin-top: 12px;
     margin-top: 12px;

+ 5 - 5
src/views/product/priceInventory/index.vue

@@ -22,8 +22,8 @@
             <el-form-item label="总库存量" prop="totalInventory">
             <el-form-item label="总库存量" prop="totalInventory">
               <el-input v-model="queryParams.totalInventory" placeholder="请输入总库存量" clearable @keyup.enter="handleQuery" />
               <el-input v-model="queryParams.totalInventory" placeholder="请输入总库存量" clearable @keyup.enter="handleQuery" />
             </el-form-item>
             </el-form-item>
-            <el-form-item label="当前可用库存" prop="nowInventory">
-              <el-input v-model="queryParams.nowInventory" placeholder="请输入当前可用库存" clearable @keyup.enter="handleQuery" />
+            <el-form-item label="当前现有库存" prop="nowInventory">
+              <el-input v-model="queryParams.nowInventory" placeholder="请输入当前现有库存" clearable @keyup.enter="handleQuery" />
             </el-form-item>
             </el-form-item>
             <el-form-item label="虚拟库存" prop="virtualInventory">
             <el-form-item label="虚拟库存" prop="virtualInventory">
               <el-input v-model="queryParams.virtualInventory" placeholder="请输入虚拟库存" clearable @keyup.enter="handleQuery" />
               <el-input v-model="queryParams.virtualInventory" placeholder="请输入虚拟库存" clearable @keyup.enter="handleQuery" />
@@ -77,7 +77,7 @@
         <el-table-column label="采购价格" align="center" prop="purchasingPrice" />
         <el-table-column label="采购价格" align="center" prop="purchasingPrice" />
         <el-table-column label="最高采购价格" align="center" prop="maxPurchasePrice" />
         <el-table-column label="最高采购价格" align="center" prop="maxPurchasePrice" />
         <el-table-column label="总库存量" align="center" prop="totalInventory" />
         <el-table-column label="总库存量" align="center" prop="totalInventory" />
-        <el-table-column label="当前可用库存" align="center" prop="nowInventory" />
+        <el-table-column label="当前现有库存" align="center" prop="nowInventory" />
         <el-table-column label="虚拟库存" align="center" prop="virtualInventory" />
         <el-table-column label="虚拟库存" align="center" prop="virtualInventory" />
         <el-table-column label="最小起订数量" align="center" prop="minOrderQuantity" />
         <el-table-column label="最小起订数量" align="center" prop="minOrderQuantity" />
         <el-table-column label="税率" align="center" prop="taxRate" />
         <el-table-column label="税率" align="center" prop="taxRate" />
@@ -118,8 +118,8 @@
         <el-form-item label="总库存量" prop="totalInventory">
         <el-form-item label="总库存量" prop="totalInventory">
           <el-input v-model="form.totalInventory" placeholder="请输入总库存量" />
           <el-input v-model="form.totalInventory" placeholder="请输入总库存量" />
         </el-form-item>
         </el-form-item>
-        <el-form-item label="当前可用库存" prop="nowInventory">
-          <el-input v-model="form.nowInventory" placeholder="请输入当前可用库存" />
+        <el-form-item label="当前现有库存" prop="nowInventory">
+          <el-input v-model="form.nowInventory" placeholder="请输入当前现有库存" />
         </el-form-item>
         </el-form-item>
         <el-form-item label="虚拟库存" prop="virtualInventory">
         <el-form-item label="虚拟库存" prop="virtualInventory">
           <el-input v-model="form.virtualInventory" placeholder="请输入虚拟库存" />
           <el-input v-model="form.virtualInventory" placeholder="请输入虚拟库存" />