017 平台属性[属性分组、规格参数、销售属性]

news2024/11/28 11:54:15

文章目录

    • 获取指定分类的属性列表
      • AttrController.java
      • AttrServiceImpl.java
    • 获取属性分组所关联的所有属性
      • AttrGroupController
      • AttrServiceImpl.java
    • 移除
      • AttrGroupController.java
      • AttrServiceImpl.java
      • AttrAttrgroupRelationDao.java
      • AttrAttrgroupRelationDao.xml
    • 获取属性分组中,当前分类下没有进行关联的所有属性
      • AttrGroupController.java
      • AttrServiceImpl.java
    • 添加属性与属性分组的关联关系
      • AttrGroupController.java
      • AttrAttrgroupRelationServiceImpl.java
  • =================================================
    • controller
      • AttrAttrgroupRelationController.java
      • AttrController.java
      • AttrGroupController.java
    • dao
      • AttrAttrgroupRelationDao.java
      • AttrDao.java
      • AttrGroupDao.java
    • entity
      • AttrAttrgroupRelationEntity.java
      • AttrEntity.java
      • AttrGroupEntity.java
    • service
      • AttrAttrgroupRelationService
      • AttrGroupService.java
      • AttrService.java
    • impl
      • AttrAttrgroupRelationServiceImpl.java
      • AttrGroupServiceImpl.java
      • AttrServiceImpl.java
    • xml
      • AttrAttrgroupRelationDao.xml
    • 前端
      • attr-add-or-update.vue
      • attr-group-relation.vue
      • attrgroup-add-or-update.vue
      • attrgroup.vue
      • baseattr.vue
      • category.vue
      • saleattr.vue

基本属性 销售属性
attr-add-or-update
attr-add-or-update

获取指定分类的属性列表

AttrController.java

    /**
     * 列表
     * 请求路径 /product/attr/base/list/{categoryId},分页查询,模糊查询,基本属性
     * 请求路径 /product/attr/sale/list/{categoryId},分页查询,模糊查询,销售属性
     */
    @RequestMapping("/{attrType}/list/{categoryId}")
    //@RequiresPermissions("product:attr:list")
    public R list(@RequestParam Map<String, Object> params,@PathVariable("categoryId") Long categoryId, @PathVariable("attrType") String attrType){
        PageUtils page = attrService.queryBaseAttrPage(params, categoryId, attrType);

        return R.ok().put("page", page);
    }

AttrServiceImpl.java

 /**
     * 获取指定分类的属性列表
     *
     * @param params
     * @param categoryId
     * @param attrType
     * @return
     */
    @Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long categoryId, String attrType) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        //拼接查询的attrtype条件
        if("base".equals(attrType)){
            queryWrapper.eq("attr_type",1);
        } else if("sale".equals(attrType)){
            queryWrapper.eq("attr_type",0);
        }


        //拼接分类id
        if (categoryId != 0) {
            queryWrapper.eq("category_id", categoryId);
        }
        //拼接关键字查询 key
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            queryWrapper.and(wrapper -> {
                wrapper.eq("id", key).or().like("name",key);
            });
        }
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );

        //------获取所属分类名称-----获取所属分组名称--------
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> records = page.getRecords();
        List<AttrRespVo> respVos = records.stream().map(attrEntity -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            //1.封装基础属性内容
            BeanUtils.copyProperties(attrEntity,attrRespVo);
            //2.封装属性分组名称
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(
                    new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getId())
            );
            //根据attrAttrgroupRelationEntity 获取attrGroup
            if (attrAttrgroupRelationEntity != null) {
                AttrGroupEntity attrGroupEntity =  attrGroupDao.selectById(attrAttrgroupRelationEntity.getAttrGroupId());

                if (attrGroupEntity != null) {
                    attrRespVo.setGroupName(attrGroupEntity.getName());
                }

            }

            //3.封装分类名称
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCategoryId());
            if(categoryEntity != null) {
                attrRespVo.setCategoryName(categoryEntity.getName());
            }



            return attrRespVo;
        }).collect(Collectors.toList());

        pageUtils.setList(respVos);

        return pageUtils;
    }

获取属性分组所关联的所有属性

在这里插入图片描述

AttrGroupController

    /**
     * 获取属性分组所关联的所有属性
     * @param attrGroupId
     * @return
     */
    @GetMapping("/{attrGroupId}/attr/relation")
    public R getAttrRelation(@PathVariable("attrGroupId") Long attrGroupId){
        List<AttrEntity> entities = attrService.getRelationAttr(attrGroupId);


        return R.ok().put("data", entities);
    }

AttrServiceImpl.java

    /**
     * 获取属性分组所关联的所有属性
     * @param attrGroupId
     * @return
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrGroupId) {
        //获取属性分组及属性关联关系
        List<AttrAttrgroupRelationEntity> entities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId)
        );

        //获取每个属性关联对象中的属性id
        List<Long> attrIds = entities.stream().map(attrAttrgroupRelationEntity -> {
            return attrAttrgroupRelationEntity.getAttrId();
        }).collect(Collectors.toList());




        //通过属性id 获取对应的 AttrEntity对象
        if (attrIds == null || attrIds.size() == 0) {
            return null;
        }

        List<AttrEntity> attrEntities = this.listByIds(attrIds);
        return attrEntities;
    }

移除

AttrGroupController.java

    /**
     * 请求参数 [{attrId: 19, attrGroupId: 10}]
     * @return
     */

    @PostMapping("/attr/relation/delete")
    public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){

        attrService.deleteRelation(vos);

        return R.ok();

    }

AttrServiceImpl.java

    @Override
    public void deleteRelation(AttrGroupRelationVo[] vos) {
        List<AttrAttrgroupRelationEntity> relationEntities = Arrays.asList(vos).stream().map(attrGroupRelationVo -> {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();

            BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);
            return attrAttrgroupRelationEntity;
        }).collect(Collectors.toList());
        //批量移除属性分组和 属性的关联关系
        attrAttrgroupRelationDao.deleteBatch(relationEntities);



    }

AttrAttrgroupRelationDao.java

package com.xd.cubemall.product.dao;

import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 属性分组关联表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Mapper
public interface AttrAttrgroupRelationDao extends BaseMapper<AttrAttrgroupRelationEntity> {

    void deleteBatch(@Param("entities") List<AttrAttrgroupRelationEntity> relationEntities);
}

AttrAttrgroupRelationDao.xml

<?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.xd.cubemall.product.dao.AttrAttrgroupRelationDao">

	<!-- 可根据自己的需求,是否要使用 -->
    <resultMap type="com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity" id="attrAttrgroupRelationMap">
        <result property="id" column="id"/>
        <result property="attrId" column="attr_id"/>
        <result property="attrGroupId" column="attr_group_id"/>
        <result property="attrSort" column="attr_sort"/>
    </resultMap>
    <delete id="deleteBatch">
        DELETE FROM tb_attr_attrgroup_relation
        <where>
            <foreach collection="entities" item="item" separator=" or ">
                (attr_id=#{item.attrId} and attr_group_id=#{item.attrGroupId})
            </foreach>
        </where>

    </delete>


</mapper>

在这里插入图片描述

获取属性分组中,当前分类下没有进行关联的所有属性

在这里插入图片描述
在这里插入图片描述

AttrGroupController.java

    /**
     * 获取属性分组中,当前分类下没有进行关联的所有属性
     * @param attrGroupId
     * @return
     */
    @GetMapping("/{attrGroupId}/noattr/relation")
    public R getNoAttrRelation(@RequestParam Map<String, Object> params, @PathVariable("attrGroupId") Long attrGroupId){
        PageUtils page = attrService.getNoRelationAttr(params, attrGroupId);

        return R.ok().put("page", page);
    }

AttrServiceImpl.java

    /**
     * 获取属性分组中,当前分类下没有进行关联的所有属性
     * @param params
     * @param attrGroupId
     * @return
     */
    @Override
    public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId) {
        //1.获取当前分类下,所有分组已经关联的属性
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
        //1.1 获取当前属性分组所对应的 分类
        Integer categoryId = attrGroupEntity.getCategoryId();
        //1.2 获取当前分类下 所关联的所有属性分组
        List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectList(
                new QueryWrapper<AttrGroupEntity>().eq("category_id",categoryId)
        );
        //获取当前分类下,所有分组的ID
        List<Long> groupIds = attrGroupEntities.stream().map(attrGroup -> {
            return attrGroup.getId();
        }).collect(Collectors.toList());
        //从中间表 attr_attrgroup_relation中 获取 groupIds 所对应的属性
        List<AttrAttrgroupRelationEntity> entities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id",groupIds)
        );
        // attrIds 是 当前分类下,所有属性分组已经关联的 属性集合
        List<Long> attrIds = entities.stream().map(item -> {
            return item.getAttrId();
        }).collect(Collectors.toList());




        //2.获取当前分类下所有属性
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("category_id",categoryId).eq("attr_type",1);

        //3.移除已经关联的内容,剩下的就是未关联的属性
        if (attrIds != null && attrIds.size() > 0) {
            queryWrapper.notIn("id",attrIds);
        }

        String key = (String) params.get("key");
        if (StringUtils.isEmpty(key)) {
            queryWrapper.and(wrapper -> {
                wrapper.eq("id", key).or().like("name",key);
            });
        }

        IPage<AttrEntity> page =  this.page(new Query<AttrEntity>().getPage(params), queryWrapper);





        return new PageUtils(page);
    }

