Explorar el Código

添加计划任务20分钟执行一根据当前汇率跟新产品的所有价格

13147038669 hace 5 meses
padre
commit
9d3b355937
Se han modificado 23 ficheros con 638 adiciones y 46 borrados
  1. 12 0
      crmeb_src/mer_java/crmeb-admin/src/main/java/com/zbkj/admin/controller/publicly/CacheController.java
  2. 44 0
      crmeb_src/mer_java/crmeb-admin/src/main/java/com/zbkj/admin/task/product/ProductPriceTask.java
  3. 41 0
      crmeb_src/mer_java/crmeb-admin/src/test/java/com/zbkj/admin/ProductPriceTaskTest.java
  4. 15 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/product/Product.java
  5. 15 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/product/ProductAttrValue.java
  6. 0 2
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/user/UserBalanceRecord.java
  7. 5 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/request/ProductAddRequest.java
  8. 21 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/request/ProductAttrValueAddRequest.java
  9. 6 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/AdminProductListResponse.java
  10. 12 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/AttrValueResponse.java
  11. 0 11
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/OrderFrontDataResponse.java
  12. 3 0
      crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/ProductInfoResponse.java
  13. 21 0
      crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/ProductTaskService.java
  14. 20 0
      crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ProductServiceImpl.java
  15. 98 0
      crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ProductTaskServiceImpl.java
  16. 10 0
      crmeb_src/mer_mer_admin/src/api/product.js
  17. 3 3
      crmeb_src/mer_mer_admin/src/views/product/comment/creatComment.vue
  18. 151 5
      crmeb_src/mer_mer_admin/src/views/product/components/creatAttr.vue
  19. 4 4
      crmeb_src/mer_mer_admin/src/views/product/components/storeEdit.vue
  20. 114 16
      crmeb_src/mer_mer_admin/src/views/product/creatProduct/TableHeadList.js
  21. 20 4
      crmeb_src/mer_mer_admin/src/views/product/creatProduct/default.js
  22. 21 0
      crmeb_src/mer_mer_admin/src/views/product/creatProduct/index.vue
  23. 2 1
      crmeb_src/mer_mer_admin/src/views/product/index.vue

+ 12 - 0
crmeb_src/mer_java/crmeb-admin/src/main/java/com/zbkj/admin/controller/publicly/CacheController.java

@@ -1,6 +1,8 @@
 package com.zbkj.admin.controller.publicly;
 
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.zbkj.common.constants.SysConfigConstants;
 import com.zbkj.common.exception.CrmebException;
 import com.zbkj.common.result.CommonResult;
 import com.zbkj.common.utils.RedisUtil;
@@ -46,4 +48,14 @@ public class CacheController {
         redisUtil.hmDelete(key);
         return CommonResult.success("删除缓存成功");
     }
+
+    @ApiOperation(value = "获取sl汇率")
+    @RequestMapping(value = "getSlRate", method = RequestMethod.GET)
+    public CommonResult<JSONObject> getSlRate() {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("LGNS_TO_USD", redisUtil.get(SysConfigConstants.DAIBI_RATE_LGNS_USD));
+        jsonObject.put("LGNS_TO_CNY", redisUtil.get(SysConfigConstants.DAIBI_RATE_LGNS_CNY));
+        jsonObject.put("USD_TO_CNY", redisUtil.get(SysConfigConstants.DAIBI_RATE_USD_CNY));
+        return CommonResult.success(jsonObject);
+    }
 }

+ 44 - 0
crmeb_src/mer_java/crmeb-admin/src/main/java/com/zbkj/admin/task/product/ProductPriceTask.java

@@ -0,0 +1,44 @@
+package com.zbkj.admin.task.product;
+
+import com.zbkj.common.utils.CrmebDateUtil;
+import com.zbkj.service.service.ProductTaskService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 自动根据汇率修改产品各价格定时任务
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team <admin@crmeb.com>
+ * +----------------------------------------------------------------------
+ */
+@Component("ProductPriceTask")
+public class ProductPriceTask {
+
+    private static final Logger logger = LoggerFactory.getLogger(ProductPriceTask.class);
+
+    @Autowired
+    private ProductTaskService productTaskService;
+
+    /**
+     * 自动根据汇率修改产品各价格
+     * cron : 0 1/20 * * * ?
+     */
+    public void updateProductPrice() {
+        logger.info("---ProductPriceTask updateProductPrice task------Execution Time - {}",
+                CrmebDateUtil.nowDateTime());
+        try {
+            productTaskService.updateProductPrice();
+        } catch (Exception e) {
+            e.printStackTrace();
+            logger.error("ProductPriceTask.updateProductPrice" + " | msg : " + e.getMessage());
+        }
+    }
+}

+ 41 - 0
crmeb_src/mer_java/crmeb-admin/src/test/java/com/zbkj/admin/ProductPriceTaskTest.java

