电商项目7:商品模块-属性分组

1、 数据库设计

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

将菜单的sql在admin 数据库执行

/*
SQLyog Ultimate v11.25 (64 bit)
MySQL - 5.7.27 : Database - gulimall_admin
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`gulimall_admin` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;

USE `gulimall_admin`;

/*Table structure for table `sys_menu` */

DROP TABLE IF EXISTS `sys_menu`;

CREATE TABLE `sys_menu` (
  `menu_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
  `name` varchar(50) DEFAULT NULL COMMENT '菜单名称',
  `url` varchar(200) DEFAULT NULL COMMENT '菜单URL',
  `perms` varchar(500) DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
  `type` int(11) DEFAULT NULL COMMENT '类型   0:目录   1:菜单   2:按钮',
  `icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
  `order_num` int(11) DEFAULT NULL COMMENT '排序',
  PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8mb4 COMMENT='菜单管理';

/*Data for the table `sys_menu` */

insert  into `sys_menu`(`menu_id`,`parent_id`,`name`,`url`,`perms`,`type`,`icon`,`order_num`) values (1,0,'系统管理',NULL,NULL,0,'system',0),(2,1,'管理员列表','sys/user',NULL,1,'admin',1),(3,1,'角色管理','sys/role',NULL,1,'role',2),(4,1,'菜单管理','sys/menu',NULL,1,'menu',3),(5,1,'SQL监控','http://localhost:8080/renren-fast/druid/sql.html',NULL,1,'sql',4),(6,1,'定时任务','job/schedule',NULL,1,'job',5),(7,6,'查看',NULL,'sys:schedule:list,sys:schedule:info',2,NULL,0),(8,6,'新增',NULL,'sys:schedule:save',2,NULL,0),(9,6,'修改',NULL,'sys:schedule:update',2,NULL,0),(10,6,'删除',NULL,'sys:schedule:delete',2,NULL,0),(11,6,'暂停',NULL,'sys:schedule:pause',2,NULL,0),(12,6,'恢复',NULL,'sys:schedule:resume',2,NULL,0),(13,6,'立即执行',NULL,'sys:schedule:run',2,NULL,0),(14,6,'日志列表',NULL,'sys:schedule:log',2,NULL,0),(15,2,'查看',NULL,'sys:user:list,sys:user:info',2,NULL,0),(16,2,'新增',NULL,'sys:user:save,sys:role:select',2,NULL,0),(17,2,'修改',NULL,'sys:user:update,sys:role:select',2,NULL,0),(18,2,'删除',NULL,'sys:user:delete',2,NULL,0),(19,3,'查看',NULL,'sys:role:list,sys:role:info',2,NULL,0),(20,3,'新增',NULL,'sys:role:save,sys:menu:list',2,NULL,0),(21,3,'修改',NULL,'sys:role:update,sys:menu:list',2,NULL,0),(22,3,'删除',NULL,'sys:role:delete',2,NULL,0),(23,4,'查看',NULL,'sys:menu:list,sys:menu:info',2,NULL,0),(24,4,'新增',NULL,'sys:menu:save,sys:menu:select',2,NULL,0),(25,4,'修改',NULL,'sys:menu:update,sys:menu:select',2,NULL,0),(26,4,'删除',NULL,'sys:menu:delete',2,NULL,0),(27,1,'参数管理','sys/config','sys:config:list,sys:config:info,sys:config:save,sys:config:update,sys:config:delete',1,'config',6),(29,1,'系统日志','sys/log','sys:log:list',1,'log',7),(30,1,'文件上传','oss/oss','sys:oss:all',1,'oss',6),(31,0,'商品系统','','',0,'editor',0),(32,31,'分类维护','product/category','',1,'menu',0),(34,31,'品牌管理','product/brand','',1,'editor',0),(37,31,'平台属性','','',0,'system',0),(38,37,'属性分组','product/attrgroup','',1,'tubiao',0),(39,37,'规格参数','product/baseattr','',1,'log',0),(40,37,'销售属性','product/saleattr','',1,'zonghe',0),(41,31,'商品维护','product/spu','',0,'zonghe',0),(42,0,'优惠营销','','',0,'mudedi',0),(43,0,'库存系统','','',0,'shouye',0),(44,0,'订单系统','','',0,'config',0),(45,0,'用户系统','','',0,'admin',0),(46,0,'内容管理','','',0,'sousuo',0),(47,42,'优惠券管理','coupon/coupon','',1,'zhedie',0),(48,42,'发放记录','coupon/history','',1,'sql',0),(49,42,'专题活动','coupon/subject','',1,'tixing',0),(50,42,'秒杀活动','coupon/seckill','',1,'daohang',0),(51,42,'积分维护','coupon/bounds','',1,'geren',0),(52,42,'满减折扣','coupon/full','',1,'shoucang',0),(53,43,'仓库维护','ware/wareinfo','',1,'shouye',0),(54,43,'库存工作单','ware/task','',1,'log',0),(55,43,'商品库存','ware/sku','',1,'jiesuo',0),(56,44,'订单查询','order/order','',1,'zhedie',0),(57,44,'退货单处理','order/return','',1,'shanchu',0),(58,44,'等级规则','order/settings','',1,'system',0),(59,44,'支付流水查询','order/payment','',1,'job',0),(60,44,'退款流水查询','order/refund','',1,'mudedi',0),(61,45,'会员列表','member/member','',1,'geren',0),(62,45,'会员等级','member/level','',1,'tubiao',0),(63,45,'积分变化','member/growth','',1,'bianji',0),(64,45,'统计信息','member/statistics','',1,'sql',0),(65,46,'首页推荐','content/index','',1,'shouye',0),(66,46,'分类热门','content/category','',1,'zhedie',0),(67,46,'评论管理','content/comments','',1,'pinglun',0),(68,41,'spu管理','product/spu','',1,'config',0),(69,41,'发布商品','product/spuadd','',1,'bianji',0),(70,43,'采购单维护','','',0,'tubiao',0),(71,70,'采购需求','ware/purchaseitem','',1,'editor',0),(72,70,'采购单','ware/purchase','',1,'menu',0),(73,41,'商品管理','product/manager','',1,'zonghe',0),(74,42,'会员价格','coupon/memberprice','',1,'admin',0),(75,42,'每日秒杀','coupon/seckillsession','',1,'job',0);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;


然后后端工程就有了这些标签了
在这里插入图片描述

所有的前端和后端交互的接口文档地址:
https://easydoc.net/s/78237135/ZUqEdvA4/hKJTcbfd

在这里插入图片描述

2、前端代码编写

1、modules下新建一个common文件夹(抽取三级分类组件、因为很多菜单用得着)
在这里插入图片描述
2、新建category.vue

<template>
<div></div>
</template>

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

export default {
//import 引入的组件需要注入到对象中才能使用
components: {},
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>

在这里插入图片描述

前端应该有一个attrgroup.vue文件
在这里插入图片描述
同样用vue模板生成代码

attrgroup.vue使用elementui的layout布局
在这里插入图片描述

<template>
  <el-row :gutter="20">
    <el-col :span="6"><div class="grid-content bg-purple"></div>菜单</el-col>
    <el-col :span="18"><div class="grid-content bg-purple"></div>表格</el-col>
  </el-row>
</template>

前端想做这种布局效果
在这里插入图片描述

2.1、抽取公共部分组件:树形结构

1、将product的category.vue里的el tree搬过来到common的category.vue放到template标签里

<el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      show-checkbox
      node-key="catId"
      :default-expanded-keys="expandKey"
      :draggable="draggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
      ref="menuTree"
    >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button
            v-if="node.level == 1 || 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>

2、去掉span标签的内容,去掉拖拽功能,默认展示节点等功能
最终template标签剩下这个

<template>
  <el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree">
  </el-tree>
</template>

3、复制data里的return声明

 return {
      draggable: false,
      pcid:[],
      updateNode: [],
      category: {
        name: "",
        parentCid: null,
        catLevel: null,
        showStatus: 1,
        sort: null,
        icon: "",
        productUnit: "",
        catId: null,
        expandId: null,
      },
      dialogVisible: false,
      dialogType: "",
      title: "",
      menus: [],
      expandKey: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
      maxLevel: 0,
    };

拖拽功能的数据全部删除

return {
      menus: [],
      expandKey: [],
      defaultProps: {
        children: "children",
        label: "name",
      },
    };

4、复制方法getMenus()

 getMenu() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl("/product/category/tree"),
        method: "get",
      }).then((data) => {
        let data1 = data.data.data;
        this.menus = data1;
      });
    },