添加属性与属性分组的关联关系

AttrGroupController.java

    @PostMapping("/attr/relation")
    public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
        attrAttrgroupRelationService.saveBatch(vos);

        return R.ok();
    }

AttrAttrgroupRelationServiceImpl.java

    /**
     * 添加属性与属性分组的关联关系
     * @param vos
     */
    @Override
    public void saveBatch(List<AttrGroupRelationVo> vos) {
        List<AttrAttrgroupRelationEntity> collect = vos.stream().map(attrGroupRelationVo -> {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);
            return attrAttrgroupRelationEntity;
        }).collect(Collectors.toList());
        this.saveBatch(collect);
    }

=================================================

controller

AttrAttrgroupRelationController.java

package com.xd.cubemall.product.controller;

import java.util.Arrays;
import java.util.Map;


import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.xd.cubemall.product.service.AttrAttrgroupRelationService;




/**
 * 属性分组关联表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 07:57:20
 */
@RestController
@RequestMapping("product/attrattrgrouprelation")
public class AttrAttrgroupRelationController {
    @Autowired
    private AttrAttrgroupRelationService attrAttrgroupRelationService;

    /**
     * 列表
     */
    @RequestMapping("/list")
    //@RequiresPermissions("product:attrattrgrouprelation:list")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = attrAttrgroupRelationService.queryPage(params);

        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{id}")
    //@RequiresPermissions("product:attrattrgrouprelation:info")
    public R info(@PathVariable("id") Long id){
		AttrAttrgroupRelationEntity attrAttrgroupRelation = attrAttrgroupRelationService.getById(id);

        return R.ok().put("attrAttrgroupRelation", attrAttrgroupRelation);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:attrattrgrouprelation:save")
    public R save(@RequestBody AttrAttrgroupRelationEntity attrAttrgroupRelation){
		attrAttrgroupRelationService.save(attrAttrgroupRelation);

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:attrattrgrouprelation:update")
    public R update(@RequestBody AttrAttrgroupRelationEntity attrAttrgroupRelation){
		attrAttrgroupRelationService.updateById(attrAttrgroupRelation);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    //@RequiresPermissions("product:attrattrgrouprelation:delete")
    public R delete(@RequestBody Long[] ids){
		attrAttrgroupRelationService.removeByIds(Arrays.asList(ids));

        return R.ok();
    }

}

AttrController.java

package com.xd.cubemall.product.controller;

import java.util.Arrays;
import java.util.Map;


import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.R;
import com.xd.cubemall.product.vo.AttrRespVo;
import com.xd.cubemall.product.vo.AttrVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.xd.cubemall.product.entity.AttrEntity;
import com.xd.cubemall.product.service.AttrService;




/**
 * 属性表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 07:57:20
 */
@RestController
@RequestMapping("product/attr")
public class AttrController {
    @Autowired
    private AttrService attrService;

    /**
     * 列表
     * 请求路径 /product/attr/base/list/{categoryId},分页查询,模糊查询,基本属性
     * 请求路径 /product/attr/sale/list/{categoryId},分页查询,模糊查询,销售属性
     */
    @RequestMapping("/{attrType}/list/{categoryId}")
    //@RequiresPermissions("product:attr:list")
    public R list(@RequestParam Map<String, Object> params,@PathVariable("categoryId") Long categoryId, @PathVariable("attrType") String attrType){
        PageUtils page = attrService.queryBaseAttrPage(params, categoryId, attrType);

        return R.ok().put("page", page);
    }


    /**
     * 指定属性信息的回显
     */
    @RequestMapping("/info/{id}")
    //@RequiresPermissions("product:attr:info")
    public R info(@PathVariable("id") Long id){
		//AttrEntity attr = attrService.getById(id);
        AttrRespVo attrRespVo = attrService.getAttrInfo(id);


        return R.ok().put("attr", attrRespVo);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:attr:save")
    public R save(@RequestBody AttrVo attrVo){
		attrService.saveAttr(attrVo);

        return R.ok();
    }

    /**
     * 修改提交操作
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:attr:update")
    public R update(@RequestBody AttrVo attrVo){
		attrService.updateAttr(attrVo);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    //@RequiresPermissions("product:attr:delete")
    public R delete(@RequestBody Long[] ids){
		attrService.removeByIds(Arrays.asList(ids));

        return R.ok();
    }

}

AttrGroupController.java

package com.xd.cubemall.product.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;


import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.R;
import com.xd.cubemall.product.entity.AttrEntity;
import com.xd.cubemall.product.service.AttrAttrgroupRelationService;
import com.xd.cubemall.product.service.AttrService;
import com.xd.cubemall.product.service.CategoryService;
import com.xd.cubemall.product.vo.AttrGroupRelationVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.xd.cubemall.product.entity.AttrGroupEntity;
import com.xd.cubemall.product.service.AttrGroupService;




/**
 * 属性分组表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 07:57:20
 */
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
    @Autowired
    private AttrGroupService attrGroupService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private AttrAttrgroupRelationService attrAttrgroupRelationService;



    @PostMapping("/attr/relation")
    public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
        attrAttrgroupRelationService.saveBatch(vos);

        return R.ok();
    }


    /**
     * 请求参数 [{attrId: 19, attrGroupId: 10}]
     * @return
     */

    @PostMapping("/attr/relation/delete")
    public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){

        attrService.deleteRelation(vos);

        return R.ok();

    }




    /**
     * 获取属性分组所关联的所有属性
     * @param attrGroupId
     * @return
     */
    @GetMapping("/{attrGroupId}/attr/relation")
    public R getAttrRelation(@PathVariable("attrGroupId") Long attrGroupId){
        List<AttrEntity> entities = attrService.getRelationAttr(attrGroupId);


        return R.ok().put("data", entities);
    }


    /**
     * 获取属性分组中,当前分类下没有进行关联的所有属性
     * @param attrGroupId
     * @return
     */
    @GetMapping("/{attrGroupId}/noattr/relation")
    public R getNoAttrRelation(@RequestParam Map<String, Object> params, @PathVariable("attrGroupId") Long attrGroupId){
        PageUtils page = attrService.getNoRelationAttr(params, attrGroupId);

        return R.ok().put("page", page);
    }



    /**
     * 列表
     */
    @RequestMapping("/list/{categoryId}")
    //@RequiresPermissions("product:attrgroup:list")
    public R list(@RequestParam Map<String, Object> params, @PathVariable("categoryId") Long categoryId){
        //PageUtils page = attrGroupService.queryPage(params);
        PageUtils page = attrGroupService.queryPage(params, categoryId);
        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{id}")
    //@RequiresPermissions("product:attrgroup:info")
    public R info(@PathVariable("id") Long id){
		AttrGroupEntity attrGroup = attrGroupService.getById(id);
        //查询出categoryPath的路径
        //当前分类ID
        Integer categoryId = attrGroup.getCategoryId();
        //查询出当前分类ID的 祖宗ID
        Long[] path = categoryService.findCategoryPath(categoryId);
        attrGroup.setCategoryPath(path);
        return R.ok().put("attrGroup", attrGroup);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:attrgroup:save")
    public R save(@RequestBody AttrGroupEntity attrGroup){
		attrGroupService.save(attrGroup);

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:attrgroup:update")
    public R update(@RequestBody AttrGroupEntity attrGroup){
		attrGroupService.updateById(attrGroup);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    //@RequiresPermissions("product:attrgroup:delete")
    public R delete(@RequestBody Long[] ids){
		attrGroupService.removeByIds(Arrays.asList(ids));

        return R.ok();
    }




}

dao

AttrAttrgroupRelationDao.java

package com.xd.cubemall.product.dao;

import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * 属性分组关联表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Mapper
public interface AttrAttrgroupRelationDao extends BaseMapper<AttrAttrgroupRelationEntity> {

    void deleteBatch(@Param("entities") List<AttrAttrgroupRelationEntity> relationEntities);
}

AttrDao.java

package com.xd.cubemall.product.dao;

import com.xd.cubemall.product.entity.AttrEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * 属性表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Mapper
public interface AttrDao extends BaseMapper<AttrEntity> {
	
}

AttrGroupDao.java

package com.xd.cubemall.product.dao;

import com.xd.cubemall.product.entity.AttrGroupEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * 属性分组表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Mapper
public interface AttrGroupDao extends BaseMapper<AttrGroupEntity> {
	
}

entity

AttrAttrgroupRelationEntity.java

package com.xd.cubemall.product.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;

/**
 * 属性分组关联表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Data
@TableName("tb_attr_attrgroup_relation")
public class AttrAttrgroupRelationEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * id
	 */
	@TableId
	private Long id;
	/**
	 * 属性ID
	 */
	private Long attrId;
	/**
	 * 属性分组ID
	 */
	private Long attrGroupId;
	/**
	 * 排序
	 */
	private Integer attrSort;

}

AttrEntity.java

package com.xd.cubemall.product.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;

/**
 * 属性表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Data
@TableName("tb_attr")
public class AttrEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 自增ID
	 */
	@TableId
	private Long id;
	/**
	 * 名称
	 */
	private String name;
	/**
	 * 搜索类型
	 */
	private Integer searchType;
	/**
	 * 图表
	 */
	private String icon;
	/**
	 * 选择值
	 */
	private String valueSelect;
	/**
	 * 属性类型:0-销售属性,1-基本属性,2-既是基本属性又是销售属性
	 */
	private Integer attrType;
	/**
	 * 启用
	 */
	private Long enable;
	/**
	 * 分类ID
	 */
	private Integer categoryId;
	/**
	 * 描述
	 */
	private Integer showDesc;

}

AttrGroupEntity.java

package com.xd.cubemall.product.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;

/**
 * 属性分组表
 * 
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
@Data
@TableName("tb_attr_group")
public class AttrGroupEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * 自增ID
	 */
	@TableId
	private Long id;
	/**
	 * 名称
	 */
	private String name;
	/**
	 * 排序
	 */
	private Integer sort;
	/**
	 * 描述
	 */
	private String descript;
	/**
	 * 图表
	 */
	private String icon;
	/**
	 * 分类ID
	 */
	private Integer categoryId;

	/**
	 * 完整的categoryID的路径
	 */
	@TableField(exist = false)
	private Long[] categoryPath;
}

service

AttrAttrgroupRelationService

package com.xd.cubemall.product.service;

import com.baomidou.mybatisplus.extension.service.IService;

import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.xd.cubemall.product.vo.AttrGroupRelationVo;

import java.util.List;
import java.util.Map;

/**
 * 属性分组关联表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
public interface AttrAttrgroupRelationService extends IService<AttrAttrgroupRelationEntity> {

    PageUtils queryPage(Map<String, Object> params);

    void saveBatch(List<AttrGroupRelationVo> vos);
}


AttrGroupService.java

package com.xd.cubemall.product.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.product.entity.AttrGroupEntity;

import java.util.Map;

/**
 * 属性分组表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
public interface AttrGroupService extends IService<AttrGroupEntity> {

    PageUtils queryPage(Map<String, Object> params);

    PageUtils queryPage(Map<String, Object> params, Long categoryId);
}


AttrService.java

package com.xd.cubemall.product.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.product.entity.AttrEntity;
import com.xd.cubemall.product.vo.AttrGroupRelationVo;
import com.xd.cubemall.product.vo.AttrRespVo;
import com.xd.cubemall.product.vo.AttrVo;

import java.util.List;
import java.util.Map;

/**
 * 属性表
 *
 * @author xuedong
 * @email email@gmail.com
 * @date 2024-08-13 01:36:04
 */
public interface AttrService extends IService<AttrEntity> {

    PageUtils queryPage(Map<String, Object> params);

    void saveAttr(AttrVo attrVo);

    PageUtils queryBaseAttrPage(Map<String, Object> params, Long categoryId, String attrType);

    AttrRespVo getAttrInfo(Long id);

    void updateAttr(AttrVo attrVo);

    List<AttrEntity> getRelationAttr(Long attrGroupId);

    void deleteRelation(AttrGroupRelationVo[] vos);

    PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId);
}


impl

AttrAttrgroupRelationServiceImpl.java

package com.xd.cubemall.product.service.impl;

import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.Query;
import com.xd.cubemall.product.vo.AttrGroupRelationVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;



import com.xd.cubemall.product.dao.AttrAttrgroupRelationDao;
import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.xd.cubemall.product.service.AttrAttrgroupRelationService;


@Service("attrAttrgroupRelationService")
public class AttrAttrgroupRelationServiceImpl extends ServiceImpl<AttrAttrgroupRelationDao, AttrAttrgroupRelationEntity> implements AttrAttrgroupRelationService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrAttrgroupRelationEntity> page = this.page(
                new Query<AttrAttrgroupRelationEntity>().getPage(params),
                new QueryWrapper<AttrAttrgroupRelationEntity>()
        );

        return new PageUtils(page);
    }


