通过pid转到前台_猿实战13——实现你没听说过的前台类目

猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是问题。想要一起实战吗?关注公号,获取基础代码,动手实战吧。

上几个章节,猿人君教会了你实现了属性/属性值和后台类目的绑定关系,今天,猿人君就带你来实现前台类目。

为什么会有前台类目

为了方便运营,在电商系统中,类目分为前台类目和后台类目。如果你经常网购,你会发现一个比较有意思的事情。鼠标移动到一级类目,会展示二级类目,点击一级二级类目,会跳转到对应的频道页面(不过做得大了都是分站,我们先考虑业务),点击三级类目会出发搜索的功能。

这些在之前的设计文章猿设计5——真电商之颠覆你的类目认知中已经讲述过了,这里就不再赘述了。

功能概览

前台类目,从某种程度上说,肩负了部分站点的导航以及内容组织的职责,要完成这一职责,我们可以先来看看需要实现的功能。

cc5cecde7c61e74486e782f3eadc0339.png

ee5a1d902de81531015d00b145e94d36.png

6335850bac29d7b4b5c11ac30f8ab75f.png

5fdbac98054bcd251916e6a1ba3e495a.png

4eb0bc33d91cae9bced99f9c393d116b.png

在前台类目模块中,系统体现了前台类目的层级关系,每一级类目都有对应的列表、新增/编辑功能。在一级类目中可以维护广告牌、在三级类目中,重点维护前后台类目的关系(以上本章节暂不讨论)。

数据库设计

根据之前的前台类目设计文章,我们很清楚的获知了前台类目的一些特征,我们根据之前的设计,将这些设计落地为数据库的物理设计,大家可以看一下(本章节仅讲述前台类目的实现)。

7953897aaaf637158dbed3561aa34907.png

就类目而言,类目就像是一棵树,每一级类目都有可能有下一级类目,像这种特性,在数据库的设计上,是一种典型的自关联结构。但是类目用于检索时,往往伴随着层级关系的查找,比如提取某一级类目的信息。所以,我们在设计时,给予了一个level字段,用于方便提取固定层级的信息。

由于每一级维护的信息可能不同,所以在数据库设计上,我们做了一个整合,每一条行记录的信息是一二三级所有信息的集合,事实上,不同的层级只涉及部分字段内容,这种设计,也是一种常见的设计。

前台类目整体前端