5、在生命周期创建时发起请求

 created() {
    this.getMenu();
  },

6、attrgroup.vue引用它
在script里引入组件

import Category from '../common/category.vue'

将组件注册进components

在这里插入图片描述

在菜单的位置直接使用该组件
在这里插入图片描述

看页面效果
在这里插入图片描述

2.2、表格部分

1、将attrgroup.vue逆向生成的代码部分复制整个div到template

 <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 v-if="isAuth('product:attrgroup:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
        <el-button v-if="isAuth('product:attrgroup: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="attrGroupId"
        header-align="center"
        align="center"
        label="分组id">
      </el-table-column>
      <el-table-column
        prop="attrGroupName"
        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="catelogId"
        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="addOrUpdateHandle(scope.row.attrGroupId)">修改</el-button>
          <el-button type="text" size="small" @click="deleteHandle(scope.row.attrGroupId)">删除</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>
  </div>

2、将data复制替换

 data () {
      return {
        dataForm: {
          key: ''
        },
        dataList: [],
        pageIndex: 1,
        pageSize: 10,
        totalPage: 0,
        dataListLoading: false,
        dataListSelections: [],
        addOrUpdateVisible: false
      }
    },

3、将接下来的部分也替换

activated () {
      this.getDataList()
    },
    methods: {
      // 获取数据列表
      getDataList () {
        this.dataListLoading = true
        this.$http({
          url: this.$http.adornUrl('/product/attrgroup/list'),
          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.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)
            }
          })
        })
      }
    }

