20210312更新-PubSub is not defined”

下面内容为最新内容,问题已解决

准确代码参考:Github

组件一览

代码和资料文档参考下一章:属性分组-后端(商品服务完成)

image.png

属性分组页面组件-attrgroup.vue

  1. <template>
  2. <el-row :gutter="20">
  3. <el-col :span="6">
  4. <category @tree-node-click="treenodeclick"></category>
  5. </el-col>
  6. <el-col :span="18">
  7. <div class="mod-config">
  8. <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
  9. <el-form-item>
  10. <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
  11. </el-form-item>
  12. <el-form-item>
  13. <el-button @click="getDataList()">查询</el-button>
  14. <el-button type="success" @click="getAllDataList()">查询全部</el-button>
  15. <el-button
  16. v-if="isAuth('product:attrgroup:save')"
  17. type="primary"
  18. @click="addOrUpdateHandle()"
  19. >新增
  20. </el-button>
  21. <el-button
  22. v-if="isAuth('product:attrgroup:delete')"
  23. type="danger"
  24. @click="deleteHandle()"
  25. :disabled="dataListSelections.length <= 0"
  26. >批量删除
  27. </el-button>
  28. </el-form-item>
  29. </el-form>
  30. <el-table
  31. :data="dataList"
  32. border
  33. v-loading="dataListLoading"
  34. @selection-change="selectionChangeHandle"
  35. style="width: 100%;"
  36. >
  37. <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
  38. <el-table-column prop="attrGroupId" header-align="center" align="center" label="分组id"></el-table-column>
  39. <el-table-column prop="attrGroupName" header-align="center" align="center" label="组名"></el-table-column>
  40. <el-table-column prop="sort" header-align="center" align="center" label="排序"></el-table-column>
  41. <el-table-column prop="descript" header-align="center" align="center" label="描述"></el-table-column>
  42. <el-table-column prop="icon" header-align="center" align="center" label="组图标"></el-table-column>
  43. <el-table-column prop="catelogId" header-align="center" align="center" label="所属分类id"></el-table-column>
  44. <el-table-column
  45. fixed="right"
  46. header-align="center"
  47. align="center"
  48. width="150"
  49. label="操作"
  50. >
  51. <template slot-scope="scope">
  52. <el-button type="text" size="small" @click="relationHandle(scope.row.attrGroupId)">关联</el-button>
  53. <el-button
  54. type="text"
  55. size="small"
  56. @click="addOrUpdateHandle(scope.row.attrGroupId)"
  57. >修改
  58. </el-button>
  59. <el-button type="text" size="small" @click="deleteHandle(scope.row.attrGroupId)">删除</el-button>
  60. </template>
  61. </el-table-column>
  62. </el-table>
  63. <el-pagination
  64. @size-change="sizeChangeHandle"
  65. @current-change="currentChangeHandle"
  66. :current-page="pageIndex"
  67. :page-sizes="[10, 20, 50, 100]"
  68. :page-size="pageSize"
  69. :total="totalPage"
  70. layout="total, sizes, prev, pager, next, jumper"
  71. ></el-pagination>
  72. <!-- 弹窗, 新增 / 修改 -->
  73. <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
  74. <!-- 修改关联关系 -->
  75. <relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update>
  76. </div>
  77. </el-col>
  78. </el-row>
  79. </template>
  80. <script>
  81. /**
  82. * 父子组件传递数据
  83. * 1)、子组件给父组件传递数据,事件机制;
  84. * 子组件给父组件发送一个事件,携带上数据。
  85. * // this.$emit("事件名",携带的数据...)
  86. */
  87. //这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  88. //例如:import 《组件名称》 from '《组件路径》';
  89. import Category from "@/views/common/category";
  90. import AddOrUpdate from "./attrgroup-add-or-update";
  91. import RelationUpdate from "./attr-group-relation";
  92. export default {
  93. //import引入的组件需要注入到对象中才能使用
  94. components: {Category, AddOrUpdate, RelationUpdate},
  95. props: {},
  96. data() {
  97. return {
  98. catId: 0,
  99. dataForm: {
  100. key: ""
  101. },
  102. dataList: [],
  103. pageIndex: 1,
  104. pageSize: 10,
  105. totalPage: 0,
  106. dataListLoading: false,
  107. dataListSelections: [],
  108. addOrUpdateVisible: false,
  109. relationVisible: false
  110. };
  111. },
  112. activated() {
  113. this.getDataList();
  114. },
  115. methods: {
  116. //处理分组与属性的关联
  117. relationHandle(groupId) {
  118. this.relationVisible = true;
  119. this.$nextTick(() => {
  120. this.$refs.relationUpdate.init(groupId);
  121. });
  122. },
  123. //感知树节点被点击
  124. treenodeclick(data, node, component) {
  125. if (node.level === 3) {
  126. this.catId = data.catId;
  127. this.getDataList(); //重新查询
  128. }
  129. },
  130. getAllDataList() {
  131. this.catId = 0;
  132. this.getDataList();
  133. },
  134. // 获取数据列表
  135. getDataList() {
  136. this.dataListLoading = true;
  137. this.$http({
  138. url: this.$http.adornUrl(`/product/attrgroup/list/${this.catId}`),
  139. method: "get",
  140. params: this.$http.adornParams({
  141. page: this.pageIndex,
  142. limit: this.pageSize,
  143. key: this.dataForm.key
  144. })
  145. }).then(({data}) => {
  146. if (data && data.code === 0) {
  147. this.dataList = data.page.list;
  148. this.totalPage = data.page.totalCount;
  149. } else {
  150. this.dataList = [];
  151. this.totalPage = 0;
  152. }
  153. this.dataListLoading = false;
  154. });
  155. },
  156. // 每页数
  157. sizeChangeHandle(val) {
  158. this.pageSize = val;
  159. this.pageIndex = 1;
  160. this.getDataList();
  161. },
  162. // 当前页
  163. currentChangeHandle(val) {
  164. this.pageIndex = val;
  165. this.getDataList();
  166. },
  167. // 多选
  168. selectionChangeHandle(val) {
  169. this.dataListSelections = val;
  170. },
  171. // 新增 / 修改
  172. addOrUpdateHandle(id) {
  173. this.addOrUpdateVisible = true;
  174. this.$nextTick(() => {
  175. this.$refs.addOrUpdate.init(id);
  176. });
  177. },
  178. // 删除
  179. deleteHandle(id) {
  180. var ids = id
  181. ? [id]
  182. : this.dataListSelections.map(item => {
  183. return item.attrGroupId;
  184. });
  185. this.$confirm(
  186. `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
  187. "提示",
  188. {
  189. confirmButtonText: "确定",
  190. cancelButtonText: "取消",
  191. type: "warning"
  192. }
  193. ).then(() => {
  194. this.$http({
  195. url: this.$http.adornUrl("/product/attrgroup/delete"),
  196. method: "post",
  197. data: this.$http.adornData(ids, false)
  198. }).then(({data}) => {
  199. if (data && data.code === 0) {
  200. this.$message({
  201. message: "操作成功",
  202. type: "success",
  203. duration: 1500,
  204. onClose: () => {
  205. this.getDataList();
  206. }
  207. });
  208. } else {
  209. this.$message.error(data.msg);
  210. }
  211. });
  212. });
  213. }
  214. }
  215. };
  216. </script>
  217. <style scoped>
  218. </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="attrGroupName">
        <el-input v-model="dataForm.attrGroupName" 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="catelogId">
        <!-- <el-input v-model="dataForm.catelogId" placeholder="所属分类id"></el-input> @change="handleChange" -->
        <!-- <el-cascader filterable placeholder="试试搜索:手机" v-model="catelogPath" :options="categorys"  :props="props"></el-cascader> -->
        <!-- :catelogPath="catelogPath"自定义绑定的属性,可以给子组件传值 -->
        <category-cascader :catelogPath.sync="catelogPath"></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 '@/views/common/category-cascader'
export default {
  data() {
    return {
      props:{
        value:"catId",
        label:"name",
        children:"children"
      },
      visible: false,
      categorys: [],
      catelogPath: [],
      dataForm: {
        attrGroupId: 0,
        attrGroupName: "",
        sort: "",
        descript: "",
        icon: "",
        catelogId: 0
      },
      dataRule: {
        attrGroupName: [
          { required: true, message: "组名不能为空", trigger: "blur" }
        ],
        sort: [{ required: true, message: "排序不能为空", trigger: "blur" }],
        descript: [
          { required: true, message: "描述不能为空", trigger: "blur" }
        ],
        icon: [{ required: true, message: "组图标不能为空", trigger: "blur" }],
        catelogId: [
          { required: true, message: "所属分类id不能为空", trigger: "blur" }
        ]
      }
    };
  },
  components:{CategoryCascader},

  methods: {
    dialogClose(){
      this.catelogPath = [];
    },
    getCategorys(){
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({ data }) => {
        this.categorys = data.data;
      });
    },
    init(id) {
      this.dataForm.attrGroupId = id || 0;
      this.visible = true;
      this.$nextTick(() => {
        this.$refs["dataForm"].resetFields();
        if (this.dataForm.attrGroupId) {
          this.$http({
            url: this.$http.adornUrl(
              `/product/attrgroup/info/${this.dataForm.attrGroupId}`
            ),
            method: "get",
            params: this.$http.adornParams()
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.dataForm.attrGroupName = data.attrGroup.attrGroupName;
              this.dataForm.sort = data.attrGroup.sort;
              this.dataForm.descript = data.attrGroup.descript;
              this.dataForm.icon = data.attrGroup.icon;
              this.dataForm.catelogId = data.attrGroup.catelogId;
              //查出catelogId的完整路径
              this.catelogPath =  data.attrGroup.catelogPath;
            }
          });
        }
      });
    },
    // 表单提交
    dataFormSubmit() {
      this.$refs["dataForm"].validate(valid => {
        if (valid) {
          this.$http({
            url: this.$http.adornUrl(
              `/product/attrgroup/${
                !this.dataForm.attrGroupId ? "save" : "update"
              }`
            ),
            method: "post",
            data: this.$http.adornData({
              attrGroupId: this.dataForm.attrGroupId || undefined,
              attrGroupName: this.dataForm.attrGroupName,
              sort: this.dataForm.sort,
              descript: this.dataForm.descript,
              icon: this.dataForm.icon,
              catelogId: this.catelogPath[this.catelogPath.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>

获取三级分类组件-category.vue

属性分组页面左侧三级分类显示的组件

<template>
  <div>
    <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
    <el-tree
      :data="menus"
      :props="defaultProps"
      node-key="catId"
      ref="menuTree"
      @node-click="nodeclick"
      :filter-node-method="filterNode"
      :highlight-current="true"
    ></el-tree>
  </div>
</template>

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

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    //这里存放数据
    return {
      filterText: "",
      menus: [],
      expandedKey: [],
      defaultProps: {
        children: "children",
        label: "name"
      }
    };
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {
    filterText(val) {
      this.$refs.menuTree.filter(val);
    }
  },
  //方法集合
  methods: {
    //树节点过滤
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({data}) => {
        this.menus = data.data;
      });
    },
    nodeclick(data, node, component) {
      console.log("子组件category的节点被点击", data, node, component);
      //向父组件发送事件;
      this.$emit("tree-node-click", data, node, component);
    }
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {
  },
  beforeCreate() {
  }, //生命周期 - 创建之前
  beforeMount() {
  }, //生命周期 - 挂载之前
  beforeUpdate() {
  }, //生命周期 - 更新之前
  updated() {
  }, //生命周期 - 更新之后
  beforeDestroy() {
  }, //生命周期 - 销毁之前
  destroyed() {
  }, //生命周期 - 销毁完成
  activated() {
  } //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>

分类级联选择组件-category-cascader.vue

此组件可以生成级联选择三级分类,属性分组新增修改时选择三级分类使用

<template>
<!--
使用说明:
1)、引入category-cascader.vue
2)、语法:<category-cascader :catelogPath.sync="catelogPath"></category-cascader>
    解释:
      catelogPath:指定的值是cascader初始化需要显示的值,应该和父组件的catelogPath绑定;
          由于有sync修饰符,所以cascader路径变化以后自动会修改父的catelogPath,这是结合子组件this.$emit("update:catelogPath",v);做的
      -->
  <div>
    <el-cascader
      filterable
      clearable
      placeholder="试试搜索:手机"
      v-model="paths"
      :options="categorys"
      :props="setting"
    ></el-cascader>
  </div>
</template>

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

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  //接受父组件传来的值
  props: {
    catelogPath: {
      type: Array,
      default(){
        return [];
      }
    }
  },
  data() {
    //这里存放数据
    return {
      setting: {
        value: "catId",
        label: "name",
        children: "children"
      },
      categorys: [],
      paths: this.catelogPath
    };
  },
  watch:{
    catelogPath(v){
      this.paths = this.catelogPath;
      console.log(this.paths)
    },
    paths(v){
      this.$emit("update:catelogPath",v);
      //还可以使用pubsub-js进行传值
      PubSub.publish("catPath",v);
    }
  },
  //方法集合
  methods: {
    getCategorys() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({ data }) => {
        this.categorys = data.data;
      });
    }
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getCategorys();
  }
};
</script>
<style scoped>
</style>

属性分组关联组件-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="attrId" header-align="center" align="center" label="属性id"></el-table-column>
            <el-table-column prop="attrName" 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="attrId" label="#"></el-table-column>
            <el-table-column prop="attrName" 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.attrId)">移除</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.attrId, 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, 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.attrId, 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>