    /**
     * 添加属性与属性分组的关联关系
     * @param vos
     */
    @Override
    public void saveBatch(List<AttrGroupRelationVo> vos) {
        List<AttrAttrgroupRelationEntity> collect = vos.stream().map(attrGroupRelationVo -> {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);
            return attrAttrgroupRelationEntity;
        }).collect(Collectors.toList());
        this.saveBatch(collect);
    }
}

AttrGroupServiceImpl.java

package com.xd.cubemall.product.service.impl;

import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.Query;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.xd.cubemall.product.dao.AttrGroupDao;
import com.xd.cubemall.product.entity.AttrGroupEntity;
import com.xd.cubemall.product.service.AttrGroupService;


@Service("attrGroupService")
public class AttrGroupServiceImpl extends ServiceImpl<AttrGroupDao, AttrGroupEntity> implements AttrGroupService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrGroupEntity> page = this.page(
                new Query<AttrGroupEntity>().getPage(params),
                new QueryWrapper<AttrGroupEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 获取指定分类下的所有属性分组列表
     * @param params
     * @param categoryId
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params, Long categoryId) {

        if(categoryId == 0){
            //没有点击任何的分类,查询所有属性分组信息
            IPage<AttrGroupEntity> page = this.page(
                    //分页条件
                    new Query<AttrGroupEntity>().getPage(params),
                    //查询条件(无)
                    new QueryWrapper<AttrGroupEntity>()
            );

            return new PageUtils(page);
        } else {
            //查询指定分类下的所有属性分组信息
            //SELECT * FROM `tb_attr_group` WHERE category_id=? AND (id=key or name like %key%)

            QueryWrapper<AttrGroupEntity> queryWrapper = new QueryWrapper<>();
            //查询条件1: category_id=?
            if (categoryId != 0){
                queryWrapper.eq("category_id", categoryId);
            }
            //查询条件2: AND (id=key or name like %key%)
            String key = (String) params.get("key");
            if (!StringUtils.isEmpty(key)){
                queryWrapper.and(qw->{
                    qw.eq("id",key).or().like("name",key);
                });
            }

            IPage<AttrGroupEntity> page = this.page(
                    //分页条件
                    new Query<AttrGroupEntity>().getPage(params),
                    //查询条件(queryWrapper)
                    queryWrapper
            );



            return new PageUtils(page);
        }


    }
}

AttrServiceImpl.java

