7 hónapja
szülő
commit
149fa65706
24 módosított fájl, 1046 hozzáadás és 297 törlés
  1. 118 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdAttrController.java
  2. 41 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdAttrJointController.java
  3. 0 16
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdController.java
  4. 71 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdTagController.java
  5. 26 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/domain/ProdAttrJointVo.java
  6. 11 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/domain/ProdAttrVo.java
  7. 24 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/mapper/ProdAttrJointVoMapper.java
  8. 16 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/mapper/ProdAttrVoMapper.java
  9. 21 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/IProdAttrJointVoService.java
  10. 40 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/IProdAttrVoService.java
  11. 34 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/impl/ProdAttrJointVoServiceImpl.java
  12. 120 0
      08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/impl/ProdAttrVoServiceImpl.java
  13. 1 1
      08.src/Xingxi/xingxi-admin/src/main/resources/application-local.yml
  14. 43 0
      08.src/Xingxi/xingxi-admin/src/main/resources/mapper/ProdAttrJointVoMapper.xml
  15. 56 42
      08.src/Xingxi/xingxi-admin/src/main/resources/mapper/ProdAttrVoMapper.xml
  16. 1 4
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/add.html
  17. 0 141
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/editAttr.html
  18. 5 5
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/prod.html
  19. 123 26
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/add.html
  20. 156 10
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/edit.html
  21. 106 52
      08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/prodAttr.html
  22. 30 0
      08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EAttrType.java
  23. 2 0
      08.src/Xingxi/xingxi-system/src/main/java/com/xingxi/master/product/service/impl/ProdAttrJointServiceImpl.java
  24. 1 0
      08.src/Xingxi/xingxi-system/src/main/resources/mapper/master/ProdAttrMapper.xml

+ 118 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdAttrController.java