类目的层级维护,从功能上讲,依然是一种整体和部分的关系,出于业务的考虑,在规模不是特别庞大的情况下,三级已经足够支撑你的运营。我们可以参考下之前的实现思路——将一级类目、二级类目、三级类目分别定义成小的组件。最后,由一个view来组织和整合它们就好了。

  
"fnCategoryDiv">
if="oneCategoryShow"> "frontDeskCategoryOneSearch" @lookSubordinate="lookOneSubordinate" />
if="twoCategoryShow"> "frontDeskCategoryTwoSearch" :pid="parentId" :pname="parentName" @lookSubordinate="lookTwoSubordinate" @returnBack="returnTwoBack" />
if="threeCategoryShow"> "frontDeskCategoryThreeSearch" :pid="parentId" :pname="parentName" @returnBack="returnThreeBack" />
import frontDeskCategoryOneSearch from '@/components/productManage/frontDeskCategoryOneSearch'import frontDeskCategoryTwoSearch from '@/components/productManage/frontDeskCategoryTwoSearch'import frontDeskCategoryThreeSearch from '@/components/productManage/frontDeskCategoryThreeSearch'export default { components: { frontDeskCategoryOneSearch, frontDeskCategoryTwoSearch, frontDeskCategoryThreeSearch }, data() { return { // 一级类目 oneCategoryShow: false, // 二级类目 twoCategoryShow: false, // 三级类目 threeCategoryShow: false, parentId: 0, parentName: '', catOneId: 0 } }, created() { // 显示一级类目 this.oneCategoryShow = true }, methods: { // 二级回退 returnTwoBack() { // 一级二级三级类目显示设置 this.oneCategoryShow = true this.twoCategoryShow = false this.threeCategoryShow = false }, // 三级回退 returnThreeBack(pid, pname) { // 一级二级三级类目显示设置 this.oneCategoryShow = false this.twoCategoryShow = true this.threeCategoryShow = false this.parentId = this.catOneId this.parentName = pname console.log(this.parentId) }, // 一级查看下级类目 lookOneSubordinate(row) { // 一级二级三级类目显示设置 this.oneCategoryShow = false this.twoCategoryShow = true this.threeCategoryShow = false this.parentId = row.fnCategoryId this.parentName = row.fnCategoryName this.catOneId = row.fnCategoryId }, // 二级查看下级类目 lookTwoSubordinate(row) { // 一级二级三级类目显示设置 this.oneCategoryShow = false this.twoCategoryShow = false this.threeCategoryShow = true this.parentId = row.fnCategoryId this.parentName = row.fnCategoryName } }}

值得注意的是,在查看下级和返回上级种,涉及组件之间的参数传递。您需要将,本级类目的ID作为父ID传入下级,而在下级返回上级的操作种,您需要将上上级的id作为父ID传入上一级列表页面(二级除外)。

关于父子组件之间的通信问题,在之前的文章中已经讲述过很多了,这里就不再赘述了。

前台类目后端实现

其实就前台类目的普通功能而言,目前来说相对简单,最主要的是建立父子关联这样一个自关联的概念。

由于之前已经给出了我们自己定义的代码生成器,属性组的实现也相对简单,考虑到篇幅问题,这一部分我们给出Controller层面的功能实现,service、和dao,还是希望你自行实现,在初学时期,多谢代码,对你熟悉掌握代码编写的技巧,是一个必不可少的环节。

/** * Copyright(c) 2004-2020 pangzi * com.pz.basic.mall.controller.product.fncategory.MallFnCategoryController.java */package com.pz.basic.mall.controller.product.fncategory; import com.pz.basic.mall.domain.base.Result;import com.pz.basic.mall.domain.product.category.query.QueryMallCategory;import com.pz.basic.mall.domain.product.category.vo.MallCategoryVo;import com.pz.basic.mall.domain.product.fncategory.MallFnBgCategoryRel;import com.pz.basic.mall.domain.product.fncategory.MallFnCategory;import com.pz.basic.mall.domain.product.fncategory.query.QueryMallFnBgCategoryRel;import com.pz.basic.mall.domain.product.fncategory.query.QueryMallFnCategory;import com.pz.basic.mall.service.product.category.MallCategoryService;import com.pz.basic.mall.service.product.fncategory.MallFnBgCategoryRelService;import com.pz.basic.mall.service.product.fncategory.MallFnCategoryService;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController; import java.util.List;  /** * * @author pangzi * @date 2020-06-22 20:47:27 * * */@RestController@RequestMapping("/fncategory")public class MallFnCategoryController {      private MallFnCategoryService mallFnCategoryService;      public void setMallFnCategoryService(MallFnCategoryService mallFnCategoryService) {        this.mallFnCategoryService = mallFnCategoryService;    }     /**     * 新增类目     * @param mallFnCategory     * @return     */    @RequestMapping("/addMallFnCategory")    public Result  addMallFnCategory(@RequestBody MallFnCategory mallFnCategory){        try{            return mallFnCategoryService.addMallFnCategory(mallFnCategory);        }catch(Exception e){            e.printStackTrace();            return new Result(false);        }    }     /**     * 根据ID查找类目     * @param id     * @return     */    @RequestMapping("/findMallFnCategoryById")    public  Result findMallFnCategoryById(Long id){        return mallFnCategoryService.getMallFnCategoryById(id.intValue());    }     /**     * 修改类目     * @param mallFnCategory     * @return     */    @RequestMapping("/updateMallFnCategory")    public Result updateMallFnCategory(@RequestBody MallFnCategory mallFnCategory){        try{            return  mallFnCategoryService.updateMallFnCategoryById(mallFnCategory);        }catch(Exception e){            e.printStackTrace();            return new Result(false);        }    }      /**     * 分页返回类目列表     * @param queryMallFnCategory     * @return     */    @RequestMapping("/findByPage")    public  Result> findByPage(@RequestBody QueryMallFnCategory queryMallFnCategory){        return mallFnCategoryService.getMallFnCategorysByPage(queryMallFnCategory);    }}

后台类目前端实现

聊完了后端数据接口的事情,我们一起来看看前端实现的问题,考虑到大部分朋友前端并不是很熟悉,我们再讲讲后台类目前端API组件的封装。

我们先封装访问后端的数据接口:

// 前台类目 export function fetchFnCategoryList(query) {  return request({    url: '/fncategory/findByPage',    method: 'post',    data: query  })} export function createMallFnCategory(data) {  return request({    url: '/fncategory/addMallFnCategory',    method: 'post',    data  })} export function updateMallFnCategory(data) {  return request({    url: '/fncategory/updateMallFnCategory',    method: 'post',    data  })}

考虑到之前有朋友说页面编写起来实在困难,在这里, 为了让你更好的掌握前台类目的内容,这次将一二三级的前台页面都给到你。不过猿人君还是希望你尽量自己编码。不然,你真的很难掌握开发技巧。

一级前台类目

<template>  <div id="frontDeskCategoryOneSearchDiv">    <div>      <el-form ref="listQuery" :model="listQuery" :inline="true">        <el-form-item label="类目名称:" prop="fnCategoryNameLike">          <el-input v-model="listQuery.fnCategoryNameLike" placeholder="请输入类目名称" clearable />        el-form-item>        <el-form-item>          <el-button type="primary" icon="el-icon-search" @click="fetchData()">查询el-button>          <el-button type="primary" icon="el-icon-edit" style="float:right;margin-bottom:20px;" @click="addDate()">新增一级el-button>        el-form-item>      el-form>    div>        <div>      <el-table        ref="table"        v-loading="listLoading"        :data="list"        style="width: 100%"        border      >        <el-table-column label="类目ID">          <template slot-scope="scope">{{ scope.row.fnCategoryId }}template>        el-table-column>        <el-table-column label="类目名称">          <template slot-scope="scope">{{ scope.row.fnCategoryName }}template>        el-table-column>        <el-table-column label="父类目ID">          无        el-table-column>        <el-table-column label="类目级别">          一级类目        el-table-column>        <el-table-column label="排序">          <template slot-scope="scope">{{ scope.row.sortOrder }}template>        el-table-column>status        <el-table-column label="是否上架">          <template slot-scope="scope">{{ scope.row.status ==1?"上架":"下架" }}template>        el-table-column>        <el-table-column label="操作" width="260">          <template slot-scope="scope">            <el-button              type="primary"              size="mini"              @click="handleSubordinate(scope.row)"            >查看下级            el-button>            <el-button              type="primary"              size="mini"              @click="handleUpdate(scope.row)"            >修改            el-button>            <el-button              type="primary"              size="mini"              @click="handleAdvertisingBoard(scope.row)"            >广告牌            el-button>          template>        el-table-column>      el-table>    div>    <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.pageSize" @pagination="getList" />        <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">      <el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="120px" style="width: 320px; margin-left:50px;">        <el-form-item label="类目名称:" prop="fnCategoryName">          <el-input v-model="temp.fnCategoryName" placeholder="请输入类目中文名" />        el-form-item>        <el-form-item label="类目排序:" prop="sortOrder">          <el-input-number            v-model="temp.sortOrder"            :min="0"            :max="100"            placeholder="请输入类目排序"          />        el-form-item>        <el-form-item label="是否上柜:" prop="status">          <el-select v-model="temp.status" placeholder="请选择">            <el-option              v-for="(item,index) in valueList"              :key="index"              :label="item.label"              :value="item.value"            />          el-select>        el-form-item>        <el-form-item label="类目ICON:">          <div style="width:300%">            <el-upload              action="http://127.0.0.1:9201//upload/uploadFile?moudle=fncategory"              list-type="picture-card"              :on-preview="handlePictureCardPreview"              :on-remove="handleRemove"              :on-success="handleSuccess"              :file-list="fnCategoryFileList"            >              <i />            el-upload>            <el-dialog :visible.sync="dialogVisible">              <img width="100%" :src="dialogImageUrl" alt="">            el-dialog>          div>        el-form-item>      el-form>      <div slot="footer">        <el-button @click="dialogFormVisible = false">          取消        el-button>        <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">          确定        el-button>      div>    el-dialog>        <el-dialog title="广告牌" :visible.sync="dialogAdvertisingBoardVisible">      <el-form ref="dataFormAdvertisingBoard" :rules="billboardRules" :model="tempBillboard" label-position="right" label-width="120px" style="width: 320px; margin-left:50px;">        <el-form-item label="广告图片:" prop="picture">          <div style="width:300%">            <el-upload              action="http://127.0.0.1:9201//upload/uploadFile?moudle=fncategory/billboard"              list-type="picture-card"              :on-preview="handleBillboardPreview"              :on-remove="handleRemove"              :on-success="handleBillboardSuccess"              :file-list="fnCategoryBillboardFileList"            >              <i />            el-upload>            <el-dialog :visible.sync="dialogVisible">              <img width="100%" :src="billboardImageUrl" alt="">            el-dialog>          div>        el-form-item>        <el-form-item label="链接类型:" prop="type">          <el-radio v-model="tempBillboard.type" :label="1">单链接el-radio>          <el-radio v-model="tempBillboard.type" :label="2">多链接el-radio>        el-form-item>        <el-form-item label="跳转内容" prop="redirectArea">          <el-input            v-model="tempBillboard.redirectArea"            style="width: 200%;"            type="textarea"            :rows="3"            placeholder="请输入内容"          />        el-form-item>        <el-form-item label="广告牌状态:" prop="status">          <el-radio v-model="tempBillboard.status" :label="1">停用el-radio>          <el-radio v-model="tempBillboard.status" :label="2">启用el-radio>        el-form-item>      el-form>      <div slot="footer">        <el-button @click="dialogAdvertisingBoardVisible = false">          取消        el-button>        <el-button type="primary" @click="advertisingBoardVisibleClick">          确定        el-button>      div>    el-dialog>  div>template> <script>import Pagination from '@/components/Pagination' // secondary package based on el-paginationimport { fetchFnCategoryList, createMallFnCategory, updateMallFnCategory, fetchFnCategoryBillboardList, createMallFnCategoryBillboard, updateMallFnCategoryBillboard } from '@/api/product-manage'export default {  components: { Pagination },  data() {    return {      tempBillboard: {        id: undefined,        fnCategoryId: undefined,        // 链接类型        type: 1,        // map_area        redirectArea: '',        // 广告牌状态        status: 1,        imageUrl: ''      },      addBillboard: true,      billboardImageUrl: '',      //      dialogImageUrl: '',      dialogVisible: false,      //      dialogStatus: '',      // 弹框是否显示      dialogFormVisible: false,      // 广告牌弹框是否显示      dialogAdvertisingBoardVisible: false,      // 广告牌弹框校验规则      billboardRules: {        picture: [{ required: true, message: '请上传图片', trigger: 'blur' }],        redirectArea: [{ required: true, message: '请输入跳转内容', trigger: 'blur' }],        status: [{ required: true, message: '请选择是否上架', trigger: 'blur' }],        type: [{ required: true, message: '请选择连接类型', trigger: 'blur' }]      },      // 弹框校验规则      rules: {        fnCategoryName: [{ required: true, message: '请输入类目名称', trigger: 'change' }],        status: [{ required: true, message: '请选择是否上架', trigger: 'change' }],        sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur' }]      },      temp: {        fnCategoryId: undefined,        // 前台类目名:        fnCategoryName: '',        // 是否上架        status: 1,        // 类目排序        sortOrder: 0,        conditions: 'N',        level: 1,        special: 0,        fnCategoryImage: ''      },      fnCategoryFileList: [],      fnCategoryBillboardFileList: [],      // 状态      valueList: [{        value: 1,        label: '是'      }, {        value: 0,        label: '否'      }],      textMap: {        update: '一级类目修改',        create: '一级类目新增'      },      // table集合      list: null,      multipleSelection: [],      // 分页      total: 0,      // loading      listLoading: true,      // 属性集合      categorypointToList: [        {          value: '无',          label: '无'        }      ],      listQuery: {        level: 1,        page: 1,        pageSize: 10      },      listBillboardQuery: {        page: 1,        pageSize: 1      }    }  },  created() {    // 列表查询    this.getList()  },  methods: {    // 广告牌弹框保存    advertisingBoardVisibleClick(row) {      if (this.addBillboard) {        createMallFnCategoryBillboard(this.tempBillboard).then(res => {          this.tempBillboard.id = res.model.id          this.dialogAdvertisingBoardVisible = false          this.$notify({            title: 'Success',            message: 'Save Successfully',            type: 'success',            duration: 2000          })        })      } else {        updateMallFnCategoryBillboard(this.tempBillboard).then(res => {          this.dialogAdvertisingBoardVisible = false          this.$notify({            title: 'Success',            message: 'Save Successfully',            type: 'success',            duration: 2000          })        })      }    },    // 广告牌    handleAdvertisingBoard(row) {      this.dialogAdvertisingBoardVisible = true      this.tempBillboard.fnCategoryId = row.fnCategoryId      this.listBillboardQuery.fnCategoryId = row.fnCategoryId      fetchFnCategoryBillboardList(this.listBillboardQuery).then(response => {        this.fnCategoryBillboardFileList = []        if (response.model !== null && response.model.length > 0) {          this.tempBillboard = response.model[0]          this.addBillboard = false          if (this.tempBillboard.imageUrl !== null && this.tempBillboard.imageUrl !== '') {            const obj = new Object()            obj.url = this.tempBillboard.imageUrl            this.fnCategoryBillboardFileList.push(obj)          }        }         // Just to simulate the time of the request        setTimeout(() => {          this.listLoading = false        }, 1.5 * 1000)      })    },    // 查看下级    handleSubordinate(row) {      this.$emit('lookSubordinate', row)    },    // 编辑    handleUpdate(row) {      this.fnCategoryFileList = []      console.log(row)      this.temp = Object.assign({}, row) // copy obj      if (undefined !== row.fnCategoryImage && row.fnCategoryImage !== null && row.fnCategoryImage !== '') {        const obj = new Object()        obj.url = row.fnCategoryImage        console.log(obj)        this.fnCategoryFileList.push(obj)      }      this.dialogStatus = 'update'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })    },    // 重置    resetTemp() {      this.temp = {        id: undefined,        // 类目中文名:        fnCategoryName: '',        // 是否上柜        status: 1,        // 类目排序        sortOrder: 0,        conditions: 'N',        level: 1,        special: 0,        fnCategoryImage: ''      }      this.fnCategoryFileList = []    },    resetTempBillboard() {      this.tempBillboard = {        id: undefined,        fnCategoryId: undefined,        // 链接类型        type: 1,        // map_area        redirectArea: '',        // 广告牌状态        status: 1,        imageUrl: ''      }      this.fnCategoryBillboardFileList = []    },    // 新增一级类目    addDate() {      this.resetTemp()      this.dialogStatus = 'create'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })    },    // 更新保存方法    updateData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          const tempData = Object.assign({}, this.temp)          updateMallFnCategory(tempData).then(() => {            const index = this.list.findIndex(v => v.id === this.temp.id)            this.list.splice(index, 1, this.temp)            this.dialogFormVisible = false            this.$notify({              title: 'Success',              message: 'Update Successfully',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    // 创建保存方法    createData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          createMallFnCategory(this.temp).then(() => {            this.dialogFormVisible = false            this.$notify({              title: 'Success',              message: 'Created Successfully',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    fetchData() {      this.getList()    },    // 列表查询    getList() {      this.listLoading = true      fetchFnCategoryList(this.listQuery).then(response => {        this.list = response.model        this.total = response.totalItem         // Just to simulate the time of the request        setTimeout(() => {          this.listLoading = false        }, 1.5 * 1000)      })    },    handleRemove(file, fileList) {      console.log(file, fileList)    },    handlePictureCardPreview(file) {      this.dialogImageUrl = file.url    },    handleSuccess(res, file, fileList) {      this.temp.fnCategoryImage = res.model      console.log(this.temp.fnCategoryImage)    },    handleBillboardPreview(file) {      this.billboardImageUrl = file.url    },    handleBillboardSuccess(res, file, fileList) {      this.tempBillboard.imageUrl = res.model      console.log(this.tempBillboard.imageUrl)    }  }}script> <style scoped>style>

二级前台类目

  
"backgroundCategoryTwoSearchDiv">
"float:right"> @click="returnBack">< "font-size:15px;margin-top:50px;line-height: 30px;">返回上一级 "primary" icon="el-icon-edit" style="margin-bottom:20px;float: left;margin-right: 40px;" @click="addDate()">新增二级
ref="table" v-loading="listLoading" :data="list" style="width: 100%" border > "类目ID"> "scope">{{ scope.row.fnCategoryId }} "类目名称"> "scope">{{ scope.row.fnCategoryName }} "父类目ID"> "scope">{{ scope.row.parentId }} "类目级别"> 二级类目 "排序"> "scope">{{ scope.row.sortOrder }} status "是否上架"> "scope">{{ scope.row.status ==1?"上架":"下架" }} "类目指向"> "scope">{{ scope.row.conditions }} "操作" width="200"> "scope"> type="primary" size="mini" @click="handleSubordinate(scope.row)" >查看下级 type="primary" size="mini" @click="handleUpdate(scope.row)" >修改
"total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> "textMap[dialogStatus]" :visible.sync="dialogFormVisible"> "dataForm" :rules="rules" :model="temp" label-position="right" label-width="120px" style="width: 320px; margin-left:50px;"> "类目名称:" prop="fnCategoryName"> "temp.fnCategoryName" placeholder="请输入类目中文名" /> "类目排序:" prop="sortOrder"> v-model="temp.sortOrder" :min="0" :max="100" placeholder="请输入类目排序" /> "是否上柜:" prop="status"> "temp.status" placeholder="请选择"> v-for="(item,index) in valueList" :key="index" :label="item.label" :value="item.value" /> "类目指向:" prop="conditions"> "temp.conditions" placeholder="请输入类目指向" /> "类目ICON:">
"width:300%"> action="http://127.0.0.1:9201//upload/uploadFile?moudle=fncategory" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :file-list="fnCategoryFileList" > "dialogVisible"> "100%" :src="dialogImageUrl" alt="">
"footer"> @click="dialogFormVisible = false"> 取消 "primary" @click="dialogStatus==='create'?createData():updateData()"> 确定
import Pagination from '@/components/Pagination' // secondary package based on el-paginationimport { fetchFnCategoryList, createMallFnCategory, updateMallFnCategory } from '@/api/product-manage'export default { components: { Pagination }, props: { pid: Number, pname: String }, data() { return { // 二级类目指向弹框是否显示 dialogFormPointToVisible: false, dialogStatus: '', // 弹框是否显示 dialogFormVisible: false, tempPointTo: { channelPage: '' }, rulesPointTo: { channelPage: [{ required: true, message: 'channelPage is required', trigger: 'blur' }] }, // 弹框校验规则 rules: { fnCategoryName: [{ required: true, message: '请输入类目名称', trigger: 'change' }], status: [{ required: true, message: '请选择是否上架', trigger: 'change' }], sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur' }] }, temp: { fnCategoryId: undefined, // 前台类目名: fnCategoryName: '', // 是否上架 status: 1, // 类目排序 sortOrder: 0, conditions: 'N', level: 1, special: 0, fnCategoryImage: '', parentId: this.pid }, // 状态 valueList: [{ value: 1, label: '是' }, { value: 0, label: '否' }], textMap: { update: '二级类目修改', create: '二级类目新增' }, // table集合 list: null, multipleSelection: [], // 分页 total: 0, // loading listLoading: true, // dialogImageUrl: '', dialogVisible: false, // listQuery: { level: 2, page: 1, pageSize: 10, parentId: this.pid }, fnCategoryFileList: [] } }, created() { // 列表查询 this.getList() }, methods: { /** * 回退 */ returnBack() { this.$emit('returnBack') }, // 管理 handleManagement(row) { this.tempPointTo.channelPage = '' this.dialogFormPointToVisible = true }, // 查看下级 handleSubordinate(row) { this.$emit('lookSubordinate', row) }, // 编辑 handleUpdate(row) { this.temp = Object.assign({}, row) // copy obj this.fnCategoryFileList = [] if (row.imageUrl !== null && row.imageUrl !== '') { const obj = {} obj.url = row.imageUrl this.fnCategoryFileList.push(obj) } this.dialogStatus = 'update' this.dialogFormVisible = true this.$nextTick(() => { this.$refs['dataForm'].clearValidate() }) }, // 重置 resetTemp() { this.temp = { id: undefined, // 类目中文名: fnCategoryName: '', // 是否上柜 status: 1, // 类目排序 sortOrder: 0, conditions: 'N', level: 1, special: 0, fnCategoryImage: '', parentId: this.pid } this.fnCategoryFileList = [] }, // 新增一级类目 addDate() { this.resetTemp() this.dialogStatus = 'create' this.dialogFormVisible = true this.$nextTick(() => { this.$refs['dataForm'].clearValidate() }) }, // 更新保存方法 updateData() { this.$refs['dataForm'].validate((valid) => { if (valid) { const tempData = Object.assign({}, this.temp) updateMallFnCategory(tempData).then(() => { const index = this.list.findIndex(v => v.id === this.temp.id) this.list.splice(index, 1, this.temp) this.dialogFormVisible = false this.$notify({ title: 'Success', message: 'Update Successfully', type: 'success', duration: 2000 }) this.getList() }) } }) }, // 创建保存方法 createData() { this.$refs['dataForm'].validate((valid) => { if (valid) { createMallFnCategory(this.temp).then(() => { this.list.unshift(this.temp) this.dialogFormVisible = false this.$notify({ title: 'Success', message: 'Created Successfully', type: 'success', duration: 2000 }) this.getList() }) } }) }, // 列表查询 getList() { this.listLoading = true fetchFnCategoryList(this.listQuery).then(response => { this.list = response.model this.total = response.totalItem // Just to simulate the time of the request setTimeout(() => { this.listLoading = false }, 1.5 * 1000) }) }, handleRemove(file, fileList) { console.log(file, fileList) }, handlePictureCardPreview(file) { this.dialogImageUrl = file.url this.dialogVisible = true } }} /* .mouseMark:hover { cursor: pointer;} */

三级前台类目

  
"backgroundCategoryTwoSearchDiv">
"float:right"> @click="returnBack(pid,pname)">< "font-size:15px;margin-top:50px;line-height: 30px;">返回上一级 "primary" icon="el-icon-edit" style="margin-bottom:20px;float: left;margin-right: 40px;" @click="addDate()">新增三级
ref="table" v-loading="listLoading" :data="list" style="width: 100%" border > "类目ID"> "scope">{{ scope.row.fnCategoryId }} "类目名称"> "scope">{{ scope.row.fnCategoryName }} "父类目ID"> "scope">{{ scope.row.parentId }} "类目级别"> 三级类目 "排序"> "scope">{{ scope.row.sortOrder }} status "是否上架"> "scope">{{ scope.row.status ==1?"上架":"下架" }} "类目指向"> "scope"> "color:#4395ff" @click="handleManagement(scope.row)">管理 "操作"> "scope"> type="primary" size="mini" @click="handleUpdate(scope.row)" >修改
"total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.pageSize" @pagination="getList" /> "textMap[dialogStatus]" :visible.sync="dialogFormVisible"> "dataForm" :rules="rules" :model="temp" label-position="right" label-width="120px" style="width: 320px; margin-left:50px;"> "类目名称:" prop="fnCategoryName"> "temp.fnCategoryName" placeholder="请输入类目中文名" /> "类目排序:" prop="sortOrder"> v-model="temp.sortOrder" :min="0" :max="100" placeholder="请输入类目排序" /> "是否上柜:" prop="status"> "temp.status" placeholder="请选择"> v-for="(item,index) in valueList" :key="index" :label="item.label" :value="item.value" /> "类目指向:" prop="conditions"> "temp.conditions" placeholder="请输入类目指向" /> "类目ICON:">
"width:300%"> action="http://127.0.0.1:9201//upload/uploadFile?moudle=fncategory" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :file-list="fnCategoryFileList" > "dialogVisible"> "100%" :src="dialogImageUrl" alt="">
"footer"> @click="dialogFormVisible = false"> 取消 "primary" @click="dialogStatus==='create'?createData():updateData()"> 确定
if="dialogFormSpecialVisible" title="三级类目指向" :visible.sync="dialogFormSpecialVisible"> "6">
"margin-bottom:10px;font-weight: 600;">第一步:选择后台类目
"never">
ref="tree" :data="data" show-checkbox node-key="categoryId" :default-expanded-keys="[1,2]" :props="treeProps" clearable filterable allow-create @check-change="updateKeyChildren" />
"1"> "17"> "top-start" effect="light">
"content">当某一后台三级类目与前台类目
进行初次绑定时,系统会强制将
对应前台类目设置成主类目
"margin-bottom:10px;font-weight: 600;">第二步:设置当前类目为前台主类目
"never">
ref="table" :data="tableList" style="width: 100%;" border > "已选后台类目"> "scope"> {{ scope.row.categoryName }} "已选前台主类目"> "scope"> {{ scope.row.fnCategoryName }} "是否设置当前类目为前台主类目" width="140"> "scope"> "scope.row.checked">是 "操作" width="300"> "scope"> width="100" type="danger" @click="handleDelete(scope.$index, scope.row)" >删除
"text-align: center;margin-top:20px;"> @click="dialogFormSpecialVisible = false"> 取消 "primary" @click="specialClick"> 确定
import Pagination from '@/components/Pagination' // secondary package based on el-paginationimport { fetchFnCategoryList, createMallFnCategory, updateMallFnCategory, fetchFnCategoryForSelect, createMallFnBgCategoryRel, findForSelectedTable } from '@/api/product-manage'export default { components: { Pagination }, props: { pid: Number, pname: String }, data() { return { atteibute: { id: undefined, mainCategory: 1, fnCategoryId: 0, categoryId: 0, categoryIdName: '', fnCategoryName: '', checked: true }, fnCategoryId: undefined, // 前台类目名: fnCategoryName: '', fnCategoryFileList: [], treeProps: { label: 'categoryName', children: 'children' }, data: [], defaultProps: { children: 'children', label: 'label' }, // dialogImageUrl: '', dialogVisible: false, // dialogStatus: '', // 特殊属性弹框是否显示 dialogFormSpecialVisible: false, // 弹框是否显示 dialogFormVisible: false, // 弹框校验规则 rules: { fnCategoryName: [{ required: true, message: '请输入类目名称', trigger: 'change' }], status: [{ required: true, message: '请选择是否上架', trigger: 'change' }], sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur' }] }, // 类目指向 categorypointToList: [ { value: '无', label: '无' }, { value: '个性URL', label: '个性URL' }, { value: '频道页', label: '频道页' }, { value: '后台类目', label: '后台类目' } ], temp: { fnCategoryId: undefined, // 前台类目名: fnCategoryName: '', // 是否上架 status: 1, // 类目排序 sortOrder: 0, conditions: 'N', level: 3, special: 0, fnCategoryImage: '', parentId: this.pid }, // 状态 valueList: [ { value: '是', label: '是' }, { value: '否', label: '否' } ], textMap: { update: '三级类目修改', create: '三级类目新增' }, // table集合 list: null, tableList: [ ], multipleSelection: [], // 分页 total: 0, // loading listLoading: true, listQuery: { level: 3, page: 1, pageSize: 10, parentId: this.pid }, listDataQuery: { fnCategoryId: 0 } } }, created() { // 列表查询 this.getList() }, methods: { updateKeyChildren(data, key1, key2) { const checkedNodes = this.$refs.tree.getCheckedNodes() if (checkedNodes != null && checkedNodes.length > 0) { for (let i = 0; i < checkedNodes.length; i++) { this.atteibute = { id: undefined, fnCategoryId: this.fnCategoryId, categoryId: checkedNodes[i].categoryId, categoryName: checkedNodes[i].categoryName, fnCategoryName: this.fnCategoryName, status: 1, checked: true } const checkedNode = checkedNodes[i] if (checkedNode.categoryId !== null && checkedNode.level === 3) { let flag = true for (let j = 0; j < this.tableList.length; j++) { if (this.tableList[j].categoryId === checkedNode.categoryId) { console.log(checkedNode) flag = false } } if (flag) { if (checkedNode.checked) { this.atteibute.mainCategory = 1 } else { this.atteibute.mainCategory = 0 } this.tableList.push(this.atteibute) } } } } }, // 管理保存 specialClick() { if (this.tableList.length < 1) { this.dialogFormSpecialVisible = false return } createMallFnBgCategoryRel(this.tableList).then(() => { this.dialogFormVisible = false this.dialogFormSpecialVisible = false this.$notify({ title: 'Success', message: 'Save Successfully', type: 'success', duration: 2000 }) }) }, handleDelete(index, row) { this.tableList.splice(index, 1) }, /** * 回退 */ returnBack() { this.$emit('returnBack') }, // 管理 handleManagement(row) { this.tableList = [] this.listDataQuery.fnCategoryId = this.fnCategoryId = row.fnCategoryId this.fnCategoryName = row.fnCategoryName this.fnCategoryId = row.fnCategoryId this.fnCategoryName = row.fnCategoryName fetchFnCategoryForSelect(this.listDataQuery).then(response => { this.data = response.model setTimeout(() => { this.listLoading = false }, 1.5 * 1000) findForSelectedTable(this.listDataQuery).then(response => { this.tableList = response.model for (let i = 0; i < this.tableList.length; i++) { this.tableList[i].fnCategoryName = row.fnCategoryName // console.log(this.data) } }) // Just to simulate the time of the request setTimeout(() => { this.listLoading = false }, 1.5 * 1000) }) this.dialogFormSpecialVisible = true }, // 编辑 handleUpdate(row) { this.temp = Object.assign({}, row) // copy obj this.dialogStatus = 'update' this.dialogFormVisible = true this.$nextTick(() => { this.$refs['dataForm'].clearValidate() }) }, // 重置 resetTemp() { this.temp = { id: undefined, // 类目中文名: fnCategoryName: '', // 是否上柜 status: 1, // 类目排序 sortOrder: 0, conditions: 'N', level: 3, special: 0, fnCategoryImage: '', parentId: this.pid } this.fnCategoryFileList = [] }, // 新增三级类目 addDate() { this.resetTemp() this.dialogStatus = 'create' this.dialogFormVisible = true this.$nextTick(() => { this.$refs['dataForm'].clearValidate() }) }, // 更新保存方法 updateData() { this.$refs['dataForm'].validate((valid) => { if (valid) { const tempData = Object.assign({}, this.temp) updateMallFnCategory(tempData).then(() => { const index = this.list.findIndex(v => v.id === this.temp.id) this.list.splice(index, 1, this.temp) this.dialogFormVisible = false this.$notify({ title: 'Success', message: 'Update Successfully', type: 'success', duration: 2000 }) }) } }) }, // 创建保存方法 createData() { this.$refs['dataForm'].validate((valid) => { if (valid) { createMallFnCategory(this.temp).then(() => { this.list.unshift(this.temp) this.dialogFormVisible = false this.$notify({ title: 'Success', message: 'Created Successfully', type: 'success', duration: 2000 }) this.getList() }) } }) }, handleRemove(file, fileList) { console.log(file, fileList) }, handlePictureCardPreview(file) { this.dialogImageUrl = file.url this.dialogVisible = true }, // 列表查询 getList() { this.listLoading = true fetchFnCategoryList(this.listQuery).then(response => { this.list = response.model this.total = response.totalItem // Just to simulate the time of the request setTimeout(() => { this.listLoading = false }, 1.5 * 1000) }) } }} /* .mouseMark:hover { cursor: pointer;} */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值