package com.xd.cubemall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xd.cubemall.common.utils.PageUtils;
import com.xd.cubemall.common.utils.Query;
import com.xd.cubemall.product.dao.AttrAttrgroupRelationDao;
import com.xd.cubemall.product.dao.AttrGroupDao;
import com.xd.cubemall.product.dao.CategoryDao;
import com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity;
import com.xd.cubemall.product.entity.AttrGroupEntity;
import com.xd.cubemall.product.entity.CategoryEntity;
import com.xd.cubemall.product.service.CategoryService;
import com.xd.cubemall.product.vo.AttrGroupRelationVo;
import com.xd.cubemall.product.vo.AttrRespVo;
import com.xd.cubemall.product.vo.AttrVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.xd.cubemall.product.dao.AttrDao;
import com.xd.cubemall.product.entity.AttrEntity;
import com.xd.cubemall.product.service.AttrService;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;


    @Autowired
    private AttrGroupDao attrGroupDao;

    @Autowired
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }


    /**
     * 在attr表中保存基本属性信息,然后在关联表中保存关联信息
     * @param attrVo
     */
    @Override
    public void saveAttr(AttrVo attrVo) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attrVo, attrEntity);
        //保存基本属性数据
        this.save(attrEntity);
        //在AttrServiceImpl类中,this.save(attrEntity)这一行代码中的this关键字指的是当前对象的实例,即AttrServiceImpl的一个实例。在这里,this代表了正在执行代码的AttrServiceImpl类的对象。
        //
        //save方法是ServiceImpl类中的一个方法,该类是AttrServiceImpl的父类(通过extends ServiceImpl<AttrDao, AttrEntity>)。ServiceImpl类是MyBatis-Plus框架中提供的一个基础服务实现类,它封装了一些常用的CRUD(创建、读取、更新、删除)操作。save方法用于保存或插入一个新的实体到数据库中。
        //
        //因此,当你调用this.save(attrEntity)时,你实际上是在调用从ServiceImpl类继承来的save方法,将attrEntity对象保存到数据库中。这个方法会利用MyBatis-Plus提供的ORM(对象关系映射)功能,将AttrEntity对象的属性与数据库表中的列进行映射,并执行插入操作。


        //保存关联数据
        AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
        attrAttrgroupRelationEntity.setAttrId(attrEntity.getId());
        attrAttrgroupRelationEntity.setAttrGroupId(attrVo.getAttrGroupId());

        attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);
        
    }


    /**
     * 获取指定分类的所有基本属性列表
     *
     * @param params
     * @param categoryId
     * @param attrType
     * @return
     */
    @Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long categoryId, String attrType) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        //拼接查询的attrtype条件
        if("base".equals(attrType)){
            queryWrapper.eq("attr_type",1);
        } else if("sale".equals(attrType)){
            queryWrapper.eq("attr_type",0);
        }


        //拼接分类id
        if (categoryId != 0) {
            queryWrapper.eq("category_id", categoryId);
        }
        //拼接关键字查询 key
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            queryWrapper.and(wrapper -> {
                wrapper.eq("id", key).or().like("name",key);
            });
        }
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );

        //------获取所属分类名称-----获取所属分组名称--------
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> records = page.getRecords();
        List<AttrRespVo> respVos = records.stream().map(attrEntity -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            //1.封装基础属性内容
            BeanUtils.copyProperties(attrEntity,attrRespVo);
            //2.封装属性分组名称
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(
                    new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getId())
            );
            //根据attrAttrgroupRelationEntity 获取attrGroup
            if (attrAttrgroupRelationEntity != null) {
                AttrGroupEntity attrGroupEntity =  attrGroupDao.selectById(attrAttrgroupRelationEntity.getAttrGroupId());

                if (attrGroupEntity != null) {
                    attrRespVo.setGroupName(attrGroupEntity.getName());
                }

            }

            //3.封装分类名称
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCategoryId());
            if(categoryEntity != null) {
                attrRespVo.setCategoryName(categoryEntity.getName());
            }



            return attrRespVo;
        }).collect(Collectors.toList());

        pageUtils.setList(respVos);

        return pageUtils;
    }


    @Override
    public AttrRespVo getAttrInfo(Long id) {

        AttrRespVo attrRespVo = new AttrRespVo();
        AttrEntity attrEntity = this.getById(id);
        //attrEntity中的基本属性 拷贝到 attrRespVo
        BeanUtils.copyProperties(attrEntity,attrRespVo);
        //1.设置分组信息
        AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attrEntity.getId())
        );
        if (attrAttrgroupRelationEntity != null) {
            attrRespVo.setAttrGroupId(attrAttrgroupRelationEntity.getAttrGroupId());
            AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrAttrgroupRelationEntity.getAttrGroupId());
            if (attrGroupEntity != null) {
                attrRespVo.setGroupName(attrGroupEntity.getName());
            }
        }

        //2.设置分类路径
        Long[] categoryPath = categoryService.findCategoryPath(attrEntity.getCategoryId());
        attrRespVo.setCategoryPath(categoryPath);

        //3.设置分类名称
        CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCategoryId());
        if (categoryEntity != null) {
            attrRespVo.setCategoryName(categoryEntity.getName());
        }
        return attrRespVo;
    }

    /**
     * 基本属性的修改--提交操作
     * @param attrVo
     */
    @Override
    public void updateAttr(AttrVo attrVo) {
        AttrEntity attrEntity = new AttrEntity();
        //基本属性的对拷
        BeanUtils.copyProperties(attrVo,attrEntity);
        this.updateById(attrEntity);

        //修改属性分组关联
        AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
        attrAttrgroupRelationEntity.setAttrId(attrVo.getId());
        attrAttrgroupRelationEntity.setAttrGroupId(attrVo.getAttrGroupId());

        Integer count = attrAttrgroupRelationDao.selectCount(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrVo.getId())
        );
        if(count > 0){
            attrAttrgroupRelationDao.update(
              attrAttrgroupRelationEntity,
              new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attrVo.getId())
            );
        }else {
            attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);

        }
    }


    /**
     * 获取属性分组所关联的所有属性
     * @param attrGroupId
     * @return
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrGroupId) {
        //获取属性分组及属性关联关系
        List<AttrAttrgroupRelationEntity> entities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId)
        );

        //获取每个属性关联对象中的属性id
        List<Long> attrIds = entities.stream().map(attrAttrgroupRelationEntity -> {
            return attrAttrgroupRelationEntity.getAttrId();
        }).collect(Collectors.toList());




        //通过属性id 获取对应的 AttrEntity对象
        if (attrIds == null || attrIds.size() == 0) {
            return null;
        }

        List<AttrEntity> attrEntities = this.listByIds(attrIds);
        return attrEntities;
    }


    /**
     * 在属性分组中删除所关联的属性
     * @param vos
     */
    @Override
    public void deleteRelation(AttrGroupRelationVo[] vos) {
        List<AttrAttrgroupRelationEntity> relationEntities = Arrays.asList(vos).stream().map(attrGroupRelationVo -> {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();

            BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);
            return attrAttrgroupRelationEntity;
        }).collect(Collectors.toList());
        //批量移除属性分组和 属性的关联关系
        attrAttrgroupRelationDao.deleteBatch(relationEntities);

    }


    /**
     * 获取属性分组中,当前分类下没有进行关联的所有属性
     * @param params
     * @param attrGroupId
     * @return
     */
    @Override
    public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId) {
        //1.获取当前分类下,所有分组已经关联的属性
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
        //1.1 获取当前属性分组所对应的 分类
        Integer categoryId = attrGroupEntity.getCategoryId();
        //1.2 获取当前分类下 所关联的所有属性分组
        List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectList(
                new QueryWrapper<AttrGroupEntity>().eq("category_id",categoryId)
        );
        //获取当前分类下,所有分组的ID
        List<Long> groupIds = attrGroupEntities.stream().map(attrGroup -> {
            return attrGroup.getId();
        }).collect(Collectors.toList());
        //从中间表 attr_attrgroup_relation中 获取 groupIds 所对应的属性
        List<AttrAttrgroupRelationEntity> entities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id",groupIds)
        );
        // attrIds 是 当前分类下,所有属性分组已经关联的 属性集合
        List<Long> attrIds = entities.stream().map(item -> {
            return item.getAttrId();
        }).collect(Collectors.toList());




        //2.获取当前分类下所有属性
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("category_id",categoryId).eq("attr_type",1);

        //3.移除已经关联的内容,剩下的就是未关联的属性
        if (attrIds != null && attrIds.size() > 0) {
            queryWrapper.notIn("id",attrIds);
        }

        String key = (String) params.get("key");
        if (StringUtils.isEmpty(key)) {
            queryWrapper.and(wrapper -> {
                wrapper.eq("id", key).or().like("name",key);
            });
        }

        IPage<AttrEntity> page =  this.page(new Query<AttrEntity>().getPage(params), queryWrapper);





        return new PageUtils(page);
    }
}

xml

AttrAttrgroupRelationDao.xml