@@ -0,0 +1,118 @@
+package com.xingxi.web.controller.master.product.controller;
+
+import com.xingxi.common.annotation.Log;
+import com.xingxi.common.core.controller.BaseController;
+import com.xingxi.common.core.domain.AjaxResult;
+import com.xingxi.common.core.page.TableDataInfo;
+import com.xingxi.common.enums.BusinessType;
+import com.xingxi.web.controller.master.product.domain.ProdAttrVo;
+import com.xingxi.web.controller.master.product.service.IProdAttrVoService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 商品属性Controller
+ *
+ * @author ruoyi
+ * @date 2025-03-09
+ */
+@Controller
+@RequestMapping("/master/product/prodAttr")
+public class ProdAttrController extends BaseController {
+    private final String prefix = "master/product/prodAttr";
+
+    @Resource
+    private IProdAttrVoService prodAttrVoService;
+
+    @RequiresPermissions("master:product:prod:viewAttrs")
+    @GetMapping("/{id}")
+    public String prodAttr(@PathVariable("id") Long id, ModelMap mMap) {
+        mMap.put("prodId", id);
+        return prefix + "/prodAttr";
+    }
+
+    /**
+     * 查询商品属性列表
+     */
+    @RequiresPermissions("master:product:list")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(ProdAttrVo prodAttrVo) {
+        startPage();
+        List<ProdAttrVo> list = prodAttrVoService.selectProdAttrVoList(prodAttrVo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询商品属性列表
+     */
+    @RequiresPermissions("master:product:list")
+    @PostMapping("/jointList")
+    @ResponseBody
+    public TableDataInfo jointList(ProdAttrVo prodAttrVo) {
+        startPage();
+        List<ProdAttrVo> list = prodAttrVoService.selectProdAttrJointList(prodAttrVo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 新增商品属性
+     */
+    @RequiresPermissions("master:product:addAttr")
+    @GetMapping("/add/{id}")
+    public String add(@PathVariable("id") Long id, ModelMap mMap) {
+        mMap.put("prodId", id);
+        return prefix + "/add";
+    }
+
+    /**
+     * 修改商品属性
+     */
+    @RequiresPermissions("master:product:editAttr")
+    @GetMapping("/edit/{id}")
+    public String edit(@PathVariable("id") Long prodAttrId, ModelMap mMap) {
+        ProdAttrVo prodAttrVo = prodAttrVoService.selectProdAttrVoByProdAttrId(prodAttrId);
+        mMap.put("prodId", prodAttrVo.getProdId());
+        mMap.put("prodAttrId", prodAttrId);
+        mMap.put("prodAttrVo", prodAttrVo);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 添加商品属性
+     */
+    @RequiresPermissions("master:product:addAttr")
+    @Log(title = "商品属性", businessType = BusinessType.INSERT)
+    @PostMapping("/addAttr")
+    @ResponseBody
+    public AjaxResult addProdAttr(@RequestBody ProdAttrVo prodAttrVo) {
+        return toAjax(prodAttrVoService.addProdAttr(prodAttrVo));
+    }
+
+    /**
+     * 修改商品属性
+     */
+    @RequiresPermissions("master:product:editAttr")
+    @Log(title = "商品属性", businessType = BusinessType.UPDATE)
+    @PostMapping("/editAttr")
+    @ResponseBody
+    public AjaxResult editAttr(@RequestBody ProdAttrVo prodAttrVo) {
+        return toAjax(prodAttrVoService.updateProdAttr(prodAttrVo));
+    }
+
+    /**
+     * 删除商品属性
+     */
+    @RequiresPermissions("master:product:tag:remove")
+    @Log(title = "商品属性", businessType = BusinessType.DELETE)
+    @PostMapping("/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids) {
+        return toAjax(prodAttrVoService.logicDeleteProdAttrByCondition(Long.parseLong(ids)));
+    }
+}

+ 41 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdAttrJointController.java

@@ -0,0 +1,41 @@
+package com.xingxi.web.controller.master.product.controller;
+
+import com.xingxi.common.core.controller.BaseController;
+import com.xingxi.common.core.page.TableDataInfo;
+import com.xingxi.web.controller.master.product.domain.ProdAttrJointVo;
+import com.xingxi.web.controller.master.product.service.IProdAttrJointVoService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 商品属性组合Controller
+ *
+ * @author ruoyi
+ * @date 2025-03-09
+ */
+@Controller
+@RequestMapping("/master/product/prodAttrJoint")
+public class ProdAttrJointController extends BaseController {
+    private final String prefix = "/master/product/attr/joint";
+
+    @Resource
+    private IProdAttrJointVoService prodAttrJointVoService;
+
+    /**
+     * 查询商品属性组合列表
+     */
+    @RequiresPermissions("master:product:attr:joint:list")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(ProdAttrJointVo prodAttrJointVo) {
+        startPage();
+        List<ProdAttrJointVo> list = prodAttrJointVoService.selectProdAttrJointVoList(prodAttrJointVo);
+        return getDataTable(list);
+    }
+}

+ 0 - 16
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdController.java

@@ -8,7 +8,6 @@ import com.xingxi.common.enums.BusinessType;
 import com.xingxi.common.enums.EProdStatus;
 import com.xingxi.common.utils.poi.ExcelUtil;
 import com.xingxi.master.product.domain.Prod;
-import com.xingxi.web.controller.master.product.domain.ProdAttrVo;
 import com.xingxi.web.controller.master.product.domain.ProdVo;
 import com.xingxi.web.controller.master.product.service.IProdAttrVoService;
 import com.xingxi.web.controller.master.product.service.IProdVoService;
@@ -33,8 +32,6 @@ public class ProdController extends BaseController {
 
     @Resource
     private IProdVoService prodVoService;
-    @Resource
-    private IProdAttrVoService prodAttrVoService;
 
     @RequiresPermissions("master:product:view")
     @GetMapping()
@@ -140,17 +137,4 @@ public class ProdController extends BaseController {
         prod.setProdStatus(EProdStatus.REJECTED.getVal());
         return toAjax(prodVoService.updateProd(prod));
     }
-
-    /**
-     * 修改商品属性
-     */
-    @RequiresPermissions("master:product:editAttr")
-    @GetMapping("/editAttr/{id}")
-    public String editAttr(@PathVariable("id") Long id, ModelMap mMap) {
-        ProdAttrVo cond = new ProdAttrVo();
-        cond.setProdId(id);
-        List<ProdAttrVo> prodAttrVo = prodAttrVoService.selectProdAttrVoList(cond);
-        mMap.put("prodAttrVo", prodAttrVo);
-        return prefix + "/editAttr";
-    }
 }

+ 71 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/controller/ProdTagController.java

@@ -0,0 +1,71 @@
+package com.xingxi.web.controller.master.product.controller;
+
+import com.xingxi.common.annotation.Log;
+import com.xingxi.common.core.controller.BaseController;
+import com.xingxi.common.core.domain.AjaxResult;
+import com.xingxi.common.enums.BusinessType;
+import com.xingxi.web.controller.master.product.domain.ProdTagVo;
+import com.xingxi.web.controller.master.product.service.IProdTagVoService;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 商品标签Controller
+ *
+ * @author ruoyi
+ * @date 2025-03-09
+ */
+@Controller
+@RequestMapping("/master/product/prodTag")
+public class ProdTagController extends BaseController {
+    private final String prefix = "master/product/prodTag";
+
+    @Resource
+    private IProdTagVoService prodTagVoService;
+
+    /**
+     * 修改商品标签
+     */
+    @RequiresPermissions("master:product:editTag")
+    @GetMapping("/editTag/{id}")
+    public String editTag(@PathVariable("id") Long id, ModelMap mMap) {
+        ProdTagVo cond = new ProdTagVo();
+        cond.setProdId(id);
+        List<ProdTagVo> prodTagVoList = new ArrayList<>();
+        List<ProdTagVo> resultList = prodTagVoService.selectProdTagVoList(cond);
+        if (resultList != null && resultList.size() > 0) {
+            prodTagVoList = resultList;
+        }
+        mMap.put("prodId", id);
+        mMap.put("prodTagVoList", prodTagVoList);
+        return prefix + "/editTag";
+    }
+
+    /**
+     * 添加商品标签
+     */
+    @RequiresPermissions("master:product:addTag")
+    @Log(title = "商品标签", businessType = BusinessType.INSERT)
+    @PostMapping("/addTags")
+    @ResponseBody
+    public AjaxResult addProdTags(ProdTagVo prodTagVo) {
+        return toAjax(prodTagVoService.addProdTags(prodTagVo));
+    }
+
+    /**
+     * 删除商品标签
+     */
+    @RequiresPermissions("master:product:tag:remove")
+    @Log(title = "商品标签", businessType = BusinessType.DELETE)
+    @PostMapping("/remove")
+    @ResponseBody
+    public AjaxResult remove(ProdTagVo prodTagVo) {
+        return toAjax(prodTagVoService.logicDeleteProdTagByCondition(prodTagVo));
+    }
+}

+ 26 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/domain/ProdAttrJointVo.java

@@ -0,0 +1,26 @@
+package com.xingxi.web.controller.master.product.domain;
+
+import com.xingxi.master.product.domain.ProdAttr;
+import com.xingxi.master.product.domain.ProdAttrJoint;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+/**
+ * 商品属性对象 m_prod_attr
+ *
+ * @author xingxi
+ * @date 2025-03-06
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString
+public class ProdAttrJointVo extends ProdAttr {
+    private static final long serialVersionUID = 1L;
+    //检索用商品属性标签名称
+    private String prodAttrName;
+    //选中的商品属性集合
+    private List<ProdAttrJoint> prodAttrJoints;
+}

+ 11 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/domain/ProdAttrVo.java

@@ -1,10 +1,13 @@
 package com.xingxi.web.controller.master.product.domain;
 
 import com.xingxi.master.product.domain.ProdAttr;
+import com.xingxi.master.product.domain.ProdAttrJoint;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import java.util.List;
+
 /**
  * 商品属性对象 m_prod_attr
  *
@@ -16,4 +19,12 @@ import lombok.ToString;
 @ToString
 public class ProdAttrVo extends ProdAttr {
     private static final long serialVersionUID = 1L;
+    // 检索用商品属性标签名称
+    private String prodAttrName;
+    // 选中的商品属性集合
+    private List<ProdAttrJoint> prodAttrJoints;
+    // 数据库同名ID处理
+    private Long jointId;
+    // 属性组和ID
+    private Long prodAttrJointId;
 }

+ 24 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/mapper/ProdAttrJointVoMapper.java

@@ -0,0 +1,24 @@
+package com.xingxi.web.controller.master.product.mapper;
+
+import com.xingxi.master.product.mapper.ProdAttrJointMapper;
+import com.xingxi.web.controller.master.product.domain.ProdAttrJointVo;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 商品属性组合Mapper接口
+ *
+ * @author xingxi
+ * @date 2025-03-06
+ */
+@Repository
+public interface ProdAttrJointVoMapper extends ProdAttrJointMapper {
+    /**
+     * 查询商品属性组合 列表
+     *
+     * @param prodAttrJointVo 商品属性组合
+     * @return 商品属性组合 列表
+     */
+    List<ProdAttrJointVo> selectProdAttrJointVoList(ProdAttrJointVo prodAttrJointVo);
+}

+ 16 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/mapper/ProdAttrVoMapper.java

@@ -15,10 +15,26 @@ import java.util.List;
 @Repository
 public interface ProdAttrVoMapper extends ProdAttrMapper {
     /**
+     * 查询商品属性VO
+     *
+     * @param prodAttrId 商品属性ID
+     * @return 商品属性VO
+     */
+    ProdAttrVo selectProdAttrVoByProdAttrId(Long prodAttrId);
+
+    /**
      * 查询商品属性列表
      *
      * @param prodAttrVo 商品属性
      * @return 商品属性集合
      */
     List<ProdAttrVo> selectProdAttrVoList(ProdAttrVo prodAttrVo);
+
+    /**
+     * 查询商品属性组合列表
+     *
+     * @param prodAttrVo 商品属性
+     * @return 商品属性组合集合
+     */
+    List<ProdAttrVo> selectProdAttrJointList(ProdAttrVo prodAttrVo);
 }

+ 21 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/IProdAttrJointVoService.java

@@ -0,0 +1,21 @@
+package com.xingxi.web.controller.master.product.service;
+
+import com.xingxi.web.controller.master.product.domain.ProdAttrJointVo;
+
+import java.util.List;
+
+/**
+ * 商品属性Service接口
+ *
+ * @author xingxi
+ * @date 2025-03-06
+ */
+public interface IProdAttrJointVoService {
+    /**
+     * 查询商品属性列表
+     *
+     * @param prodAttrJointVo 商品属性Vo
+     * @return 商品属性集合
+     */
+    List<ProdAttrJointVo> selectProdAttrJointVoList(ProdAttrJointVo prodAttrJointVo);
+}

+ 40 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/IProdAttrVoService.java

@@ -12,10 +12,50 @@ import java.util.List;
  */
 public interface IProdAttrVoService {
     /**
+     * 查询商品属性VO
+     *
+     * @param prodAttrId 商品属性ID
+     * @return 商品属性VO
+     */
+    ProdAttrVo selectProdAttrVoByProdAttrId(Long prodAttrId);
+
+    /**
      * 查询商品属性列表
      *
      * @param prodAttrVo 商品属性Vo
      * @return 商品属性集合
      */
     List<ProdAttrVo> selectProdAttrVoList(ProdAttrVo prodAttrVo);
+
+    /**
+     * 查询商品属性组合列表
+     *
+     * @param prodAttrVo 商品属性Vo
+     * @return 商品属性组合集合
+     */
+    List<ProdAttrVo> selectProdAttrJointList(ProdAttrVo prodAttrVo);
+
+    /**
+     * 添加商品属性
+     *
+     * @param prodAttrVo 商品属性Vo
+     * @return 影响行数
+     */
+    int addProdAttr(ProdAttrVo prodAttrVo);
+
+    /**
+     * 添加商品属性
+     *
+     * @param prodAttrVo 商品属性Vo
+     * @return 影响行数
+     */
+    int updateProdAttr(ProdAttrVo prodAttrVo);
+
+    /**
+     * 删除商品属性
+     *
+     * @param prodAttrId 商品属性ID
+     * @return 影响行数
+     */
+    int logicDeleteProdAttrByCondition(Long prodAttrId);
 }

+ 34 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/impl/ProdAttrJointVoServiceImpl.java

@@ -0,0 +1,34 @@
+package com.xingxi.web.controller.master.product.service.impl;
+
+import com.xingxi.common.enums.EDelFlag;
+import com.xingxi.web.controller.master.product.domain.ProdAttrJointVo;
+import com.xingxi.web.controller.master.product.mapper.ProdAttrJointVoMapper;
+import com.xingxi.web.controller.master.product.service.IProdAttrJointVoService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 商品属性Service业务层处理
+ *
+ * @author xingxi
+ * @date 2025-03-06
+ */
+@Service
+public  class ProdAttrJointVoServiceImpl implements IProdAttrJointVoService {
+    @Resource
+    private ProdAttrJointVoMapper prodAttrJointVoMapper;
+
+    /**
+     * 查询商品属性列表
+     *
+     * @param prodAttrJointVo 商品属性
+     * @return 商品属性
+     */
+    @Override
+    public List<ProdAttrJointVo> selectProdAttrJointVoList(ProdAttrJointVo prodAttrJointVo) {
+        prodAttrJointVo.setDelFlag(EDelFlag.NO.getVal());
+        return prodAttrJointVoMapper.selectProdAttrJointVoList(prodAttrJointVo);
+    }
+}

+ 120 - 0
08.src/Xingxi/xingxi-admin/src/main/java/com/xingxi/web/controller/master/product/service/impl/ProdAttrVoServiceImpl.java

@@ -1,11 +1,19 @@
 package com.xingxi.web.controller.master.product.service.impl;
 
+import com.xingxi.common.enums.EAttrType;
+import com.xingxi.common.enums.EDelFlag;
+import com.xingxi.common.exception.BusinessException;
+import com.xingxi.common.utils.DateUtils;
+import com.xingxi.common.utils.ShiroUtils;
+import com.xingxi.master.product.domain.ProdAttrJoint;
+import com.xingxi.master.product.mapper.ProdAttrJointMapper;
 import com.xingxi.web.controller.master.product.domain.ProdAttrVo;
 import com.xingxi.web.controller.master.product.mapper.ProdAttrVoMapper;
 import com.xingxi.web.controller.master.product.service.IProdAttrVoService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -18,6 +26,19 @@ import java.util.List;
 public  class ProdAttrVoServiceImpl implements IProdAttrVoService {
     @Resource
     private ProdAttrVoMapper prodAttrVoMapper;
+    @Resource
+    private ProdAttrJointMapper prodAttrJointMapper;
+
+    /**
+     * 查询商品属性VO
+     *
+     * @param prodAttrId 商品属性ID
+     * @return 商品属性VO
+     */
+    @Override
+    public ProdAttrVo selectProdAttrVoByProdAttrId(Long prodAttrId) {
+        return prodAttrVoMapper.selectProdAttrVoByProdAttrId(prodAttrId);
+    }
 
     /**
      * 查询商品属性列表
@@ -27,6 +48,105 @@ public  class ProdAttrVoServiceImpl implements IProdAttrVoService {
      */
     @Override
     public List<ProdAttrVo> selectProdAttrVoList(ProdAttrVo prodAttrVo) {
+        prodAttrVo.setDelFlag(EDelFlag.NO.getVal());
         return prodAttrVoMapper.selectProdAttrVoList(prodAttrVo);
     }
+
+    /**
+     * 查询商品属性列表
+     *
+     * @param prodAttrVo 商品属性
+     * @return 商品属性
+     */
+    @Override
+    public List<ProdAttrVo> selectProdAttrJointList(ProdAttrVo prodAttrVo) {
+        prodAttrVo.setDelFlag(EDelFlag.NO.getVal());
+        return prodAttrVoMapper.selectProdAttrJointList(prodAttrVo);
+    }
+
+    /**
+     * 添加商品属性
+     *
+     * @param prodAttrVo 商品属性Vo
+     * @return 影响行数
+     */
+    @Override
+    public int addProdAttr(ProdAttrVo prodAttrVo) {
+        prodAttrVo.setDelFlag(EDelFlag.NO.getVal());
+        prodAttrVo.setCreateUser(ShiroUtils.getLoginName());
+        prodAttrVo.setCreateTime(DateUtils.getNowDate());
+        int effectRows = prodAttrVoMapper.insertProdAttr(prodAttrVo);
+        if (effectRows == 0) {
+            throw new BusinessException("新建商品属性时发生错误!");
+        }
+
+        if (EAttrType.JOINT.getVal().equals(prodAttrVo.getAttrType())) {
+            for (ProdAttrJoint prodAttrJoint : prodAttrVo.getProdAttrJoints()) {
+                prodAttrJoint.setProdAttrId(prodAttrVo.getProdAttrId());
+                prodAttrJoint.setDelFlag(EDelFlag.NO.getVal());
+                prodAttrJoint.setCreateUser(ShiroUtils.getLoginName());
+                prodAttrJoint.setCreateTime(DateUtils.getNowDate());
+            }
+            effectRows = prodAttrJointMapper.batchInsertProdAttrJoint(prodAttrVo.getProdAttrJoints());
+        }
+        return effectRows;
+    }
+
+    /**
+     * 修改商品属性
+     *
+     * @param prodAttrVo 商品属性Vo
+     * @return 影响行数
+     */
+    @Override
+    public int updateProdAttr(ProdAttrVo prodAttrVo) {
+        prodAttrVo.setUpdateUser(ShiroUtils.getLoginName());
+        prodAttrVo.setUpdateTime(DateUtils.getNowDate());
+        int effectRows = prodAttrVoMapper.updateProdAttr(prodAttrVo);
+        if (effectRows == 0) {
+            throw new BusinessException("修改商品属性时发生错误!");
+        }
+
+        if (EAttrType.JOINT.getVal().equals(prodAttrVo.getAttrType())) {
+            List<String> ids = new ArrayList<>();
+            for (ProdAttrJoint prodAttrJoint : prodAttrVo.getProdAttrJoints()) {
+                prodAttrJoint.setProdAttrId(prodAttrVo.getProdAttrId());
+                prodAttrJoint.setDelFlag(EDelFlag.NO.getVal());
+                prodAttrJoint.setCreateUser(ShiroUtils.getLoginName());
+                prodAttrJoint.setCreateTime(DateUtils.getNowDate());
+                if (prodAttrJoint.getProdAttrJointId() != null) {
+                    ids.add(prodAttrJoint.getProdAttrJointId().toString());
+                }
+            }
+            effectRows = prodAttrJointMapper.deleteProdAttrJointByProdAttrJointIds(ids.toArray(new String[0]));
+            effectRows = prodAttrJointMapper.batchInsertProdAttrJoint(prodAttrVo.getProdAttrJoints());
+        }
+        return effectRows;
+    }
+
+    /**
+     * 删除商品属性
+     *
+     * @param prodAttrId 商品属性ID
+     * @return 影响行数
+     */
+    @Override
+    public int logicDeleteProdAttrByCondition(Long prodAttrId) {
+        ProdAttrVo checkProdAttr = prodAttrVoMapper.selectProdAttrVoByProdAttrId(prodAttrId);
+        // 如果是属性需要检查是否有商品组合在使用
+        if (EAttrType.ATTR.getVal().equals(checkProdAttr.getAttrType())) {
+            ProdAttrJoint cond = new ProdAttrJoint();
+            cond.setProdAttrId(prodAttrId);
+            cond.setProdId(checkProdAttr.getProdId());
+            cond.setJointProdAttrId(checkProdAttr.getProdAttrId());
+            cond.setDelFlag(EDelFlag.NO.getVal());
+            List<ProdAttrJoint> checkResultList = prodAttrJointMapper.selectProdAttrJointList(cond);
+            if (checkResultList.size() > 0) {
+                throw new BusinessException("商品属性使用中,不能删除!");
+            }
+        }
+        ProdAttrVo prodAttrVo = new ProdAttrVo();
+        prodAttrVo.setProdAttrId(prodAttrId);
+        return prodAttrVoMapper.logicDeleteProdAttrByCondition(prodAttrVo);
+    }
 }

+ 1 - 1
08.src/Xingxi/xingxi-admin/src/main/resources/application-local.yml

@@ -72,7 +72,7 @@ spring:
         host: redis.njnet.vip
         port: 6379
         password: Biandan123
-        timeout: 6000ms           # 连接超时时长(毫秒)
+        timeout: 10000ms           # 连接超时时长(毫秒)
         lettuce:
             pool:
                 max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)

+ 43 - 0
08.src/Xingxi/xingxi-admin/src/main/resources/mapper/ProdAttrJointVoMapper.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xingxi.web.controller.master.product.mapper.ProdAttrJointVoMapper">
+    <resultMap type="ProdAttrJointVo" id="ProdAttrJointVoResult">
+        <result property="prodAttrId"           column="prodAttrId" />
+        <result property="prodId"               column="prodId"     />
+        <result property="attrName"             column="attrName"   />
+        <result property="attrType"             column="attrType"   />
+        <result property="delFlag"              column="delFlag"    />
+        <result property="createTime"           column="createTime" />
+        <result property="createUser"           column="createUser" />
+        <result property="updateUser"           column="updateUser" />
+        <result property="updateTime"           column="updateTime" />
+        <result property="attrName"             column="attrName"   />
+        <result property="attrType"             column="attrType"   />
+    </resultMap>
+
+    <sql id="selectProdAttrJointVo">
+        select m_prod_attr_joint.prodAttrJointId
+             , m_prod_attr_joint.prodId
+             , m_prod_attr_joint.prodAttrId
+             , m_prod_attr_joint.jointProdId
+             , m_prod_attr_joint.jointProdAttrId
+             , m_prod_attr_joint.delFlag
+             , m_prod_attr_joint.createUser
+             , m_prod_attr_joint.createTime
+             , m_prod_attr_joint.updateUser
+             , m_prod_attr_joint.updateTime
+             , m_prod_attr.attrName
+             , m_prod_attr.attrType
+        from m_prod_attr_joint
+        inner join m_prod_attr on m_prod_attr.prodId = m_prod_attr_joint.prodId and m_prod_attr.prodAttrId = m_prod_attr_joint.jointProdAttrId and m_prod_attr.delFlag = '0'
+    </sql>
+
+    <select id="selectProdAttrJointVoList" parameterType="ProdAttrJointVo" resultMap="ProdAttrJointVoResult">
+        <include refid="selectProdAttrJointVo"/>
+        <where>
+            <if test="prodId != null "> and m_prod_attr_joint.prodId = #{prodId}</if>
+            <if test="prodAttrId != null "> and m_prod_attr_joint.prodAttrId = #{prodAttrId}</if>
+            <if test="delFlag != null  and delFlag != ''"> and m_prod_attr_joint.delFlag = #{delFlag}</if>
+        </where>
+    </select>
+</mapper>

+ 56 - 42
08.src/Xingxi/xingxi-admin/src/main/resources/mapper/ProdAttrVoMapper.xml

@@ -2,56 +2,70 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.xingxi.web.controller.master.product.mapper.ProdAttrVoMapper">
     <resultMap type="ProdAttrVo" id="ProdAttrVoResult">
-        <result property="id"                   column="id"                 />
-        <result property="prodClassId"          column="prodClassId"        />
-        <result property="prodName"             column="prodName"           />
-        <result property="ipId"                 column="ipId"               />
-        <result property="designerId"           column="designerId"         />
-        <result property="description"          column="description"        />
-        <result property="prodStatus"           column="prodStatus"         />
-        <result property="thirdIdConfirmFlag"   column="thirdIdConfirmFlag" />
-        <result property="delFlag"              column="delFlag"            />
-        <result property="createUser"           column="createUser"         />
-        <result property="createTime"           column="createTime"         />
-        <result property="updateUser"           column="updateUser"         />
-        <result property="updateTime"           column="updateTime"         />
-        <result property="prodClass"            column="className"          />
-        <result property="ipName"               column="ipName"             />
-        <result property="designerName"         column="designerName"       />
+        <result property="prodAttrId"           column="prodAttrId" />
+        <result property="prodId"               column="prodId"     />
+        <result property="attrName"             column="attrName"   />
+        <result property="attrType"             column="attrType"   />
+        <result property="delFlag"              column="delFlag"    />
+        <result property="createTime"           column="createTime" />
+        <result property="createUser"           column="createUser" />
+        <result property="updateUser"           column="updateUser" />
+        <result property="updateTime"           column="updateTime" />
+        <result property="jointId"              column="jointId" />
+        <result property="prodAttrJointId"      column="prodAttrJointId" />
     </resultMap>
 
     <sql id="selectProdAttrVo">
-        select m_prod.id
-             , m_prod.prodClassId
-             , m_prod.prodName
-             , m_prod.ipId
-             , m_prod.designerId
-             , m_prod.description
-             , m_prod.prodStatus
-             , m_prod.thirdIdConfirmFlag
-             , m_prod_class.className
-             , m_designer.designerName
-             , m_ipinfo.ipName
-        from m_prod
-        inner join m_prod_class on m_prod.prodClassId = m_prod_class.prodClassId
-        inner join m_designer on m_prod.designerId = m_designer.id
-        inner join m_ipinfo on m_prod.ipId = m_ipinfo.ipId
+        select m_prod_attr.prodAttrId
+             , m_prod_attr.prodId
+             , m_prod_attr.attrName
+             , m_prod_attr.attrType
+             , m_prod_attr.delFlag
+             , m_prod_attr.createUser
+             , m_prod_attr.createTime
+             , m_prod_attr.updateUser
+             , m_prod_attr.updateTime
+        from m_prod_attr
     </sql>
 
+    <select id="selectProdAttrVoByProdAttrId" parameterType="Long" resultMap="ProdAttrVoResult">
+        <include refid="selectProdAttrVo"/>
+        where prodAttrId = #{prodAttrId}
+    </select>
+
     <select id="selectProdAttrVoList" parameterType="ProdAttrVo" resultMap="ProdAttrVoResult">
         <include refid="selectProdAttrVo"/>
         <where>
-            <if test="prodClassId != null "> and m_prod.prodClassId = #{prodClassId}</if>
-            <if test="prodName != null  and prodName != ''"> and m_prod.prodName like concat('%', #{prodName}, '%')</if>
-            <if test="ipId != null "> and ipId = #{ipId}</if>
-            <if test="designerId != null "> and m_prod.designerId = #{designerId}</if>
-            <if test="description != null  and description != ''"> and m_prod.description = #{description}</if>
-            <if test="prodStatus != null  and prodStatus != ''"> and m_prod.prodStatus = #{prodStatus}</if>
-            <if test="thirdIdConfirmFlag != null  and thirdIdConfirmFlag != ''"> and m_prod.thirdIdConfirmFlag = #{thirdIdConfirmFlag}</if>
-            <if test="delFlag != null  and delFlag != ''"> and m_prod.delFlag = #{delFlag}</if>
-            <if test="prodClass != null  and prodClass != ''"> and m_prod_class.className like concat('%', #{prodClass}, '%')</if>
-            <if test="designerName != null  and designerName != ''"> and m_designer.designerName like concat('%', #{designerName}, '%')</if>
-            <if test="ipName != null  and ipName != ''"> and m_ipinfo.ipName like concat('%', #{ipName}, '%')</if>
+            <if test="prodId != null "> and m_prod_attr.prodId = #{prodId}</if>
+            <if test="prodAttrId != null "> and m_prod_attr.prodAttrId = #{prodAttrId}</if>
+            <if test="attrType != null "> and m_prod_attr.attrType = #{attrType}</if>
+            <if test="attrName != null  and attrName != ''"> and m_prod_attr.attrName like concat('%', #{attrName}, '%')</if>
+            <if test="delFlag != null  and delFlag != ''"> and m_prod_attr.delFlag = #{delFlag}</if>
+        </where>
+    </select>
+
+    <select id="selectProdAttrJointList" parameterType="ProdAttrVo" resultMap="ProdAttrVoResult">
+        select m_prod_attr.prodAttrId
+        , m_prod_attr.prodId
+        , m_prod_attr.attrName
+        , m_prod_attr.attrType
+        , m_prod_attr.delFlag
+        , m_prod_attr.createUser
+        , m_prod_attr.createTime
+        , m_prod_attr.updateUser
+        , m_prod_attr.updateTime
+        , m_prod_attr_joint.prodAttrId as jointId
+        , m_prod_attr_joint.prodAttrJointId
+        from m_prod_attr
+        left join m_prod_attr_joint on m_prod_attr.prodId = m_prod_attr_joint.jointProdId and m_prod_attr.prodAttrId = m_prod_attr_joint.jointProdAttrId
+        <if test="jointId != null "> and m_prod_attr_joint.prodAttrId = #{jointId}</if>
+        <if test="delFlag != null  and delFlag != ''"> and m_prod_attr_joint.delFlag = #{delFlag}</if>
+        <where>
+            <if test="prodId != null "> and m_prod_attr.prodId = #{prodId}</if>
+            <if test="prodAttrId != null "> and m_prod_attr.prodAttrId = #{prodAttrId}</if>
+            <if test="attrType != null "> and m_prod_attr.attrType = #{attrType}</if>
+            <if test="attrName != null  and attrName != ''"> and m_prod_attr.attrName like concat('%', #{attrName}, '%')</if>
+            <if test="delFlag != null  and delFlag != ''"> and m_prod_attr.delFlag = #{delFlag}</if>
         </where>
     </select>
 </mapper>

+ 1 - 4
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/add.html

@@ -43,7 +43,7 @@
                 <div class="form-group">
                     <label class="col-sm-3 control-label">设计师:</label>
                     <div class="col-sm-8">
-                        <select name="designerId" class="form-control m-b" th:with="designers=${@product.getDesigners()}" th:field="*{designerId}" >
+                        <select name="designerId" class="form-control m-b" th:with="designers=${@product.getDesigners()}" >
                             <option value="">所有</option>
                             <option th:each="designer : ${designers}" th:text="${designer.designerName}" th:value="${designer.id}"></option>
                         </select>
@@ -58,9 +58,6 @@
                     </div>
                 </div>
             </div>
-            <div class="col-xs-12">
-                <input type="button" onclick="test()">
-            </div>
         </form>
     </div>
     <th:block th:include="include :: footer" />

+ 0 - 141
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/editAttr.html

@@ -1,141 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
-<head>
-    <th:block th:include="include :: header('编辑标签')" />
-    <th:block th:include="include :: select2-css" />
-    <th:block th:include="include :: bootstrap-select-css" />
-    <th:block th:include="include :: summernote-css" />
-</head>
-<body class="white-bg">
-    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
-        <form class="form-horizontal m" id="form-prod-edit" th:object="${prodVo}">
-            <input name="id" th:field="*{id}" type="hidden">
-            <div class="col-xs-12">
-                <div class="form-group">
-                    <label class="col-sm-3 control-label">商品分类:</label>
-                    <div class="col-sm-8">
-                        <select name="prodClassId" class="form-control" th:with="prodClasses=${@product.getProdClasses()}" th:field="*{prodClassId}" >
-                            <option value="">所有</option>
-                            <option th:each="prodClass : ${prodClasses}" th:text="${prodClass.className}" th:value="${prodClass.prodClassId}"></option>
-                        </select>
-                    </div>
-                </div>
-            </div>
-            <div class="col-xs-12">
-                <div class="form-group">
-                    <label class="col-sm-3 control-label">商品名称:</label>
-                    <div class="col-sm-8">
-                        <input name="prodName" class="form-control" type="text" th:field="*{prodName}">
-                    </div>
-                </div>
-            </div>
-            <div class="col-xs-12">
-                <div class="form-group">
-                    <label class="col-sm-3 control-label">文创名称:</label>
-                    <div class="col-sm-8">
-                        <select name="ipId" class="form-control m-b" th:with="ipInfos=${@ipInfo.getIpInfos()}" th:field="*{ipId}" >
-                            <option value="">所有</option>
-                            <option th:each="ipInfo : ${ipInfos}" th:text="${ipInfo.ipName}" th:value="${ipInfo.ipId}"></option>
-                        </select>
-                    </div>
-                </div>
-            </div>
-            <div class="col-xs-12">
-                <div class="form-group">
-                    <label class="col-sm-3 control-label">设计师:</label>
-                    <div class="col-sm-8">
-                        <select name="designerId" class="form-control m-b" th:with="designers=${@product.getDesigners()}" th:field="*{designerId}" >
-                            <option value="">所有</option>
-                            <option th:each="designer : ${designers}" th:text="${designer.designerName}" th:value="${designer.id}"></option>
-                        </select>
-                    </div>
-                </div>
-            </div>
-            <div class="col-xs-12">
-                <div class="form-group">
-                    <label class="col-sm-3 control-label">商品描述:</label>
-                    <div class="col-sm-10" style="margin-left: 80px">
-                        <div class="summernote" style="border: red;" id="summernote"></div>
-                    </div>
-                </div>
-            </div>
-        </form>
-    </div>
-    <th:block th:include="include :: footer" />
-    <th:block th:include="include :: select2-js" />
-    <th:block th:include="include :: bootstrap-select-js" />
-    <th:block th:include="include :: summernote-js" />
-    <script th:inline="javascript">
-        var prefix = ctx + "master/product/prod"
-        $(".summernote").summernote({
-            lang: 'zh-CN',
-            callbacks:{
-                onImageUpload: function (files) {
-                    var fileSize = 0;
-                    fileSize = files[0].size;
-                    fileSize=Math. round( fileSize/1024*100)/100;
-
-                    if(fileSize>2048){
-                        layer.msg('上传文件不得大于2M,请重新上传。', {time: 3000, icon:6});
-                        return false;
-                    }
-
-                    if (!/image\/\w+/.test(files[0].type)) {
-                        layer.msg('上传的不是图片文件,请重新上传。', {time: 3000, icon:6});
-                        return false;
-                    }
-
-                    var formData = new FormData();
-                    formData.append('imageFile', files[0]);
-                    $.ajax({
-                        url : ctx + "common/upload/file/image",
-                        type : 'POST',
-                        data : formData,
-                        processData : false,
-                        contentType : false,
-                        success : function(result) {
-                            $('.summernote').summernote('insertImage', result.imageUrl);
-                        },error:function(){
-                            $.modal.alertError("上传失败");
-                        }
-                    });
-                }
-            },
-            height: 600,
-            toolbar: [
-                ['style', ['fontname', 'bold', 'italic', 'underline', 'clear']],
-                ['font', ['strikethrough', 'superscript', 'subscript']],
-                ['fontsize', ['fontsize', 'undo', 'redo']],
-                ['color', ['color']],
-                ['para', ['ul', 'ol', 'paragraph']],
-                ['height', ['height']],
-                ['insert', ['picture', 'table']],
-                ['search', ['findnreplace', 'changecolor']]
-            ],
-        });
-        $('.summernote').summernote('code', [[${prodVo.description}]]);
-
-        $("#form-prod-edit").validate({
-            focusCleanup: true
-        });
-
-        function submitHandler() {
-            if ($.validate.form()) {
-                var form = document.getElementById("form-prod-edit");
-                var formData = new FormData(form);
-                formData.append("description", $('#summernote').summernote('code'));
-                $.ajax({
-                    url: prefix + "/edit",
-                    data: formData,
-                    type: "post",
-                    processData: false,
-                    contentType: false,
-                    success: function(result) {
-                        $.operate.successCallback(result);
-                    }
-                });
-            }
-        }
-    </script>
-</body>
-</html>

+ 5 - 5
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prod/prod.html

@@ -57,13 +57,13 @@
             </div>
 
             <div class="btn-group-sm" id="toolbar" role="group">
-                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="system:prod:add">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="master:product:prod:add">
                     <i class="fa fa-plus"></i> 添加
                 </a>
-                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="system:prod:edit">
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="master:product:prod:edit">
                     <i class="fa fa-edit"></i> 修改
                 </a>
-                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="system:prod:remove">
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="master:product:prod:remove">
                     <i class="fa fa-remove"></i> 删除
                 </a>
             </div>
@@ -77,7 +77,7 @@
         var editFlag = [[${@permission.hasPermi('master:product:prod:edit')}]];
         var removeFlag = [[${@permission.hasPermi('master:product:prod:remove')}]];
         var approveFlag = [[${@permission.hasPermi('master:product:prod:approve')}]];
-        var editAttrFlag = [[${@permission.hasPermi('master:product:prod:editAttr')}]];
+        var editAttrFlag = [[${@permission.hasPermi('master:product:prod:viewAttrs')}]];
         var editTagFlag = [[${@permission.hasPermi('master:product:prod:editTag')}]];
         var prefix = ctx + "master/product/prod";
         var prodStatuses = [[${@dict.getType('prod_status')}]];
@@ -138,7 +138,7 @@
         });
 
         function editAttr(id) {
-            $.modal.openTab("商品属性信息",ctx + "master/product/prodAttr/editAttr/" + id);
+            $.modal.openTab("商品属性信息",ctx + "master/product/prodAttr/" + id);
         }
 
         function editTag(id) {

+ 123 - 26
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/add.html

@@ -1,44 +1,141 @@
 <!DOCTYPE html>
 <html lang="zh" xmlns:th="http://www.thymeleaf.org" >
 <head>
-    <th:block th:include="include :: header(#{prodProp.header})" />
+    <th:block th:include="include :: header('新增商品属性')" />
 </head>
 <body class="white-bg">
     <div class="wrapper wrapper-content animated fadeInRight ibox-content">
-        <form class="form-horizontal m" id="form-prodProp-add">
-            <div class="tabs-container">
-                <ul class="nav nav-tabs">
-                    <li class="active" id="selectProp"><a data-toggle="tab" href="#tab-1" aria-expanded="true"> 选择属性</a>
-                    </li>
-                    <li class="" id="inputProp"><a data-toggle="tab" href="#tab-2" aria-expanded="false"> 手工增加</a>
-                    </li>
-                </ul>
-                <div class="tab-content">
-                    <div id="tab-1" class="tab-pane active">
-                        <div class="panel-body">
-                            <div class="col-sm-12 select-table table-striped">
-                                <table id="bootstrap-table"></table>
-                            </div>
-                        </div>
+        <form class="form-horizontal m" id="form-prodAttr-add">
+            <input id="prodId" name="prodId" th:value="${prodId}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">属性名称:</label>
+                    <div class="col-sm-8">
+                        <input name="attrName" class="form-control" type="text">
                     </div>
-                    <div id="tab-2" class="tab-pane">
-                        <div class="panel-body">
-                            <div class="form-group">
-                                <label class="col-sm-3 control-label is-required">[[#{prop.propName}]]:</label>
-                                <div class="col-sm-8">
-                                    <textarea rows = "6" style="OVERFLOW:visible" class="form-control" id="propName" name="propName" placeholder="属性名称" required></textarea>
-                                    <label class="control-label">如有多个,请每行写一个。请勿输入“/”,“/”会被自动转换为“-”</label>
-                                </div>
-                            </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">属性种类 :</label>
+                    <div class="col-sm-8">
+                        <div class="radio radio-box">
+                            <input type="radio" name="attrType" value="attr" id="rAttrType1" checked=""><label>属性</label>
+                        </div>
+                        <div class="radio radio-box">
+                            <input type="radio" name="attrType" value="joint" id="rAttrType2"><label>属性组合</label>
                         </div>
                     </div>
                 </div>
             </div>
         </form>
+        <div class="col-sm-12" id="prodAttr-area">
+            <div class="btn-group-sm" id="toolbar" role="group">
+            </div>
+            <div class="col-sm-8 select-table table-striped">
+                <table id="prodAttr-table"></table>
+            </div>
+        </div>
     </div>
     <th:block th:include="include :: footer" />
-    <script th:src="@{/biandan/product/prodProp/add.js?v=2.0}"></script>
     <script th:inline="javascript">
+        var prefix = ctx + "master/product/prodAttr";
+
+        var options = {
+            id: "prodAttr-table",
+            url: prefix + "/list",
+            modalName: "商品属性列表",
+            showSearch: false,
+            showPageGo: false,
+            showRefresh: true,
+            showColumns: false,
+            showToggle: false,
+            showExport: false,
+            queryParams: queryParams,
+            columns: [
+                {
+                    checkbox: true
+                },
+                {
+                    field: 'attrName',
+                    title: '属性名称'
+                },
+                {
+                    field: 'attrType',
+                    title: '属性分类'
+                }
+            ]
+        };
+        $.table.init(options);
+
+        $("#form-prodAttr-add").validate({
+            rules: {
+                attrName: {
+                    required: true
+                }
+            },
+            messages: {
+                attrName: icon + "请输入属性名称"
+            },
+            focusCleanup: true
+        });
+
+        $("input[name='attrType']").change(function() {
+            if ($(this).is(":checked")) {
+                if ($("input[name='attrType']:checked").val() === "attr") {
+                    $("#prodAttr-area").hide();
+                } else {
+                    $("#prodAttr-area").show();
+                    $.table.refresh();
+                }
+            }
+        });
+
+        function queryParams(params) {
+            var search = $.table.queryParams(params);
+            search.prodId = $("#prodId").val();
+            search.attrType = 'attr';
+            search.attrName = null;
+            return search;
+        }
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                var attrType = $("input[name='attrType']:checked").val();
+                if (attrType === "attr") {
+                    $.operate.save(prefix + "/addAttr", $('#form-prodAttr-add').serialize());
+                } else {
+                    var prodAttrJoints = [];
+                    var selectedRows = $("#prodAttr-table").bootstrapTable('getSelections');
+                    selectedRows.forEach((row) => {
+                        prodAttrJoint = {
+                            "prodId" : $("#prodId").val(),
+                            "jointProdId" : $("#prodId").val(),
+                            "jointProdAttrId" : row.prodAttrId,
+                        }
+                        prodAttrJoints.push(prodAttrJoint);
+                    });
+
+                    var data = {
+                        "prodId" : $("#prodId").val(),
+                        "attrName" : $("input[name='attrName']").val(),
+                        "attrType" : attrType,
+                        "prodAttrJoints" : prodAttrJoints
+                    }
+                    $.ajax({
+                        url: prefix + "/addAttrs",
+                        contentType: 'application/json',
+                        data: JSON.stringify(data),
+                        type: "post",
+                        processData: false,
+                        success: function(result) {
+                            $.operate.successCallback(result);
+                        }
+                    });
+                }
+            }
+        }
+        $("#prodAttr-area").hide();
     </script>
 </body>
 </html>

+ 156 - 10
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/edit.html

@@ -1,26 +1,172 @@
 <!DOCTYPE html>
 <html lang="zh" xmlns:th="http://www.thymeleaf.org" >
 <head>
-    <th:block th:include="include :: header(#{prodProp.header.edit})" />
+    <th:block th:include="include :: header('新增商品属性')" />
 </head>
 <body class="white-bg">
     <div class="wrapper wrapper-content animated fadeInRight ibox-content">
-        <form class="form-horizontal m" id="form-prodProp-edit" th:object="${prodProp}">
-            <input name="propId" th:field="*{propId}" type="hidden">
-            <div class="form-group">    
-                <label class="col-sm-3 control-label is-required">[[#{prodProp.propName}]]:</label>
-                <div class="col-sm-8">
-                    <input name="propName" th:field="*{propName}" class="form-control" type="text" required>
+        <form class="form-horizontal m" id="form-prodAttr-edit" th:object="${prodAttrVo}">
+            <input id="prodId" name="prodId" th:value="${prodId}" type="hidden">
+            <input id="prodAttrId" name="prodAttrId" th:value="${prodAttrId}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">属性名称:</label>
+                    <div class="col-sm-8">
+                        <input name="attrName" class="form-control" type="text" th:field="*{attrName}">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">属性种类 :</label>
+                    <div class="col-sm-8">
+                        <div class="radio-box" th:each="dict:${@dict.getType('prod_attr_type')}">
+                            <input type="radio" th:id="${dict.dictCode}" name="attrType" th:value="${dict.dictValue}" th:field="*{attrType}">
+                            <label th:for="${dict.dictCode}" th:text="${dict.dictLabel}"></label>
+                        </div>
+                    </div>
                 </div>
             </div>
-            <input name="updateTime" th:value="${#dates.format(prodProp.updateTime, 'yyyy-MM-dd HH:mm:ss')}" type="hidden">
         </form>
+        <div class="col-sm-12" id="prodAttr-area">
+            <div class="btn-group-sm" id="toolbar" role="group">
+            </div>
+            <div class="col-sm-8 select-table table-striped">
+                <table id="prodAttr-table"></table>
+            </div>
+        </div>
     </div>
     <th:block th:include="include :: footer" />
-    <script th:src="@{/biandan/product/prodProp/edit.js?v=2.0}"></script>
-
     <script th:inline="javascript">
+        var prefix = ctx + "master/product/prodAttr";
+
+        var options = {
+            id: "prodAttr-table",
+            url: prefix + "/jointList",
+            modalName: "商品属性列表",
+            showSearch: false,
+            showPageGo: false,
+            showRefresh: true,
+            showColumns: false,
+            showToggle: false,
+            showExport: false,
+            queryParams: queryParams,
+            columns: [
+                {
+                    checkbox: true,
+                    formatter: function(value, row, index) {
+                        if (row.jointId !== null) {
+                            return {
+                                checked : true
+                            }
+                        }
+                    }
+                },
+                {
+                    field: 'attrName',
+                    title: '属性名称'
+                },
+                {
+                    field: 'attrType',
+                    title: '属性分类'
+                }
+            ]
+        };
+        $.table.init(options);
+
+        $("#form-prodAttr-add").validate({
+            rules: {
+                attrName: {
+                    required: true
+                }
+            },
+            messages: {
+                attrName: icon + "请输入属性名称"
+            },
+            focusCleanup: true
+        });
+
+        $("input[name='attrType']").change(function() {
+            if ($(this).is(":checked")) {
+                if ($("input[name='attrType']:checked").val() === "attr") {
+                    $("#prodAttr-area").hide();
+                } else {
+                    $("#prodAttr-area").show();
+                    $.table.refresh();
+                }
+            }
+        });
+
+        function queryParams(params) {
+            var search = $.table.queryParams(params);
+            search.prodId = $("#prodId").val();
+            search.jointId = $("#prodAttrId").val();
+            search.attrType = 'attr';
+            search.prodAttrId = null;
+            search.attrName = null;
+            return search;
+        }
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                var attrType = $("input[name='attrType']:checked").val();
+                if (attrType === "attr") {
+                    var data = {
+                        "prodId" : $("#prodId").val(),
+                        "prodAttrId" : $("#prodAttrId").val(),
+                        "attrName" : $("input[name='attrName']").val(),
+                        "attrType" : attrType
+                    }
+                    $.ajax({
+                        url: prefix + "/editAttr",
+                        contentType: 'application/json',
+                        data: JSON.stringify(data),
+                        type: "post",
+                        processData: false,
+                        success: function(result) {
+                            $.operate.successCallback(result);
+                        }
+                    });
+                } else {
+                    var prodAttrJoints = [];
+                    var selectedRows = $("#prodAttr-table").bootstrapTable('getSelections');
+                    selectedRows.forEach((row) => {
+                        prodAttrJoint = {
+                            "prodAttrJointId" : row.prodAttrJointId,
+                            "prodId" : $("#prodId").val(),
+                            "jointProdId" : $("#prodId").val(),
+                            "jointProdAttrId" : row.prodAttrId,
+                        }
+                        prodAttrJoints.push(prodAttrJoint);
+                    });
 
+                    var data = {
+                        "prodId" : $("#prodId").val(),
+                        "prodAttrId" : $("#prodAttrId").val(),
+                        "attrName" : $("input[name='attrName']").val(),
+                        "attrType" : attrType,
+                        "prodAttrJoints" : prodAttrJoints
+                    }
+                    $.ajax({
+                        url: prefix + "/editAttr",
+                        contentType: 'application/json',
+                        data: JSON.stringify(data),
+                        type: "post",
+                        processData: false,
+                        success: function(result) {
+                            $.operate.successCallback(result);
+                        }
+                    });
+                }
+            }
+        }
+        $(function() {
+            if ($("input[name='attrType']:checked").val() === "attr") {
+                $("#prodAttr-area").hide();
+            } else {
+                $("#prodAttr-area").show();
+            }
+        })
     </script>
 </body>
 </html>

+ 106 - 52
08.src/Xingxi/xingxi-admin/src/main/resources/templates/master/product/prodAttr/prodAttr.html

@@ -1,58 +1,112 @@
 <!DOCTYPE html>
 <html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
 <head>
-    <th:block th:include="include :: header(#{prodProp.header.list})" />
+    <th:block th:include="include :: header('编辑商品属性')" />
 </head>
-<body class="gray-bg">
-     <div class="container-div">
-        <div class="row">
-            <div class="col-sm-12 search-collapse">
-                <form id="formId">
-                    <div class="select-list">
-                        <ul>
-                            <li>
-                                <label>[[#{prodProp.prodId}]]:</label>
-                                <input type="text" name="prodId"/>
-                            </li>
-                            <li>
-                                <label>[[#{prodProp.propName}]]:</label>
-                                <input type="text" name="propName"/>
-                            </li>
-                            <li>
-                                <label>[[#{prodProp.sort}]]:</label>
-                                <input type="text" name="sort"/>
-                            </li>
-                            <li>
-                                <label>[[#{prodProp.delFlag}]]:</label>
-                                <input type="text" name="delFlag"/>
-                            </li>
-                            <li>
-                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;[[#{btn.search}]]</a>
-                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;[[#{btn.reset}]]</a>
-                            </li>
-                        </ul>
-                    </div>
-                </form>
-            </div>
+<body class="white-bg">
+<form id="formId" class="form-horizontal m-t">
+<input id="prodId" th:value="${prodId}" type="hidden">
+</form>
+<div class="btn-group-sm" id="toolbar" role="group">
+    <a class="btn btn-success" onclick="addAttr()" shiro:hasPermission="master:product:prodAttr:add">
+        <i class="fa fa-plus"></i> 添加
+    </a>
+</div>
+<div class="col-sm-12 select-table table-striped">
+    <table id="bootstrap-table"></table>
+</div>
+<th:block th:include="include :: footer" />
+<script th:inline="javascript">
+    var prefix = ctx + "master/product/prodAttr";
+    var datas = [[${@dict.getType('prod_attr_type')}]];
+    var editFlag = [[${@permission.hasPermi('master:product:prodAttr:edit')}]];
+    var removeFlag = [[${@permission.hasPermi('master:product:prodAttr:remove')}]];
+    var editJointFlag = [[${@permission.hasPermi('master:product:prodJoint:edit')}]];
+    var removeJointFlag = [[${@permission.hasPermi('master:product:prodJoint:remove')}]];
 
-            <div class="btn-group-sm" id="toolbar" role="group">
-                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="product:prodProp:add">
-                    <i class="fa fa-plus"></i> [[#{btn.add}]]
-                </a>
-                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="product:prodProp:edit">
-                    <i class="fa fa-edit"></i> [[#{btn.modify}]]
-                </a>
-            </div>
-            <div class="col-sm-12 select-table table-striped">
-                <table id="bootstrap-table"></table>
-            </div>
-        </div>
-    </div>
-    <th:block th:include="include :: footer" />
-    <script th:inline="javascript">
-        var editFlag = [[${@permission.hasPermi('product:prodProp:edit')}]];
-        var removeFlag = [[${@permission.hasPermi('product:prodProp:remove')}]];
-        var prefix = ctx + "master/product/prodAttr";
-    </script>
+    $("#form-prod-edit").validate({
+        focusCleanup: true
+    });
+
+    $(function() {
+        var options = {
+            url: prefix + "/list",
+            createUrl: prefix + "/add/{id}",
+            updateUrl: prefix + "/edit/{id}",
+            removeUrl: prefix + "/remove",
+            exportUrl: prefix + "/export",
+            modalName: "商品属性",
+            detailView: true,
+            queryParams : {
+                "prodId": $("#prodId").val()
+            },
+            onExpandRow : function(index, row, $detail) {
+                initChildTable(index, row, $detail);
+            },
+            columns: [
+                {
+                    field: 'attrName',
+                    title: '属性名称'
+                },
+                {
+                    field: 'attrType',
+                    title: '类型',
+                    formatter: function(value, row, index) {
+                        return $.table.selectDictLabel(datas, value);
+                    }
+                },
+                {
+                    title: '操作',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.prodAttrId + '\')"><i class="fa fa-edit"></i>编辑</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.prodAttrId + '\')"><i class="fa fa-remove"></i>删除</a> ');
+                        return actions.join('');
+                    }
+                }
+            ]
+        };
+        $.table.init(options);
+    });
+
+    initChildTable = function(index, row, $detail) {
+        var childTable = $detail.html('<table style="table-layout:fixed"></table>').find('table');
+        $(childTable).bootstrapTable({
+            url: ctx + "master/product/prodAttrJoint/list",
+            method: 'post',
+            sidePagination: "server",
+            contentType: "application/x-www-form-urlencoded",
+            queryParams : {
+                "prodId": $("#prodId").val(),
+                "prodAttrId": row.prodAttrId
+            },
+            columns: [
+                {
+                    field : 'attrName',
+                    title : '属性名称'
+                },
+                {
+                    title: '操作',
+                    align: 'center',
+                    formatter: function (value, row, index) {
+                        var subActions = [];
+                        subActions.push('<a class="btn btn-success btn-xs ' + editJointFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
+                        subActions.push('<a class="btn btn-danger btn-xs ' + removeJointFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a> ');
+                        return subActions.join('');
+                    }
+                }
+            ]
+        });
+    };
+
+    function addAttr() {
+        $.operate.add($("#prodId").val());
+    }
+
+    function removeAttr() {
+        $.operate.add($("#prodId").val());
+    }
+</script>
 </body>
-</html>
+</html>

+ 30 - 0
08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EAttrType.java

@@ -0,0 +1,30 @@
+package com.xingxi.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @program: gululuq
+ * @description: 删除标志
+ * @author: 金
+ * @create: 2025-03-16
+ */
+@AllArgsConstructor
+@Getter
+public enum EAttrType {
+    ATTR("attr", "属性"),
+    JOINT("joint", "属性组合");
+
+    private String val;
+    private String desc;
+
+    // 解析
+    public static EAttrType parseByVal(String val) {
+        for (EAttrType type : EAttrType.values()) {
+            if (type.getVal().equalsIgnoreCase(val)) {
+                return type;
+            }
+        }
+        return EAttrType.ATTR;
+    }
+}

+ 2 - 0
08.src/Xingxi/xingxi-system/src/main/java/com/xingxi/master/product/service/impl/ProdAttrJointServiceImpl.java

@@ -1,6 +1,7 @@
 package com.xingxi.master.product.service.impl;
 
 import com.xingxi.common.core.text.Convert;
+import com.xingxi.common.enums.EDelFlag;
 import com.xingxi.common.utils.DateUtils;
 import com.xingxi.master.product.domain.ProdAttrJoint;
 import com.xingxi.master.product.mapper.ProdAttrJointMapper;
@@ -40,6 +41,7 @@ public class ProdAttrJointServiceImpl implements IProdAttrJointService {
      */
     @Override
     public List<ProdAttrJoint> selectProdAttrJointList(ProdAttrJoint prodAttrJoint) {
+        prodAttrJoint.setDelFlag(EDelFlag.NO.getVal());
         return prodAttrJointMapper.selectProdAttrJointList(prodAttrJoint);
     }
 

+ 1 - 0
08.src/Xingxi/xingxi-system/src/main/resources/mapper/master/ProdAttrMapper.xml

@@ -114,6 +114,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update m_prod_attr
         set delFlag = '1'
         <where>
+            <if test="prodAttrId != null "> and prodAttrId = #{prodAttrId}</if>
             <if test="prodId != null "> and prodId = #{prodId}</if>
             <if test="attrName != null  and attrName != ''"> and attrName like concat('%', #{attrName}, '%')</if>
             <if test="attrType != null  and attrType != ''"> and attrType = #{attrType}</if>