4、导入组件
在这里插入图片描述
5、将逆向工程成的attrgroup-add-or-update.vue放置当前文件夹内

看页面效果
在这里插入图片描述

2.3、父子组件传递事件

在这里插入图片描述
category为子组件,attrgroup为父组件

绑定单击事件
在这里插入图片描述
在common的category里绑定
在这里插入图片描述

nodeClick(data,node,component){
        console.log("当前点击的节点信息:",data,node,component);  
    },

在这里插入图片描述
###向父组件发送事件

 // 向父组件发送事件
        this.$emit("tree-node-click",data,node,component);

在这里插入图片描述

###父组件接收
回到attrgroup.vue

 <el-col :span="6"><div class="grid-content bg-purple"></div>
        <category @tree-node-click="treenodeClick"></category>
    </el-col>

在这里插入图片描述

  //感知子组件传递的事件
        treenodeClick(data,node,component){
            console.log("子组件的category被点击:",data,node,component);
            console.log("被点击的子组件id是:",data.catId);
        },

在这里插入图片描述

2.4、获取分类属性分组(接后端)

在这里插入图片描述
在这里插入图片描述
当点击三级分类才查询分组,点击一级和二级分类不用查询分组

 //感知子组件传递的事件
    treenodeClick(data, node, component) {
      console.log("子组件的category被点击:", data, node, component);
      console.log("被点击的子组件id是:", data.catId);
      // 当是三级分类时给catId赋值
      if (node.level == 3) {
        this.catId = data.catId;
        // 再次调用获取数据列表
        this.getDataList();
      }

    },

在这里插入图片描述

因为没数据所以可以造点数据
在这里插入图片描述

在这里插入图片描述

测试模糊查询
在这里插入图片描述

在这里插入图片描述

2.5、前端cascader级联选择器

在这里插入图片描述
1、找到attr-group-add-or-update.vue,将所属分类id换成dataForm.catelogId

    <el-form-item label="所属分类id" prop="catelogId">
        <!--  <el-input v-model="dataForm.catelogId" placeholder="所属分类id"></el-input> -->
         <el-cascader
    v-model="dataForm.catelogId"
    :options="categorys"></el-cascader>
      </el-form-item>

2、attr-group-add-or-update.vue 写一个方法

 getCategorys(){
      this.$http({
        url: this.$http.adornUrl("/product/category/tree"),
        method: "get",
      }).then((data) => {
          this.categorys = data.data.data;
          console.log("获取到商品数据==》{}",this.categorys);
      });
    }

3、创建时调用,生命周期函数
在这里插入图片描述
4、cascoder级联
在这里插入图片描述

在这里插入图片描述

这时候效果就出来了,但是样式有点怪
在这里插入图片描述

但是选中后无选中后的颜色区分
在这里插入图片描述

在style中指定样式

<style scope>
  .el-cascader-node.in-active-path,
  .el-cascader-node.is-active,
  .el-cascader-node.is-selectable.in-checked-path {
    color: red;
  }
</style>

效果就出来了
在这里插入图片描述
但是最后没有数据
是因为我们只有3级菜单,但是最后一个children返回了空集合。需要后台解决

在这里插入图片描述

新增点击保存时。catelogId是传的数组。这里时有问题的。只传最终的三级分类id
在这里插入图片描述
这时候只用取数组中最后一个值传给后端即可
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3、后端代码编写

3.1、获取分类属性分组

在这里插入图片描述

前端的key查询其实是多字段精确或模糊匹配
在这里插入图片描述

AttrGroupController

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

AttrGroupService

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

AttrGroupServiceImpl

 @Override
    public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
        // 当前端的catelogId为0,没传的时候,
        if (catelogId == 0){
            return this.queryPage(params);
        }
        QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<AttrGroupEntity>().eq("catelog_id",catelogId);
        // 当前端传了key
        String key = (String)params.get("key");
        if (!StringUtils.isEmpty(key)){
            // select * from pms_attr_group where catelog_id = ? and (attr_gruop_id = ? or attr_group_name like %%)
           wrapper.and((obj)->{
                obj.eq("attr_group_id",key).or().like("attr_group_name",key);
           });
        }
        IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params),wrapper);
        return new PageUtils(page);
    }

在这里插入图片描述

在这里插入图片描述
sql语句正确,调整前端代码

3.2、新增商品分组(接前端2.5)

商品三级分类获取后,需要将children里面为空的不返回前端
实体类加一注解即可

@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<CategoryEntity> children;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值