<?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.xd.cubemall.product.dao.AttrAttrgroupRelationDao">

	<!-- 可根据自己的需求,是否要使用 -->
    <resultMap type="com.xd.cubemall.product.entity.AttrAttrgroupRelationEntity" id="attrAttrgroupRelationMap">
        <result property="id" column="id"/>
        <result property="attrId" column="attr_id"/>
        <result property="attrGroupId" column="attr_group_id"/>
        <result property="attrSort" column="attr_sort"/>
    </resultMap>
    <delete id="deleteBatch">
        DELETE FROM tb_attr_attrgroup_relation
        <where>
            <foreach collection="entities" item="item" separator=" or ">
                (attr_id=#{item.attrId} and attr_group_id=#{item.attrGroupId})
            </foreach>
        </where>

    </delete>


</mapper>

前端

attr-add-or-update.vue

<template>
  <el-dialog
    :title="!dataForm.id ? '新增' : '修改'"
    :close-on-click-modal="false"
    :visible.sync="visible"
    @closed="dialogClose"
  >
    <el-form :model="dataForm" :rules="dataRule" ref="dataForm" label-width="120px">
      <!--       @keyup.enter.native="dataFormSubmit()" -->
      <el-form-item label="属性名" prop="name">
        <el-input v-model="dataForm.name" placeholder="属性名"></el-input>
      </el-form-item>
      <el-form-item label="属性类型" prop="attrType">
        <el-select v-model="dataForm.attrType" placeholder="请选择">
          <el-option label="规格参数" :value="1"></el-option>
          <el-option label="销售属性" :value="0"></el-option>
        </el-select>
      </el-form-item>

      <el-form-item label="值类型" prop="valueType">
        <el-switch
          v-model="dataForm.valueType"
          active-text="允许多个值"
          inactive-text="只能单个值"
          active-color="#13ce66"
          inactive-color="#ff4949"
          :inactive-value="0"
          :active-value="1"
        ></el-switch>
      </el-form-item>
      <el-form-item label="可选值" prop="valueSelect">
        <!-- <el-input v-model="dataForm.valueSelect"></el-input> -->
        <el-select
          v-model="dataForm.valueSelect"
          multiple
          filterable
          allow-create
          placeholder="请输入内容"
        ></el-select>
      </el-form-item>
      <el-form-item label="属性图标" prop="icon">
        <el-input v-model="dataForm.icon" placeholder="属性图标"></el-input>
      </el-form-item>
      <el-form-item label="所属分类" prop="categoryId">
        <category-cascader :categoryPath.sync="categoryPath"></category-cascader>
      </el-form-item>
      <el-form-item label="所属分组" prop="attrGroupId" v-if="type == 1">
        <el-select ref="groupSelect" v-model="dataForm.attrGroupId" placeholder="请选择">
          <el-option
            v-for="item in attrGroups"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="可检索" prop="searchType" v-if="type == 1">
        <el-switch
          v-model="dataForm.searchType"
          active-color="#13ce66"
          inactive-color="#ff4949"
          :active-value="1"
          :inactive-value="0"
        ></el-switch>
      </el-form-item>
      <el-form-item label="快速展示" prop="showDesc" v-if="type == 1">
        <el-switch
          v-model="dataForm.showDesc"
          active-color="#13ce66"
          inactive-color="#ff4949"
          :active-value="1"
          :inactive-value="0"
        ></el-switch>
      </el-form-item>
      <el-form-item label="启用状态" prop="enable">
        <el-switch
          v-model="dataForm.enable"
          active-color="#13ce66"
          inactive-color="#ff4949"
          :active-value="1"
          :inactive-value="0"
        ></el-switch>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="visible = false">取消</el-button>
      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
    </span>
  </el-dialog>
</template>

<script>
import CategoryCascader from "../common/category-cascader";
export default {
  data() {
    return {
      visible: false,
      dataForm: {
        id: 0,
        name: "",
        searchType: 0,
        valueType: 1,
        icon: "",
        valueSelect: "",
        attrType: 1,
        enable: 1,
        categoryId: "",
        attrGroupId: "",
        showDesc: 0
      },
      categoryPath: [],
      attrGroups: [],
      dataRule: {
        name: [
          { required: true, message: "属性名不能为空", trigger: "blur" }
        ],
        searchType: [
          {
            required: true,
            message: "是否需要检索不能为空",
            trigger: "blur"
          }
        ],
       
        icon: [
          { required: true, message: "属性图标不能为空", trigger: "blur" }
        ],
        attrType: [
          {
            required: true,
            message: "属性类型不能为空",
            trigger: "blur"
          }
        ],
        enable: [
          {
            required: true,
            message: "启用状态不能为空",
            trigger: "blur"
          }
        ],
        categoryId: [
          {
            required: true,
            message: "需要选择正确的三级分类数据",
            trigger: "blur"
          }
        ],
        showDesc: [
          {
            required: true,
            message: "快速展示不能为空",
            trigger: "blur"
          }
        ]
      }
    };
  },
  props:{
    type:{
      type: Number,
      default: 1
    }
  },
  watch: {
    categoryPath(path) {
      //监听到路径变化需要查出这个三级分类的分组信息
      console.log("路径变了", path);
      this.attrGroups = [];
      this.dataForm.attrGroupId = "";
      this.dataForm.categoryId = path[path.length - 1];
      if (path && path.length == 3) {
        this.$http({
          url: this.$http.adornUrl(
            `/product/attrgroup/list/${path[path.length - 1]}`
          ),
          method: "get",
          params: this.$http.adornParams({ page: 1, limit: 10000000 })
        }).then(({ data }) => {
          if (data && data.code === 0) {
            this.attrGroups = data.page.list;
          } else {
            this.$message.error(data.msg);
          }
        });
      } else if (path.length == 0) {
        this.dataForm.categoryId = "";
      } else {
        this.$message.error("请选择正确的分类");
        this.dataForm.categoryId = "";
      }
    }
  },
  components: { CategoryCascader },
  methods: {
    init(id) {
      this.dataForm.id = id || 0;
      this.dataForm.attrType = this.type;
      this.visible = true;
      this.$nextTick(() => {
        this.$refs["dataForm"].resetFields();
        if (this.dataForm.id) {
          this.$http({
            url: this.$http.adornUrl(
              `/product/attr/info/${this.dataForm.id}`
            ),
            method: "get",
            params: this.$http.adornParams()
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.dataForm.name = data.attr.name;
              this.dataForm.searchType = data.attr.searchType;
              this.dataForm.valueType = data.attr.valueType;
              this.dataForm.icon = data.attr.icon;
              this.dataForm.valueSelect = data.attr.valueSelect.split(";");
              this.dataForm.attrType = data.attr.attrType;
              this.dataForm.enable = data.attr.enable;
              this.dataForm.categoryId = data.attr.categoryId;
              this.dataForm.showDesc = data.attr.showDesc;
              //attrGroupId
              //categoryPath
              this.categoryPath = data.attr.categoryPath;
              this.$nextTick(() => {
                this.dataForm.attrGroupId = data.attr.attrGroupId;
              });
            }
          });
        }
      });
    },
    // 表单提交
    dataFormSubmit() {
      this.$refs["dataForm"].validate(valid => {
        if (valid) {
          this.$http({
            url: this.$http.adornUrl(
              `/product/attr/${!this.dataForm.id ? "save" : "update"}`
            ),
            method: "post",
            data: this.$http.adornData({
              id: this.dataForm.id || undefined,
              name: this.dataForm.name,
              searchType: this.dataForm.searchType,
              valueType: this.dataForm.valueType,
              icon: this.dataForm.icon,
              valueSelect: this.dataForm.valueSelect.join(";"),
              attrType: this.dataForm.attrType,
              enable: this.dataForm.enable,
              categoryId: this.dataForm.categoryId,
              attrGroupId: this.dataForm.attrGroupId,
              showDesc: this.dataForm.showDesc
            })
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.$message({
                message: "操作成功",
                type: "success",
                duration: 1500,
                onClose: () => {
                  this.visible = false;
                  this.$emit("refreshDataList");
                }
              });
            } else {
              this.$message.error(data.msg);
            }
          });
        }
      });
    },
    //dialogClose
    dialogClose() {
      this.categoryPath = [];
    }
  }
};
</script>


attr-group-relation.vue

<template>
  <div>
    <el-dialog :close-on-click-modal="false" :visible.sync="visible" @closed="dialogClose">
      <el-dialog width="40%" title="选择属性" :visible.sync="innerVisible" append-to-body>
        <div>
          <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
            <el-form-item>
              <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
            </el-form-item>
            <el-form-item>
              <el-button @click="getDataList()">查询</el-button>
            </el-form-item>
          </el-form>
          <el-table
            :data="dataList"
            border
            v-loading="dataListLoading"
            @selection-change="innerSelectionChangeHandle"
            style="width: 100%;"
          >
            <el-table-column type="selection" header-align="center" align="center"></el-table-column>
            <el-table-column prop="id" header-align="center" align="center" label="属性id"></el-table-column>
            <el-table-column prop="name" header-align="center" align="center" label="属性名"></el-table-column>
            <el-table-column prop="icon" header-align="center" align="center" label="属性图标"></el-table-column>
            <el-table-column prop="valueSelect" header-align="center" align="center" label="可选值列表"></el-table-column>
          </el-table>
          <el-pagination
            @size-change="sizeChangeHandle"
            @current-change="currentChangeHandle"
            :current-page="pageIndex"
            :page-sizes="[10, 20, 50, 100]"
            :page-size="pageSize"
            :total="totalPage"
            layout="total, sizes, prev, pager, next, jumper"
          ></el-pagination>
        </div>
        <div slot="footer" class="dialog-footer">
          <el-button @click="innerVisible = false">取 消</el-button>
          <el-button type="primary" @click="submitAddRealtion">确认新增</el-button>
        </div>
      </el-dialog>
      <el-row>
        <el-col :span="24">
          <el-button type="primary" @click="addRelation">新建关联</el-button>
          <el-button
            type="danger"
            @click="batchDeleteRelation"
            :disabled="dataListSelections.length <= 0"
          >批量删除</el-button>
          <!--  -->
          <el-table
            :data="relationAttrs"
            style="width: 100%"
            @selection-change="selectionChangeHandle"
            border
          >
            <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
            <el-table-column prop="id" label="属性ID"></el-table-column>
            <el-table-column prop="name" label="属性名"></el-table-column>
            <el-table-column prop="valueSelect" label="可选值">
              <template slot-scope="scope">
                <el-tooltip placement="top">
                  <div slot="content">
                    <span v-for="(i,index) in scope.row.valueSelect.split(';')" :key="index">
                      {{i}}
                      <br />
                    </span>
                  </div>
                  <el-tag>{{scope.row.valueSelect.split(";")[0]+" ..."}}</el-tag>
                </el-tooltip>
              </template>
            </el-table-column>
            <el-table-column fixed="right" header-align="center" align="center" label="操作">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="relationRemove(scope.row.id)">移除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    //这里存放数据
    return {
      attrGroupId: 0,
      visible: false,
      innerVisible: false,
      relationAttrs: [],
      dataListSelections: [],
      dataForm: {
        key: ""
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListLoading: false,
      innerdataListSelections: []
    };
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    innerSelectionChangeHandle(val) {
      this.innerdataListSelections = val;
    },
    addRelation() {
      this.getDataList();
      this.innerVisible = true;
    },
    batchDeleteRelation(val) {
      let postData = [];
      this.dataListSelections.forEach(item => {
        postData.push({ attrId: item.id, attrGroupId: this.attrGroupId });
      });
      this.$http({
        url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),
        method: "post",
        data: this.$http.adornData(postData, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({ type: "success", message: "删除成功" });
          this.init(this.attrGroupId);
        } else {
          this.$message({ type: "error", message: data.msg });
        }
      });
    },
    //移除关联
    relationRemove(attrId) {
      let data = [];

      data.push({ attrId:attrId, attrGroupId: this.attrGroupId });
      this.$http({
        url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),
        method: "post",
        data: this.$http.adornData(data, false)
      }).then(({ data }) => {
        if (data.code == 0) {
          this.$message({ type: "success", message: "删除成功" });
          this.init(this.attrGroupId);
        } else {
          this.$message({ type: "error", message: data.msg });
        }
      });
    },
    submitAddRealtion() {
      this.innerVisible = false;
      //准备数据
      console.log("准备新增的数据", this.innerdataListSelections);
      if (this.innerdataListSelections.length > 0) {
        let postData = [];
        this.innerdataListSelections.forEach(item => {
          postData.push({ attrId: item.id, attrGroupId: this.attrGroupId });
        });
        this.$http({
          url: this.$http.adornUrl("/product/attrgroup/attr/relation"),
          method: "post",
          data: this.$http.adornData(postData, false)
        }).then(({ data }) => {
          if (data.code == 0) {
            this.$message({ type: "success", message: "新增关联成功" });
          }
          this.$emit("refreshData");
          this.init(this.attrGroupId);
        });
      } else {
      }
    },
    init(id) {
      this.attrGroupId = id || 0;
      this.visible = true;
      this.$http({
        url: this.$http.adornUrl(
          "/product/attrgroup/" + this.attrGroupId + "/attr/relation"
        ),
        method: "get",
        params: this.$http.adornParams({})
      }).then(({ data }) => {
        this.relationAttrs = data.data;
      });
    },
    dialogClose() {},

    //========
    // 获取数据列表
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl(
          "/product/attrgroup/" + this.attrGroupId + "/noattr/relation"
        ),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    },
    // 每页数
    sizeChangeHandle(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    // 当前页
    currentChangeHandle(val) {
      this.pageIndex = val;
      this.getDataList();
    }
  }
};
</script>
<style scoped>
</style>