@@ -0,0 +1,41 @@
+package com.zbkj.admin;
+
+import com.zbkj.common.constants.SysConfigConstants;
+import com.zbkj.common.utils.RedisUtil;
+import com.zbkj.service.service.ProductTaskService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.math.BigDecimal;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class ProductPriceTaskTest {
+
+    @Autowired
+    private ProductTaskService productTaskService;
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Test
+    public void testUpdateProductPrice() {
+        System.out.println("开始执行产品价格更新任务测试...");
+
+        // 模拟 Redis 中的汇率值 (假设 1 LGNS = 5.5 RMB)
+        BigDecimal mockRate = new BigDecimal("5.5");
+        redisUtil.set(SysConfigConstants.DAIBI_RATE_LGNS_CNY, mockRate);
+        System.out.println("模拟汇率已设置: " + mockRate);
+
+        try {
+            productTaskService.updateProductPrice();
+            System.out.println("产品价格更新任务执行成功。");
+        } catch (Exception e) {
+            System.err.println("产品价格更新任务执行失败:" + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}

+ 15 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/product/Product.java

@@ -71,12 +71,24 @@ public class Product implements Serializable {
     @ApiModelProperty(value = "商品价格")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "商品价格")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "会员价格")
     private BigDecimal vipPrice;
 
+    @ApiModelProperty(value = "会员价格")
+    private BigDecimal vipPriceRmb;
+
+    @ApiModelProperty(value = "汇率")
+    private BigDecimal lgnToCny;
+
     @ApiModelProperty(value = "市场价/原价/划线价")
     private BigDecimal otPrice;
 
+    @ApiModelProperty(value = "市场价/原价/划线价")
+    private BigDecimal otPriceRmb;
+
     @ApiModelProperty(value = "单位名")
     private String unitName;
 
@@ -89,6 +101,9 @@ public class Product implements Serializable {
     @ApiModelProperty(value = "成本价")
     private BigDecimal cost;
 
+    @ApiModelProperty(value = "成本价")
+    private BigDecimal costRmb;
+
     @ApiModelProperty(value = "虚拟销量")
     private Integer ficti;
 

+ 15 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/product/ProductAttrValue.java

@@ -49,21 +49,33 @@ public class ProductAttrValue implements Serializable {
     @ApiModelProperty(value = "价格")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "价格")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "图片")
     private String image;
 
     @ApiModelProperty(value = "成本价")
     private BigDecimal cost;
 
+    @ApiModelProperty(value = "成本价")
+    private BigDecimal costRmb;
+
     @ApiModelProperty(value = "商品条码")
     private String barCode;
 
     @ApiModelProperty(value = "原价")
     private BigDecimal otPrice;
 
+    @ApiModelProperty(value = "原价")
+    private BigDecimal otPriceRmb;
+
     @ApiModelProperty(value = "重量")
     private BigDecimal weight;
 
+    @ApiModelProperty(value = "汇率")
+    private BigDecimal lgnToCny;
+
     @ApiModelProperty(value = "体积")
     private BigDecimal volume;
 
@@ -106,6 +118,9 @@ public class ProductAttrValue implements Serializable {
     @ApiModelProperty(value = "会员价格")
     private BigDecimal vipPrice;
 
+    @ApiModelProperty(value = "会员价格")
+    private BigDecimal vipPriceRmb;
+
     @ApiModelProperty(value = "营销类型:0=基础商品,1=秒杀,2=拼团")
     private Integer marketingType;
 

+ 0 - 2
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/model/user/UserBalanceRecord.java

@@ -63,6 +63,4 @@ public class UserBalanceRecord implements Serializable {
     @ApiModelProperty(value = "提现状态(只有在提现的时候会在数据中加载)")
     private Integer withdrawStatus;
 
-    @ApiModelProperty(value = "操作时汇率")
-    private BigDecimal rate;
 }

+ 5 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/request/ProductAddRequest.java

@@ -14,6 +14,7 @@ import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -62,6 +63,10 @@ public class ProductAddRequest implements Serializable {
     @Length(max = 50, message = "商品名称长度不能超过50个字符")
     private String name;
 
+    @ApiModelProperty(value = "商品名称", required = true)
+    @NotNull(message = "汇率不能为空")
+    BigDecimal lgnToCny;
+
     @ApiModelProperty(value = "商品简介", required = true)
     @NotBlank(message = "商品简介不能为空")
     @Length(max = 100, message = "商品简介长度不能超过100个字符")

+ 21 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/request/ProductAttrValueAddRequest.java

@@ -48,9 +48,18 @@ public class ProductAttrValueAddRequest implements Serializable {
     @DecimalMax(value = "999999.99", message = "商品金额最大为999999.99")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "规格属性金额", required = true)
+    @NotNull(message = "规格属性金额不能为空")
+    @DecimalMin(value = "0", message = "金额不能小于0")
+    @DecimalMax(value = "999999.99", message = "商品金额最大为999999.99")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "会员价格")
     private BigDecimal vipPrice;
 
+    @ApiModelProperty(value = "会员价格")
+    private BigDecimal vipPriceRmb;
+
     @ApiModelProperty(value = "图片", required = true)
     @NotEmpty(message = "商品规格属性图片不能为空")
     private String image;
@@ -61,12 +70,24 @@ public class ProductAttrValueAddRequest implements Serializable {
     @DecimalMax(value = "999999.99", message = "商品成本价最大为999999.99")
     private BigDecimal cost;
 
+    @ApiModelProperty(value = "成本价", required = true)
+    @NotNull(message = "规格属性成本价不能为空")
+    @DecimalMin(value = "0", message = "成本价不能小于0")
+    @DecimalMax(value = "999999.99", message = "商品成本价最大为999999.99")
+    private BigDecimal costRmb;
+
     @ApiModelProperty(value = "原价", required = true)
     @NotNull(message = "规格属性原价不能为空")
     @DecimalMin(value = "0", message = "原价不能小于0")
     @DecimalMax(value = "999999.99", message = "商品原价最大为999999.99")
     private BigDecimal otPrice;
 
+    @ApiModelProperty(value = "原价", required = true)
+    @NotNull(message = "规格属性原价不能为空")
+    @DecimalMin(value = "0", message = "原价不能小于0")
+    @DecimalMax(value = "999999.99", message = "商品原价最大为999999.99")
+    private BigDecimal otPriceRmb;
+
     @ApiModelProperty(value = "重量", required = true)
     //@NotNull(message = "规格属性重量不能为空")
     @DecimalMin(value = "0", message = "重量不能小于0")

+ 6 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/AdminProductListResponse.java

@@ -50,9 +50,15 @@ public class AdminProductListResponse implements Serializable {
     @ApiModelProperty(value = "商品价格")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "商品价格")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "会员价格")
     private BigDecimal vipPrice;
 
+    @ApiModelProperty(value = "会员价格")
+    private BigDecimal vipPriceRmb;
+
     @ApiModelProperty(value = "排序")
     private Integer sort;
 

+ 12 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/AttrValueResponse.java

@@ -48,15 +48,24 @@ public class AttrValueResponse implements Serializable {
     @ApiModelProperty(value = "属性金额")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "属性金额")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "图片")
     private String image;
 
     @ApiModelProperty(value = "成本价")
     private BigDecimal cost;
 
+    @ApiModelProperty(value = "成本价")
+    private BigDecimal costRmb;
+
     @ApiModelProperty(value = "原价")
     private BigDecimal otPrice;
 
+    @ApiModelProperty(value = "原价")
+    private BigDecimal otPriceRmb;
+
     @ApiModelProperty(value = "重量")
     private BigDecimal weight;
 
@@ -96,6 +105,9 @@ public class AttrValueResponse implements Serializable {
     @ApiModelProperty(value = "会员价格")
     private BigDecimal vipPrice;
 
+    @ApiModelProperty(value = "会员价格")
+    private BigDecimal vipPriceRmb;
+
     @ApiModelProperty(value = "兑换积分")
     private Integer redeemIntegral;
 

+ 0 - 11
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/OrderFrontDataResponse.java

@@ -116,15 +116,4 @@ public class OrderFrontDataResponse implements Serializable {
     @ApiModelProperty(value = "预约订单取消预约小时数")
     private Integer cancelServiceOrderHour;
 
-    @ApiModelProperty(value = "汇率(RmbToSl)")
-    private BigDecimal rate;
-
-    @ApiModelProperty(value = "汇率差(total_price_reat-pay_fee_sl)")
-    private BigDecimal rateDiff;
-
-    @ApiModelProperty(value = "SL订单金额")
-    private BigDecimal totalPriceReat;
-
-    @ApiModelProperty(value = "rmb算出来的订单金额/汇率")
-    private BigDecimal payFeeSl;
 }

+ 3 - 0
crmeb_src/mer_java/crmeb-common/src/main/java/com/zbkj/common/response/ProductInfoResponse.java

@@ -108,6 +108,9 @@ public class ProductInfoResponse implements Serializable {
     @ApiModelProperty(value = "商品价格")
     private BigDecimal price;
 
+    @ApiModelProperty(value = "商品价格")
+    private BigDecimal priceRmb;
+
     @ApiModelProperty(value = "销量")
     private Integer sales;
 

+ 21 - 0
crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/ProductTaskService.java

@@ -0,0 +1,21 @@
+package com.zbkj.service.service;
+
+/**
+ * 产品任务服务接口
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team <admin@crmeb.com>
+ * +----------------------------------------------------------------------
+ */
+public interface ProductTaskService {
+
+    /**
+     * 自动根据汇率修改产品各种价格
+     */
+    void updateProductPrice();
+}

+ 20 - 0
crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ProductServiceImpl.java

@@ -319,6 +319,11 @@ public class ProductServiceImpl extends ServiceImpl<ProductDao, Product> impleme
         product.setPrice(minAttrValue.getPrice());
         product.setOtPrice(minAttrValue.getOtPrice());
         product.setCost(minAttrValue.getCost());
+        product.setCostRmb(minAttrValue.getCostRmb());
+        product.setOtPriceRmb(minAttrValue.getOtPriceRmb());
+        product.setVipPriceRmb(minAttrValue.getVipPriceRmb());
+        product.setPriceRmb(minAttrValue.getPriceRmb());
+        product.setLgnToCny(request.getLgnToCny());
         product.setAuditStatus(ProductConstants.AUDIT_STATUS_EXEMPTION);
         product.setIsAudit(false);
         product.setIsShow(false);
@@ -355,6 +360,11 @@ public class ProductServiceImpl extends ServiceImpl<ProductDao, Product> impleme
             attrValue.setSku(getSku(e.getAttrValue()));
             attrValue.setQuota(0);
             attrValue.setQuotaShow(0);
+            attrValue.setPriceRmb(e.getPriceRmb());
+            attrValue.setCostRmb(e.getCostRmb());
+            attrValue.setOtPriceRmb(e.getOtPriceRmb());
+            attrValue.setVipPriceRmb(e.getVipPriceRmb());
+            attrValue.setLgnToCny(request.getLgnToCny());
             attrValue.setType(product.getType());
             attrValue.setMarketingType(product.getMarketingType());
             attrValue.setImage(systemAttachmentService.clearPrefix(e.getImage(), cdnUrl));
@@ -728,6 +738,11 @@ public class ProductServiceImpl extends ServiceImpl<ProductDao, Product> impleme
         product.setPrice(minAttrValue.getPrice());
         product.setOtPrice(minAttrValue.getOtPrice());
         product.setCost(minAttrValue.getCost());
+        product.setCostRmb(minAttrValue.getCostRmb());
+        product.setOtPriceRmb(minAttrValue.getOtPriceRmb());
+        product.setVipPriceRmb(minAttrValue.getVipPriceRmb());
+        product.setPriceRmb(minAttrValue.getPriceRmb());
+        product.setLgnToCny(productRequest.getLgnToCny());
         if (product.getIsPaidMember()) {
             product.setVipPrice(minAttrValue.getVipPrice());
         }
@@ -766,6 +781,11 @@ public class ProductServiceImpl extends ServiceImpl<ProductDao, Product> impleme
             ProductAttrValue attrValue = new ProductAttrValue();
             BeanUtils.copyProperties(e, attrValue);
             attrValue.setSku(getSku(e.getAttrValue()));
+            attrValue.setPriceRmb(e.getPriceRmb());
+            attrValue.setOtPriceRmb(e.getOtPriceRmb());
+            attrValue.setCostRmb(e.getCostRmb());
+            attrValue.setVipPriceRmb(e.getVipPriceRmb());
+            attrValue.setLgnToCny(productRequest.getLgnToCny());
             attrValue.setImage(systemAttachmentService.clearPrefix(e.getImage(), cdnUrl));
             attrValue.setVersion(0);
             attrValue.setType(product.getType());

+ 98 - 0
crmeb_src/mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ProductTaskServiceImpl.java

@@ -0,0 +1,98 @@
+package com.zbkj.service.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zbkj.common.constants.SysConfigConstants;
+import com.zbkj.common.model.product.Product;
+import com.zbkj.common.model.product.ProductAttrValue;
+import com.zbkj.common.utils.RedisUtil;
+import com.zbkj.service.service.ProductAttrValueService;
+import com.zbkj.service.service.ProductService;
+import com.zbkj.service.service.ProductTaskService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+
+/**
+ * 产品任务服务实现类
+ */
+@Service
+public class ProductTaskServiceImpl implements ProductTaskService {
+
+    private static final Logger logger = LoggerFactory.getLogger(ProductTaskServiceImpl.class);
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Autowired
+    private ProductService productService;
+
+    @Autowired
+    private ProductAttrValueService productAttrValueService;
+
+    /**
+     * 自动根据汇率修改产品各种价格
+     * 逻辑:
+     * price = price_rmb / lgns_to_rmb 向上取整保留2位小数
+     * vip_price = vip_price_rmb / lgns_to_rmb 向上取整保留2位小数
+     * ot_price = ot_price_rmb / lgns_to_rmb 向上取整保留2位小数
+     * cost = cost_rmb / lgns_to_rmb 向上取整保留2位小数
+     */
+    @Override
+    @Transactional
+    public void updateProductPrice() {
+        Object rateObj = redisUtil.get(SysConfigConstants.DAIBI_RATE_LGNS_CNY);
+        if (rateObj == null) {
+            logger.warn("定时任务执行失败:Redis中未找到汇率配置 [{}]", SysConfigConstants.DAIBI_RATE_LGNS_CNY);
+            return;
+        }
+
+        BigDecimal lgnsToRmb = new BigDecimal(rateObj.toString());
+        if (lgnsToRmb.compareTo(BigDecimal.ZERO) <= 0) {
+            logger.warn("定时任务执行失败:汇率必须大于0,当前汇率 [{}]", lgnsToRmb);
+            return;
+        }
+
+        logger.info("开始执行自动根据汇率更新产品价格任务,当前汇率: {}", lgnsToRmb);
+
+        // 1. 更新 eb_product 表
+        List<Product> productList = productService.list(new LambdaQueryWrapper<Product>().eq(Product::getIsDel, false));
+        for (Product product : productList) {
+            product.setPrice(calculatePrice(product.getPriceRmb(), lgnsToRmb));
+            product.setVipPrice(calculatePrice(product.getVipPriceRmb(), lgnsToRmb));
+            product.setOtPrice(calculatePrice(product.getOtPriceRmb(), lgnsToRmb));
+            product.setCost(calculatePrice(product.getCostRmb(), lgnsToRmb));
+        }
+        if (!productList.isEmpty()) {
+            productService.updateBatchById(productList);
+        }
+
+        // 2. 更新 eb_product_attr_value 表
+        List<ProductAttrValue> attrValueList = productAttrValueService
+                .list(new LambdaQueryWrapper<ProductAttrValue>().eq(ProductAttrValue::getIsDel, false));
+        for (ProductAttrValue attrValue : attrValueList) {
+            attrValue.setPrice(calculatePrice(attrValue.getPriceRmb(), lgnsToRmb));
+            attrValue.setVipPrice(calculatePrice(attrValue.getVipPriceRmb(), lgnsToRmb));
+            attrValue.setOtPrice(calculatePrice(attrValue.getOtPriceRmb(), lgnsToRmb));
+            attrValue.setCost(calculatePrice(attrValue.getCostRmb(), lgnsToRmb));
+        }
+        if (!attrValueList.isEmpty()) {
+            productAttrValueService.updateBatchById(attrValueList);
+        }
+
+        logger.info("完成自动根据汇率更新产品价格任务。更新商品数: {}, 更新规格数: {}", productList.size(), attrValueList.size());
+    }
+
+    private BigDecimal calculatePrice(BigDecimal rmbPrice, BigDecimal rate) {
+        if (rmbPrice == null || rmbPrice.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        // 使用 CEILING 向上取整,保留2位小数
+        return rmbPrice.divide(rate, 2, RoundingMode.CEILING);
+    }
+}

+ 10 - 0
crmeb_src/mer_mer_admin/src/api/product.js

@@ -736,3 +736,13 @@ export function productMarketingListApi(params) {
     params,
   });
 }
+
+/**
+ * 获取SL汇率
+ */
+export function getSlRateApi() {
+  return request({
+    url: '/publicly/cache/getSlRate',
+    method: 'get',
+  });
+}

+ 3 - 3
crmeb_src/mer_mer_admin/src/views/product/comment/creatComment.vue

@@ -148,13 +148,13 @@ let attrValue = [
 ];
 const objTitle = {
   price: {
-    title: '售价',
+    title: '售价sL',
   },
   cost: {
-    title: '成本价',
+    title: '成本价sL',
   },
   otPrice: {
-    title: '划线价',
+    title: '划线价sL',
   },
   stock: {
     title: '库存',

+ 151 - 5
crmeb_src/mer_mer_admin/src/views/product/components/creatAttr.vue

@@ -287,7 +287,7 @@
       <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
         <!-- 单规格表格-->
         <el-form-item v-if="formValidate.specType === false">
-          <el-alert title="价格设置范围 0.01~999999.99" type="info"> </el-alert>
+          <el-alert :title="'价格设置范围 0.01~999999.99,sLgns价格根据当前汇率实时换算,当前rmb转slgns汇率:' + lgnToCny" type="info"> </el-alert>
           <el-table :data="OneattrValue" border class="tabNumWidth" size="small">
             <el-table-column label="图片" width="60" align="center">
               <template slot-scope="scope">
@@ -345,12 +345,13 @@
                 <el-input-number
                   v-else
                   v-model.trim="scope.row[iii]"
-                  :disabled="isDisabled || (iii === 'stock' && formValidate.type == 6 ? true : false)"
+                  :disabled="isDisabled || (iii === 'stock' && formValidate.type == 6 ? true : false) || iii === 'price' || iii === 'cost' || iii === 'otPrice' || iii === 'vipPrice'"
                   :min="iii === 'stock' || iii === 'weight' || iii === 'volume' ? 0 : 0.01"
                   :max="formValidate.isPaidMember && iii === 'vipPrice' ? Number(scope.row.price) - 0.01 : 999999.99"
                   :step="iii === 'stock' ? 1 : 0.01"
                   controls-position="right"
                   step-strictly
+                  @change="['priceRmb', 'vipPriceRmb', 'costRmb', 'otPriceRmb'].includes(iii) ? changePrice(scope.row, scope.$index, iii.replace('Rmb', '')) : null"
                 ></el-input-number>
               </template>
             </el-table-column>
@@ -411,7 +412,7 @@
           class="labeltop"
           :class="isDisabled ? 'disLabel' : 'disLabelmoren'"
         >
-          <el-alert title="价格设置范围 0.01~999999.99" type="info"> </el-alert>
+          <el-alert :title="'价格设置范围 0.01~999999.99 sLgns价格根据当前汇率实时换算,当前rmb转slgns汇率:' + lgnToCny" type="info"> </el-alert>
           <el-table
             :data="ManyAttrValue"
             border
@@ -471,6 +472,20 @@
                       controls-position="right"
                       class="priceBox"
                       clearable
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'priceRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="oneFormBatch[0].priceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      :step="0.01"
+                      controls-position="right"
+                      class="priceBox"
+                      clearable
+                      @change="changePrice(oneFormBatch[0], 0, 'price')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'vipPrice' && formValidate.isPaidMember">
@@ -483,6 +498,20 @@
                       controls-position="right"
                       class="priceBox"
                       clearable
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'vipPriceRmb' && formValidate.isPaidMember">
+                    <el-input-number
+                      :controls="false"
+                      v-model="oneFormBatch[0].vipPriceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      :step="0.01"
+                      controls-position="right"
+                      class="priceBox"
+                      clearable
+                      @change="changePrice(oneFormBatch[0], 0, 'vipPrice')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'cost'">
@@ -495,6 +524,20 @@
                       controls-position="right"
                       class="priceBox"
                       clearable
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'costRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="oneFormBatch[0].costRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      :step="0.01"
+                      controls-position="right"
+                      class="priceBox"
+                      clearable
+                      @change="changePrice(oneFormBatch[0], 0, 'cost')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'otPrice'">
@@ -507,6 +550,20 @@
                       controls-position="right"
                       class="priceBox"
                       clearable
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'otPriceRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="oneFormBatch[0].otPriceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      :step="0.01"
+                      controls-position="right"
+                      class="priceBox"
+                      clearable
+                      @change="changePrice(oneFormBatch[0], 0, 'otPrice')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'stock' && formValidate.type !== OrderSecondTypeEnum.Reservation">
@@ -599,6 +656,17 @@
                       :min="0.01"
                       :max="999999.99"
                       class="priceBox"
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'priceRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="ManyAttrValue[scope.$index].priceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      class="priceBox"
+                      @change="changePrice(ManyAttrValue[scope.$index], scope.$index, 'price')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'vipPrice' && formValidate.isPaidMember">
@@ -609,6 +677,18 @@
                       :max="999999.99"
                       class="priceBox"
                       clearable
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'vipPriceRmb' && formValidate.isPaidMember">
+                    <el-input-number
+                      :controls="false"
+                      v-model="ManyAttrValue[scope.$index].vipPriceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      class="priceBox"
+                      clearable
+                      @change="changePrice(ManyAttrValue[scope.$index], scope.$index, 'vipPrice')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'cost'">
@@ -618,6 +698,17 @@
                       :min="0.01"
                       :max="999999.99"
                       class="priceBox"
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'costRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="ManyAttrValue[scope.$index].costRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      class="priceBox"
+                      @change="changePrice(ManyAttrValue[scope.$index], scope.$index, 'cost')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'otPrice'">
@@ -627,6 +718,17 @@
                       :min="0.01"
                       :max="999999.99"
                       class="priceBox"
+                      :disabled="true"
+                    ></el-input-number>
+                  </template>
+                  <template v-else-if="item.slot === 'otPriceRmb'">
+                    <el-input-number
+                      :controls="false"
+                      v-model="ManyAttrValue[scope.$index].otPriceRmb"
+                      :min="0.01"
+                      :max="999999.99"
+                      class="priceBox"
+                      @change="changePrice(ManyAttrValue[scope.$index], scope.$index, 'otPrice')"
                     ></el-input-number>
                   </template>
                   <template v-else-if="item.slot === 'stock' && formValidate.type !== OrderSecondTypeEnum.Reservation">
@@ -792,7 +894,7 @@
 import addCdkey from '@/views/product/components/addCdkey.vue';
 import addCloudDisk from '@/views/product/components/addCloudDisk.vue';
 import vuedraggable from 'vuedraggable';
-import { attrCreatApi, templateListApi } from '@/api/product';
+import { attrCreatApi, templateListApi, getSlRateApi } from '@/api/product';
 import { arraysEqual } from '@/utils';
 import product from '@/mixins/product';
 import { defaultObj } from '../creatProduct/default';
@@ -833,8 +935,10 @@ export default {
       delete obj.attrValueReservationList;
       if (!this.formValidate.isPaidMember) {
         delete obj.vipPrice;
+        delete obj.vipPriceRmb;
       } else {
         obj.vipPrice = Object.assign({}, defaultObj.attrValueList[0]).vipPrice;
+        obj.vipPriceRmb = Object.assign({}, defaultObj.attrValueList[0]).vipPriceRmb;
       }
       if (this.formValidate.type === 2) {
         delete obj.itemNumber;
@@ -860,6 +964,7 @@ export default {
   },
   data() {
     return {
+      lgnToCny:0,
       OrderSecondTypeEnum: OrderSecondTypeEnum,
       carMytabIndex: 0,
       carMytabName: '',
@@ -968,6 +1073,11 @@ export default {
     },
   },
   mounted() {
+    getSlRateApi().then(res => {
+      this.lgnToCny = res.LGNS_TO_CNY
+      // 确保 lgnToCny 字段在提交表单时一同提交。 修改点: 在 creatAttr.vue 组件加载并获取到汇率后,使用 this.$set 将 lgnToCny 写入到 formValidate 对象中。这样在点击保存/提审时,index.vue 组装表单数据会自动包含该字段。
+      this.$set(this.formValidate, 'lgnToCny', res.LGNS_TO_CNY);
+    });
     this.getTimeCheckGroup()
     //预约商品
     if (this.$route.params.id && this.$route.params.id != 0 && this.formValidate.type === 7) {
@@ -1101,7 +1211,27 @@ export default {
       this.carMytabIndex = index;
       this.carMytabName = name;
       this.dialogVisible = true;
+      this.carMytabIndex = index;
+      this.carMytabName = name;
+      this.dialogVisible = true;
     }),
+    /**
+     * 自动计算 sL 价格
+     * @param row 行数据
+     * @param index 行索引
+     * @param type 类型 price, vipPrice, cost, otPrice
+     */
+    changePrice(row, index, type) {
+      if (!this.lgnToCny) return;
+      let rmbKey = type + 'Rmb'; // e.g. priceRmb
+      let rmbVal = row[rmbKey];
+      // 计算: 向上取整(val / rate * 100) / 100
+      let slVal = Math.ceil((rmbVal / this.lgnToCny) * 100) / 100;
+      row[type] = slVal;
+      // 如果是批量设置 (Row index 0 and passed oneFormBatch row?)
+      // Actually row is passed by reference, so modifying it is enough.
+      // But if it's single spec or multi spec, the binding ensures update.
+    },
     // 设置预约库存弹窗生成时间、库存,只在新增中调用, 设置数量跟时间,用一个updateList函数复用批量和单个逻辑。
     updateList(item) {
       const oldList = item.attrValueReservationList || [];
@@ -1370,6 +1500,10 @@ export default {
           vipPrice: 0.01,
           cost: 0.01,
           otPrice: 0.01,
+          priceRmb: 0.01,
+          vipPriceRmb: 0.01,
+          costRmb: 0.01,
+          otPriceRmb: 0.01,
           barCode: '',
           itemNumber: '',
           stock: 0,
@@ -1413,7 +1547,15 @@ export default {
                 cdkeyId: manyItem.cdkeyId || '',
                 cdkey: manyItem.cdkey || {},
                 expand: manyItem.expand || '',
-                cdkeyLibraryName: manyItem.cdkeyLibraryName || ''
+                attrValueReservationList: manyItem.attrValueReservationList || [],
+                cdkeyId: manyItem.cdkeyId || '',
+                cdkey: manyItem.cdkey || {},
+                expand: manyItem.expand || '',
+                cdkeyLibraryName: manyItem.cdkeyLibraryName || '',
+                priceRmb: manyItem.priceRmb || 0.01,
+                vipPriceRmb: manyItem.vipPriceRmb || 0.01,
+                costRmb: manyItem.costRmb || 0.01,
+                otPriceRmb: manyItem.otPriceRmb || 0.01,
               });
             } else if (k > 0 && manyItem.attr_arr.length && data[i].add_pic && combination.includes(val)) {
               // data[i].detail中的value是规格值 存在与 manyItem.attr_arr 中的某一项
@@ -1817,8 +1959,11 @@ export default {
     batchData(val) {
       if (this.oneFormBatch[0].image) this.$set(val, 'image', this.oneFormBatch[0].image);
       if (this.oneFormBatch[0].price > 0) this.$set(val, 'price', this.oneFormBatch[0].price);
+      if (this.oneFormBatch[0].priceRmb > 0) this.$set(val, 'priceRmb', this.oneFormBatch[0].priceRmb);
       if (this.oneFormBatch[0].cost > 0) this.$set(val, 'cost', this.oneFormBatch[0].cost);
+      if (this.oneFormBatch[0].costRmb > 0) this.$set(val, 'costRmb', this.oneFormBatch[0].costRmb);
       if (this.oneFormBatch[0].otPrice > 0) this.$set(val, 'otPrice', this.oneFormBatch[0].otPrice);
+      if (this.oneFormBatch[0].otPriceRmb > 0) this.$set(val, 'otPriceRmb', this.oneFormBatch[0].otPriceRmb);
       if (this.oneFormBatch[0].barCode) this.$set(val, 'barCode', this.oneFormBatch[0].barCode);
       if (this.oneFormBatch[0].stock >= 0) this.$set(val, 'stock', this.oneFormBatch[0].stock);
       if (this.oneFormBatch[0].weight >= 0) this.$set(val, 'weight', this.oneFormBatch[0].weight);
@@ -1826,6 +1971,7 @@ export default {
       if (this.oneFormBatch[0].brokerage > 0) this.$set(val, 'brokerage', this.oneFormBatch[0].brokerage);
       if (this.oneFormBatch[0].brokerageTwo > 0) this.$set(val, 'brokerageTwo', this.oneFormBatch[0].brokerageTwo);
       if (this.oneFormBatch[0].vipPrice > 0) this.$set(val, 'vipPrice', this.oneFormBatch[0].vipPrice);
+      if (this.oneFormBatch[0].vipPriceRmb > 0) this.$set(val, 'vipPriceRmb', this.oneFormBatch[0].vipPriceRmb);
       if (this.oneFormBatch[0].itemNumber) this.$set(val, 'itemNumber', this.oneFormBatch[0].itemNumber);
     },
     // 添加按钮

+ 4 - 4
crmeb_src/mer_mer_admin/src/views/product/components/storeEdit.vue

@@ -161,16 +161,16 @@ const defaultObj = {
 };
 const objTitle = {
   price: {
-    title: '售价',
+    title: '售价sL',
   },
   cost: {
-    title: '成本价',
+    title: '成本价sL',
   },
   otPrice: {
-    title: '划线价',
+    title: '划线价sL',
   },
   vipPrice: {
-    title: '会员价',
+    title: '会员价sL',
   },
   stock: {
     title: '库存',

+ 114 - 16
crmeb_src/mer_mer_admin/src/views/product/creatProduct/TableHeadList.js

@@ -1,19 +1,37 @@
 // 导出TableHead 数据
 export const GoodsTableHead = [
   {
-    title: '售价',
+    title: '售价¥',
+    slot: 'priceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '售价sL',
     slot: 'price',
     align: 'center',
     minWidth: '100px',
   },
   {
-    title: '成本价',
+    title: '成本价¥',
+    slot: 'costRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '成本价sL',
     slot: 'cost',
     align: 'center',
     minWidth: 120,
   },
   {
-    title: '划线价',
+    title: '划线价¥',
+    slot: 'otPriceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '划线价sL',
     slot: 'otPrice',
     align: 'center',
     minWidth: '100px',
@@ -93,7 +111,13 @@ export const imageTableHead = [
 // 会员价
 export const vipPriceTableHead = [
   {
-    title: '会员价',
+    title: '会员价¥',
+    slot: 'vipPriceRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '会员价sL',
     slot: 'vipPrice',
     align: 'center',
     minWidth: 120,
@@ -103,19 +127,37 @@ export const vipPriceTableHead = [
 // 云盘
 export const VirtualTableHead = [
   {
-    title: '售价',
+    title: '售价¥',
+    slot: 'priceRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '售价sL',
     slot: 'price',
     align: 'center',
     minWidth: 120,
   },
   {
-    title: '成本价',
+    title: '成本价¥',
+    slot: 'costRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '成本价sL',
     slot: 'cost',
     align: 'center',
     minWidth: 120,
   },
   {
-    title: '划线价',
+    title: '划线价¥',
+    slot: 'otPriceRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '划线价sL',
     slot: 'otPrice',
     align: 'center',
     minWidth: 120,
@@ -156,19 +198,37 @@ export const VirtualTableHead = [
 //   卡密设置
 export const VirtualTableHead2 = [
   {
-    title: '售价',
+    title: '售价¥',
+    slot: 'priceRmb',
+    align: 'center',
+    minWidth: 100,
+  },
+  {
+    title: '售价sL',
     slot: 'price',
     align: 'center',
     minWidth: 100,
   },
   {
-    title: '成本价',
+    title: '成本价¥',
+    slot: 'costRmb',
+    align: 'center',
+    minWidth: 100,
+  },
+  {
+    title: '成本价sL',
     slot: 'cost',
     align: 'center',
     minWidth: 100,
   },
   {
-    title: '划线价',
+    title: '划线价¥',
+    slot: 'otPriceRmb',
+    align: 'center',
+    minWidth: 100,
+  },
+  {
+    title: '划线价sL',
     slot: 'otPrice',
     align: 'center',
     minWidth: 100,
@@ -210,19 +270,38 @@ export const VirtualTableHead2 = [
 //虚拟商品
 export const FictitiousTableHead = [
   {
-    title: '售价',
+
+    title: '售价¥',
+    slot: 'priceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '售价sL',
     slot: 'price',
     align: 'center',
     minWidth: '100px',
   },
   {
-    title: '成本价',
+    title: '成本价¥',
+    slot: 'costRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '成本价sL',
     slot: 'cost',
     align: 'center',
     minWidth: 120,
   },
   {
-    title: '划线价',
+    title: '划线价¥',
+    slot: 'otPriceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '划线价sL',
     slot: 'otPrice',
     align: 'center',
     minWidth: '100px',
@@ -270,19 +349,38 @@ export const FictitiousTableHead = [
 // 预约商品
 export const reservationTableHeard = [
   {
-    title: '售价',
+
+    title: '售价¥',
+    slot: 'priceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '售价sL',
     slot: 'price',
     align: 'center',
     minWidth: '100px',
   },
   {
-    title: '成本价',
+    title: '成本价¥',
+    slot: 'costRmb',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    title: '成本价sL',
     slot: 'cost',
     align: 'center',
     minWidth: 120,
   },
   {
-    title: '划线价',
+    title: '划线价¥',
+    slot: 'otPriceRmb',
+    align: 'center',
+    minWidth: '100px',
+  },
+  {
+    title: '划线价sL',
     slot: 'otPrice',
     align: 'center',
     minWidth: '100px',

+ 20 - 4
crmeb_src/mer_mer_admin/src/views/product/creatProduct/default.js

@@ -18,9 +18,13 @@ export const defaultObj = {
       brokerage: 0,
       brokerageTwo: 0,
       price: 0.01,
+      priceRmb: 0.01,
       vipPrice: 0.01,
+      vipPriceRmb: 0.01,
       cost: 0.01,
+      costRmb: 0.01,
       otPrice: 0.01,
+      otPriceRmb: 0.01,
       stock: 0,
       barCode: '',
       itemNumber: '',
@@ -85,16 +89,28 @@ export const defaultObj = {
 };
 export const objTitle = {
   price: {
-    title: '售价',
+    title: '售价sL',
+  },
+  priceRmb: {
+    title: '售价¥',
   },
   vipPrice: {
-    title: '会员价',
+    title: '会员价sL',
+  },
+  vipPriceRmb: {
+    title: '会员价¥',
   },
   cost: {
-    title: '成本价',
+    title: '成本价sL',
+  },
+  costRmb: {
+    title: '成本价¥',
   },
   otPrice: {
-    title: '划线价',
+    title: '划线价sL',
+  },
+  otPriceRmb: {
+    title: '划线价¥',
   },
   stock: {
     title: '库存',

+ 21 - 0
crmeb_src/mer_mer_admin/src/views/product/creatProduct/index.vue

@@ -1396,6 +1396,27 @@ export default {
         this.currentTab = '2';
         return this.$message.warning('请完整添加规格图片');
       }
+
+      // RMB Price Validation
+      let priceVerifyList = [];
+      if (this.formValidate.specType) {
+        let manyList = [...this.ManyAttrValue];
+        manyList.shift(); // Remove batch setting row
+        priceVerifyList = manyList;
+      } else {
+        priceVerifyList = this.OneattrValue;
+      }
+
+      for (let i = 0; i < priceVerifyList.length; i++) {
+        let item = priceVerifyList[i];
+        if (Number(item.priceRmb) <= 0) return this.$message.warning('售价¥必须大于0');
+        if (Number(item.costRmb) <= 0) return this.$message.warning('成本价¥必须大于0');
+        if (Number(item.otPriceRmb) <= 0) return this.$message.warning('划线价¥必须大于0');
+        if (this.formValidate.isPaidMember && Number(item.vipPriceRmb) <= 0) {
+          return this.$message.warning('会员价¥必须大于0');
+        }
+      }
+
       this.loadingBtn = true;
       let data = this.getFromData();
       parseFloat(this.$route.params.id) > 0

+ 2 - 1
crmeb_src/mer_mer_admin/src/views/product/index.vue

@@ -224,7 +224,8 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column prop="price" label="商品售价" min-width="90" v-if="checkedCities.includes('商品售价')" />
+        <el-table-column prop="price" label="商品售价(sL)" min-width="90" v-if="checkedCities.includes('商品售价')" />
+        <el-table-column prop="priceRmb" label="商品售价(¥)" min-width="90" v-if="checkedCities.includes('商品售价')" />
         <el-table-column prop="sales" label="销量" min-width="90" v-if="checkedCities.includes('销量')" />
         <el-table-column prop="stock" label="库存" min-width="90" v-if="checkedCities.includes('库存')" />
         <el-table-column label="失败原因" min-width="150" v-if="tableFrom.type === '7'" :show-overflow-tooltip="true">