attrgroup-add-or-update.vue


<template>
  <el-dialog
    :title="!dataForm.id ? '新增' : '修改'"
    :close-on-click-modal="false"
    :visible.sync="visible"
    @closed="dialogClose"
  >
    <el-form
      :model="dataForm"
      :rules="dataRule"
      ref="dataForm"
      @keyup.enter.native="dataFormSubmit()"
      label-width="120px"
    >
      <el-form-item label="组名" prop="name">
        <el-input v-model="dataForm.name" placeholder="组名"></el-input>
      </el-form-item>
      <el-form-item label="排序" prop="sort">
        <el-input v-model="dataForm.sort" placeholder="排序"></el-input>
      </el-form-item>
      <el-form-item label="描述" prop="descript">
        <el-input v-model="dataForm.descript" placeholder="描述"></el-input>
      </el-form-item>
      <el-form-item label="组图标" prop="icon">
        <el-input v-model="dataForm.icon" placeholder="组图标"></el-input>
      </el-form-item>
      <el-form-item label="所属分类" prop="categoryId">
        <!-- <el-input v-model="dataForm.catelogId" placeholder="所属分类id"></el-input> -->
        <category-cascader :categoryPath.sync="categoryPath"></category-cascader>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="visible = false">取消</el-button>
      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
    </span>
  </el-dialog>
</template>

<script>
import CategoryCascader from '../common/category-cascader'
export default {
  data() {
    return {
      props:{
        value:"id",
        label:"name",
        children:"childrens"
      },
      visible: false,
      categorys: [],
      categoryPath: [],
      dataForm: {
        id: 0,
        name: "",
        sort: "",
        descript: "",
        icon: "",
        categoryId: 0
      },
      dataRule: {
        name: [
          { required: true, message: "组名不能为空", trigger: "blur" }
        ],
        sort: [{ required: true, message: "排序不能为空", trigger: "blur" }],
        descript: [
          { required: true, message: "描述不能为空", trigger: "blur" }
        ],
        icon: [{ required: true, message: "组图标不能为空", trigger: "blur" }],
        categoryId: [
          { required: true, message: "所属分类id不能为空", trigger: "blur" }
        ]
      }
    };
  },
  components:{CategoryCascader},

  methods: {
    dialogClose(){
      this.categoryPath = [];
    },
    getCategorys(){
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({ data }) => {
        this.categorys = data.data;
      });
    },
    init(id) {
      this.dataForm.id = id || 0;
      this.visible = true;
      this.$nextTick(() => {
        this.$refs["dataForm"].resetFields();
        if (this.dataForm.id) {

          this.$http({
            url: this.$http.adornUrl(
              `/product/attrgroup/info/${this.dataForm.id}`
            ),
            method: "get",
            params: this.$http.adornParams()
          }).then(({ data }) => {

            if (data && data.code === 0) {

              this.dataForm.name = data.attrGroup.name;
              this.dataForm.sort = data.attrGroup.sort;
              this.dataForm.descript = data.attrGroup.descript;
              this.dataForm.icon = data.attrGroup.icon;
              this.dataForm.categoryId = data.attrGroup.categoryId;
              this.categoryPath =  data.attrGroup.categoryPath;
            }
          });
        }
      });
    },
    // 表单提交
    dataFormSubmit() {
      this.$refs["dataForm"].validate(valid => {
        if (valid) {
          this.$http({
            url: this.$http.adornUrl(
              `/product/attrgroup/${
                !this.dataForm.id ? "save" : "update"
              }`
            ),
            method: "post",
            data: this.$http.adornData({
              id: this.dataForm.id || undefined,
              name: this.dataForm.name,
              sort: this.dataForm.sort,
              descript: this.dataForm.descript,
              icon: this.dataForm.icon,
              categoryId: this.categoryPath[this.categoryPath.length-1]
            })
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.$message({
                message: "操作成功",
                type: "success",
                duration: 1500,
                onClose: () => {
                  this.visible = false;
                  this.$emit("refreshDataList");
                }
              });
            } else {
              this.$message.error(data.msg);
            }
          });
        }
      });
    }
  },
  created(){
    this.getCategorys();
  }
};
</script>


attrgroup.vue

<template>
  <el-row :gutter="20">
    <el-col :span="6">
      <category @tree-node-click="treenodeclick"></category>
    </el-col>
    <el-col :span="18">
      <div class="mod-config">
        <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
          <el-form-item>
            <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
          </el-form-item>
          <el-form-item>
            <el-button @click="getDataList()">查询</el-button>
            <el-button type="success" @click="getAllDataList()">查询全部</el-button>
            <el-button
              type="primary"
              @click="addOrUpdateHandle()"
            >新增</el-button>
            <el-button
              type="danger"
              @click="deleteHandle()"
              :disabled="dataListSelections.length <= 0"
            >批量删除</el-button>
          </el-form-item>
        </el-form>
        <el-table
          :data="dataList"
          border
          v-loading="dataListLoading"
          @selection-change="selectionChangeHandle"
          style="width: 100%;"
        >
          <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
          <el-table-column prop="id" header-align="center" align="center" label="分组id"></el-table-column>
          <el-table-column prop="name" header-align="center" align="center" label="组名"></el-table-column>
          <el-table-column prop="sort" header-align="center" align="center" label="排序"></el-table-column>
          <el-table-column prop="descript" header-align="center" align="center" label="描述"></el-table-column>
          <el-table-column prop="icon" header-align="center" align="center" label="组图标"></el-table-column>
          <el-table-column prop="categoryId" header-align="center" align="center" label="所属分类id"></el-table-column>
          <el-table-column
            fixed="right"
            header-align="center"
            align="center"
            width="150"
            label="操作"
          >
            <template slot-scope="scope">
              <el-button type="text" size="small" @click="relationHandle(scope.row.id)">关联</el-button>
              <el-button
                type="text"
                size="small"
                @click="addOrUpdateHandle(scope.row.id)"
              >修改</el-button>
              <el-button type="text" size="small" @click="deleteHandle(scope.row.id)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          @size-change="sizeChangeHandle"
          @current-change="currentChangeHandle"
          :current-page="pageIndex"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          :total="totalPage"
          layout="total, sizes, prev, pager, next, jumper"
        ></el-pagination>
        <!-- 弹窗, 新增 / 修改 -->
        <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>

        <!-- 修改关联关系 -->
        <relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update>
      </div>
    </el-col>
  </el-row>
</template>

<script>

import Category from "../common/category";
import AddOrUpdate from "./attrgroup-add-or-update";
import RelationUpdate from "./attr-group-relation";
export default {

  components: { Category, AddOrUpdate, RelationUpdate },
  props: {},
  data() {
    return {
      categoryId: 0,
      dataForm: {
        key: ""
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListLoading: false,
      dataListSelections: [],
      addOrUpdateVisible: false,
      relationVisible: false
    };
  },
  activated() {
    this.getDataList();
  },
  methods: {
    //处理分组与属性的关联
    relationHandle(groupId) {

      this.relationVisible = true;
      this.$nextTick(() => {
        this.$refs.relationUpdate.init(groupId);
      });
    },
    getAllDataList(){
      this.categoryId = 0;
      this.dataForm.key = "";
      this.getDataList();
    },
    // 获取数据列表
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl(`/product/attrgroup/list/${this.categoryId}`),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    },
    // 每页数
    sizeChangeHandle(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    // 当前页
    currentChangeHandle(val) {
      this.pageIndex = val;
      this.getDataList();
    },
    // 多选
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    treenodeclick(data,node,component){
        console.log('treenodeclick');
        if(node.level==3){
          this.categoryId = data.id; //设置分类ID 为当前节点ID
          this.getDataList();
        }
    },
    // 新增 / 修改
    addOrUpdateHandle(id) {
      this.addOrUpdateVisible = true;
      this.$nextTick(() => {
        this.$refs.addOrUpdate.init(id);
      });
    },
    // 删除
    deleteHandle(id) {
      var ids = id
        ? [id]
        : this.dataListSelections.map(item => {
            return item.attrGroupId;
          });
      this.$confirm(
        `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      ).then(() => {
        this.$http({
          url: this.$http.adornUrl("/product/attrgroup/delete"),
          method: "post",
          data: this.$http.adornData(ids, false)
        }).then(({ data }) => {
          if (data && data.code === 0) {
            this.$message({
              message: "操作成功",
              type: "success",
              duration: 1500,
              onClose: () => {
                this.getDataList();
              }
            });
          } else {
            this.$message.error(data.msg);
          }
        });
      });
    }
  }
};
</script>
<style scoped>
</style>



baseattr.vue

<template>
  <el-row :gutter="20">
    <el-col :span="6">
      <category @tree-node-click="treenodeclick"></category>
    </el-col>
    <el-col :span="18">
      <div class="mod-config">
        <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
          <el-form-item>
            <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
          </el-form-item>
          <el-form-item>
            <el-button @click="getDataList()">查询</el-button>
            <el-button type="success" @click="getAllDataList()">查询全部</el-button>
            <el-button
              type="primary"
              @click="addOrUpdateHandle()"
            >新增</el-button>
            <el-button
              v-if="isAuth('product:attr:delete')"
              type="danger"
              @click="deleteHandle()"
              :disabled="dataListSelections.length <= 0"
            >批量删除</el-button>
          </el-form-item>
        </el-form>
        <el-table
          :data="dataList"
          border
          v-loading="dataListLoading"
          @selection-change="selectionChangeHandle"
          style="width: 100%;"
        >
          <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
          <el-table-column prop="id" header-align="center" align="center" label="id"></el-table-column>
          <el-table-column prop="name" header-align="center" align="center" label="属性名"></el-table-column>
          <el-table-column
            v-if="attrtype == 1"
            prop="searchType"
            header-align="center"
            align="center"
            label="可检索"
          >
            <template slot-scope="scope">
              <i class="el-icon-success" v-if="scope.row.searchType==1"></i>
              <i class="el-icon-error" v-else></i>
            </template>
          </el-table-column>
          <el-table-column prop="valueType" header-align="center" align="center" label="值类型">
            <template slot-scope="scope">
              <el-tag type="success" v-if="scope.row.valueType==0">单选</el-tag>
              <el-tag v-else>多选</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="icon" header-align="center" align="center" label="图标"></el-table-column>
          <el-table-column prop="valueSelect" header-align="center" align="center" label="可选值">
            <template slot-scope="scope">
              <el-tooltip placement="top">
                <div slot="content">
                  <span v-for="(i,index) in scope.row.valueSelect.split(';')" :key="index">{{i}}<br/></span>
                </div>
                <el-tag>{{scope.row.valueSelect.split(";")[0]+" ..."}}</el-tag>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column prop="enable" header-align="center" align="center" label="启用">
            <template slot-scope="scope">
              <i class="el-icon-success" v-if="scope.row.enable==1"></i>
              <i class="el-icon-error" v-else></i>
            </template>
          </el-table-column>
          <el-table-column prop="categoryName" header-align="center" align="center" label="所属分类"></el-table-column>
          <el-table-column
            v-if="attrtype == 1"
            prop="groupName"
            header-align="center"
            align="center"
            label="所属分组"
          ></el-table-column>
          <el-table-column v-if="attrtype == 1" prop="showDesc" header-align="center" align="center" label="快速展示">
            <template slot-scope="scope">
              <i class="el-icon-success" v-if="scope.row.showDesc==1"></i>
              <i class="el-icon-error" v-else></i>
            </template>
          </el-table-column>
          <el-table-column
            fixed="right"
            header-align="center"
            align="center"
            width="150"
            label="操作"
          >
            <template slot-scope="scope">
              <el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.id)">修改</el-button>
              <el-button type="text" size="small" @click="deleteHandle(scope.row.id)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          @size-change="sizeChangeHandle"
          @current-change="currentChangeHandle"
          :current-page="pageIndex"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          :total="totalPage"
          layout="total, sizes, prev, pager, next, jumper"
        ></el-pagination>
        <!-- 弹窗, 新增 / 修改 -->
        <add-or-update
          :type="attrtype"
          v-if="addOrUpdateVisible"
          ref="addOrUpdate"
          @refreshDataList="getDataList"
        ></add-or-update>
      </div>
    </el-col>
  </el-row>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import Category from "../common/category";
import AddOrUpdate from "./attr-add-or-update";
export default {
  //import引入的组件需要注入到对象中才能使用
  components: { Category, AddOrUpdate },
  props: {
    attrtype: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      id: 0,
      type: 1,
      dataForm: {
        key: ""
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListLoading: false,
      dataListSelections: [],
      addOrUpdateVisible: false
    };
  },
  activated() {
    this.getDataList();
  },
  methods: {
    //感知树节点被点击
    treenodeclick(data, node, component) {
      if (node.level == 3) {
        this.id = data.id;
        this.getDataList(); //重新查询
      }
    },
    getAllDataList(){
      this.id = 0;
      this.dataForm.key = "";
      this.getDataList();
    },
    // 获取数据列表
    getDataList() {
      this.dataListLoading = true;
      let type = this.attrtype == 0 ? "sale" : "base";
      this.$http({
        url: this.$http.adornUrl(`/product/attr/${type}/list/${this.id}`),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    },
    // 每页数
    sizeChangeHandle(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    // 当前页
    currentChangeHandle(val) {
      this.pageIndex = val;
      this.getDataList();
    },
    // 多选
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    // 新增 / 修改
    addOrUpdateHandle(id) {
      this.addOrUpdateVisible = true;
      this.$nextTick(() => {
        this.$refs.addOrUpdate.init(id);
      });
    },
    // 删除
    deleteHandle(id) {
      var ids = id
        ? [id]
        : this.dataListSelections.map(item => {
            return item.id;
          });
      this.$confirm(
        `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      ).then(() => {
        this.$http({
          url: this.$http.adornUrl("/product/attr/delete"),
          method: "post",
          data: this.$http.adornData(ids, false)
        }).then(({ data }) => {
          if (data && data.code === 0) {
            this.$message({
              message: "操作成功",
              type: "success",
              duration: 1500,
              onClose: () => {
                this.getDataList();
              }
            });
          } else {
            this.$message.error(data.msg);
          }
        });
      });
    }
  }
};
</script>
<style scoped>
</style>



category.vue

<template>
  <div>
    <el-button type="danger" @click="batchDelete">批量删除</el-button>
    <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      show-checkbox
      node-key="id"
      :default-expanded-keys="expandedKey"
      ref="menuTree"
    >
       <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button
            v-if="node.level <=2"
            type="text"
            size="mini"
            @click="() => append(data)"
          >Append</el-button>
          <el-button type="text" size="mini" @click="edit(data)">edit</el-button>
          <el-button
            v-if="node.childNodes.length==0"
            type="text"
            size="mini"
            @click="() => remove(node, data)"
          >Delete</el-button>
        </span>
      </span>
    </el-tree>

    <el-dialog
      :title="title"
      :visible.sync="dialogVisible"
      width="30%"
      :close-on-click-modal="false"
    >
      <el-form :model="category">
        <el-form-item label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submitData">确 定</el-button>
      </span>
    </el-dialog>

  </div>
</template>

<script>


export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      pCid: [],
      draggable: false,
      updateNodes: [],
      maxLevel: 0,
      title: "",
      dialogType: "", //edit,add
      category: {
        name: "",
        parentId: 0,
        isShow: 1,
        isMenu: 0,
        seq: 0,
        templateId: 0,
        id: null
      },
      dialogVisible: false,
      menus: [],
      expandedKey: [],
      defaultProps: {
        children: "childrens",
        label: "name"
      }
    };
  },

  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({ data }) => {
        console.log("成功获取到菜单数据...", data.data);
        this.menus = data.data;
      });
    },

    edit(data) {
      console.log("要修改的数据", data);
      //设置对话框类型是编辑
      this.dialogType = "edit";
      //设置title名称
      this.title = "修改分类";
      //显示对话框
      this.dialogVisible = true;

      //根据当前id获取分类详细信息
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.id}`),
        method: "get"
      }).then(({ data }) => {
        //请求成功
        //回填分类信息,与添加逻辑不通点
        this.category.name = data.data.name;
        this.category.id = data.data.id;
        this.category.goodsNum = data.data.goodsNum;
        this.category.isMenu = data.data.isMenu;
        this.category.parentId = data.data.parentId;
        this.category.seq = data.data.seq;
        this.category.isShow = data.data.isShow;

      });
    },


    append(data) {
      console.log("append", data);

      //为了区分是添加还是修改
      this.dialogType = "add";
      //设置名称
      this.title = "添加分类";
      //显示添加对话框
      this.dialogVisible = true;
         //以下封装catgroy对象值
      this.category.parentId = data.id; //当前节点父id
      this.category.id = null;
      this.category.name = "";
      this.category.goodsNum = 0;
      this.category.isMenu = "";
      this.category.isShow = 1;
      this.category.templateId = 0;
      this.category.seq = 0;
    },

    submitData() {
      //添加分类
      if (this.dialogType == "add") {
        this.addCategory();
      }
      //编辑分类
      if (this.dialogType == "edit") {
        this.editCategory();
      }
    },
 //修改三级分类数据
    editCategory() {
      var { id, name, goodsNum, isMenu } = this.category; //设置分类名称
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData({ id, name, goodsNum, isMenu}, false) //添加修改参数
      }).then(({ data }) => {
        this.$message({
          message: "菜单修改成功",
          type: "success"
        });
        //关闭对话框
        this.dialogVisible = false;
        //更新最新的菜单列表
        this.getMenus();
        //设置默认打开行
        this.expandedKey = [this.category.parentId];
      });
    },

    addCategory() {
      console.log("提交的三级分类数据", this.category);
      this.$http({
        url: this.$http.adornUrl("/product/category/save"), //请求的url
        method: "post", //请求的方式
        data: this.$http.adornData(this.category, false) //请求封装的参数
      }).then(({ data }) => {
        this.$message({
          message: "菜单保存成功",
          type: "success"
        });
        //对话框设置为隐藏
        this.dialogVisible = false;
        //重新加载菜单列表
        this.getMenus();
        //设置默认展开
        this.expandedKey = [this.category.parentId];
      });
    },

    batchDelete() { //批量删除
      let ids = []; //封装参数ID集合
      let checkedNodes = this.$refs.menuTree.getCheckedNodes(); //通过判断checkbox是否被选中
      console.log("被选中的元素", checkedNodes);
      for (let i = 0; i < checkedNodes.length; i++) {
        ids.push(checkedNodes[i].id); //把选中checkbox id值添加的ids集合中
      }
      this.$confirm(`是否批量删除【${ids}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false)
          }).then(({ data }) => {
            this.$message({
              message: "菜单批量删除成功",
              type: "success"
            });
            //刷新菜单列表
            this.getMenus();
          });
        })
        .catch(() => {});
    },

    remove(node, data) { //单条删除
      var ids = [data.id]; //删除逻辑根据ID ,并且封装成数组
      this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"), //删除API url
            method: "post", //删除api ,请求方式
            data: this.$http.adornData(ids, false) //传入参数 ,id集合
          }).then(({ data }) => {
            this.$message({
              message: "菜单删除成功",
              type: "success"
            });
            //重新刷新当前的菜单
            this.getMenus();
            //设置需要默认展开的菜单,删除节点父节点
            this.expandedKey = [node.parent.data.id];
          });
        })
        .catch(() => {});

      console.log("remove", node, data);
    }


  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>



saleattr.vue


<template>
  <div>
      <base-attr :attrtype="0"></base-attr>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import BaseAttr from './baseattr'
export default {
  //import引入的组件需要注入到对象中才能使用
  components: {BaseAttr},
  props: {},
  data() {
    //这里存放数据
    return {};
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {},
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {},
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2201201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划算法专题(六):回文串问题

目录 1、回文子串&#xff08;"引子题"&#xff09; 1.1 算法原理 1.2 算法代码 2、最长回文子串 2.1 算法原理 2.2 算法代码 3、分割回文串 IV&#xff08;hard&#xff09; 3.1 算法原理 3.2 算法代码 4、分割字符串 II&#xff08;hard&#xff09; 4…

甲虫身体图像分割系统源码&数据集分享

甲虫身体图像分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientRepBiPAN&#xff06;yolov8-seg-C2f-FocusedLinearAttention等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challen…

C语言之扫雷小游戏(完整代码版)

说起扫雷游戏&#xff0c;这应该是很多人童年的回忆吧&#xff0c;中小学电脑课最常玩的必有扫雷游戏&#xff0c;那么大家知道它是如何开发出来的吗&#xff0c;扫雷游戏背后的原理是什么呢&#xff1f;今天就让我们一探究竟&#xff01; 扫雷游戏介绍 如下图&#xff0c;简…

从0开始linux(12)——命令行参数与环境变量

欢迎来到博主的专栏&#xff1a;从0开始linux 博主ID&#xff1a;代码小豪 文章目录 命令行参数环境变量 我们先打断一下关于进程的话题&#xff0c;博主先来介绍两个东西&#xff0c;分别是命令行参数与环境变量。那么有人看到这就会问了&#xff0c;难道说命令行参数和环境变…

Spring系列 循环依赖

文章目录 注入方式循环依赖的场景单例创建流程getSingletoncreateBeandoCreateBeancreateBeanInstance 循环依赖分析为什么都使用构造函数无法解决&#xff1f;为什么使用Autowired可以解决&#xff1f;为什么要添加到 earlySingletonObjects 缓存中&#xff1f;allowCircularR…

基于Kafka2.1解读Producer原理

文章目录 前言一、Kafka Producer是什么&#xff1f;二、主要组件1.Kafka Producer1.1 partitioner1.2 keySerializer1.3 valueSerializer1.4 accumulator1.5 sender 2.Sender2.1 acks2.2 clientinFlightBatches 3. Selector3.1 nioSelector3.2 channels 4. 全局总览 总结 前言…

【hot100-java】N 皇后

回溯篇 视频题解 真的裂开了&#xff0c;多看视频题解。 class Solution {public List<List<String>> solveNQueens(int n) {List<List<String>>retnew ArrayList<>();int []colnew int[n];boolean[] onPathnew boolean[n];boolean[] diag1ne…

(Linux和数据库)1.Linux操作系统和常用命令

了解Linux操作系统介绍 除了办公和玩游戏之外不用Linux&#xff0c;其他地方都要使用Linux&#xff08;it相关&#xff09; iOS的本质是unix&#xff08;unix是付费版本的操作系统&#xff09; unix和Linux之间很相似 Linux文件系统和目录 bin目录--放工具使用的 操作Linux远程…

双光吊舱图像采集详解!

一、图像采集 可见光图像采集&#xff1a; 使用高性能的可见光相机&#xff0c;通过镜头捕捉自然光或人工光源照射下的目标图像。 相机内部通常配备有先进的图像传感器&#xff0c;如CMOS或CCD&#xff0c;用于将光信号转换为电信号。 红外图像采集&#xff1a; 利用红外热…

【hot100-java】二叉树的最近公共祖先

二叉树篇 我觉得是比两个节点的深度&#xff0c;取min&#xff08;一种情况&#xff09; DFS解题。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ clas…

Unity/VS 消除不想要的黄色警告

方法一&#xff1a;单个消除 在要关闭的代码前一行写上#pragma warning disable 警告代码编码 在要关闭代码行下面一行写上#pragma warning restore 警告代码编码 精准的关闭指定地方引起的代码警告&#xff0c;不会过滤掉无辜的代码 #pragma warning disable 0162,1634HandleL…

JDBC: 连接池

文章目录 没有连接池的现状连接池解决现状问题的原理连接池好处常用连接池的介绍Druid连接池DRUID简介Druid常用的配置参数Druid连接池基本使用API介绍 案例代码 没有连接池的现状 通过下图来分析一下我们目前jdbc程序的结构。 以前使用的jdbc的缺点&#xff1a; 1、操作数据库…

户外打气泵方案软件设计开发

随着户外活动的普及和人们对便捷生活的需求&#xff0c;打气泵成为越来越多有车人士及爱好户外运动的人的装备之一。而打气泵的核心控制是它的芯片和软件方案&#xff0c;今天我们就介绍一下打气泵芯片软件方案的开发过程与技术要点。 打气泵方案的软件设计相较于硬件更具复杂性…

数据库——sql多表查询

当要在两个表&#xff08;或多个表&#xff09;中查找对应数据时&#xff0c;与普通的查询略有不同。本篇博文用于介绍基本的多表查询的方法。 为方便展示&#xff0c;本篇建了两个数据库表“学生表”和“班级表”作为例子 其中&#xff0c;在“学生表”中&#xff0c;cid标签…

RT-DETR改进策略:BackBone改进|CAFormer在RT-DETR中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入RT-DETR模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(动态新增、修改等操作)

SpringBoot教程&#xff08;二十四&#xff09; | SpringBoot实现分布式定时任务之Quartz&#xff08;动态新增、修改等操作&#xff09; 前言数据库脚本创建需要被调度的方法创建相关实体类创建业务层接口创建业务层实现类控制层类测试结果 前言 我这边的SpringBoot的版本为2…

Android 防止截屏和录屏

通过给当前的window对象设置标记WindowManager.LayoutParams.FLAG_SECURE来防止截屏和录屏 protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 防止截屏getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManage…

vscode配置:启用括号对着色

想要的效果&#xff1a;启用括号对着色&#xff0c;在大括号之间用折线表示&#xff0c;看起来会更加直观方便&#xff0c;例如在less中嵌套层级比较多时&#xff0c;大括号的层级不容易看清楚&#xff0c;做了这个配置会更好一些。 vscode安装扩展插件&#xff1a;Bracket P…

Spring Boot学习资源库:Spring生态的精华

摘 要 社会的进步&#xff0c;教育行业发展迅速&#xff0c;人们对教育越来越重视&#xff0c;在当今网络普及的情况下&#xff0c;教学模式也开始逐渐网络化&#xff0c;各大高校开始网络教学模式。 本文研究的教学资源库系统基于Springboot框架&#xff0c;采用Java技术和MYS…

Linux deepin系统通过编辑crontab来设置定时任务---定时关机

在Linux系统中&#xff0c;crontab 是用来设置周期性被执行的指令的守护进程。通过编辑 crontab&#xff0c;您可以安排定时任务&#xff0c;比如定时关机、定时备份文件、定时运行脚本等。以下是如何编辑 crontab 来设置定时任务的步骤&#xff1a; 打开终端&#xff1a;您可以…