Commit 969c3877641eeecf77c7395b7981bb006b8d2f13

Authored by YunaiV
1 parent 6a0f7134

mall:完善商品分类的管理后台界面

sql/optional/mall/mall.sql
... ... @@ -20,25 +20,6 @@ SET NAMES utf8mb4;
20 20 -- ----------------------------
21 21 -- Table structure for product_category
22 22 -- ----------------------------
23   -DROP TABLE IF EXISTS `product_category`;
24   -CREATE TABLE `product_category`
25   -(
26   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号',
27   - `parent_id` bigint NOT NULL COMMENT '父分类编号',
28   - `name` varchar(255) NOT NULL COMMENT '分类名称',
29   - `icon` varchar(100) NOT NULL DEFAULT '#' COMMENT '分类图标',
30   - `banner_url` varchar(255) NOT NULL COMMENT '分类图片',
31   - `sort` int DEFAULT '0' COMMENT '分类排序',
32   - `description` varchar(1024) DEFAULT NULL COMMENT '分类描述',
33   - `status` tinyint NOT NULL COMMENT '开启状态',
34   - `creator` varchar(64) DEFAULT '' COMMENT '创建者',
35   - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
36   - `updater` varchar(64) DEFAULT '' COMMENT '更新者',
37   - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
38   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
39   - `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
40   - PRIMARY KEY (`id`) USING BTREE
41   -) ENGINE=InnoDB COMMENT='商品分类';
42 23  
43 24 -- ----------------------------
44 25 -- Table structure for product_brand
... ... @@ -83,6 +64,7 @@ INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `pa
83 64 VALUES ('分类删除', 'product:category:delete', 3, 4, @parentId, '', '', '', 0);
84 65 INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
85 66 VALUES ('分类导出', 'product:category:export', 3, 5, @parentId, '', '', '', 0);
  67 +
86 68 -- 品牌管理 菜单 SQL
87 69 INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
88 70 VALUES ('品牌管理', '', 2, 1, 2001, 'brand', '', 'mall/product/brand/index', 0);
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/AppCategoryController.java
... ... @@ -35,6 +35,4 @@ public class AppCategoryController {
35 35 return success(CategoryConvert.INSTANCE.convertList03(list));
36 36 }
37 37  
38   -
39   -
40 38 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/category/vo/AppCategoryListRespVO.java
... ... @@ -8,7 +8,7 @@ import javax.validation.constraints.NotBlank;
8 8 import javax.validation.constraints.NotNull;
9 9  
10 10 @Data
11   -@ApiModel(value = "App - 商品分类 列表 Request VO", description = "参数和 CategoryBaseVO 是一致的")
  11 +@ApiModel(value = "App - 商品分类 Response VO")
12 12 public class AppCategoryListRespVO {
13 13  
14 14 @ApiModelProperty(value = "分类编号", required = true, example = "2")
... ... @@ -22,17 +22,8 @@ public class AppCategoryListRespVO {
22 22 @NotBlank(message = "分类名称不能为空")
23 23 private String name;
24 24  
25   - @ApiModelProperty(value = "分类图标")
26   - @NotBlank(message = "分类图标不能为空")
27   - private String icon;
28   -
29 25 @ApiModelProperty(value = "分类图片", required = true)
30 26 @NotBlank(message = "分类图片不能为空")
31   - private String bannerUrl;
32   -
33   - @ApiModelProperty(value = "分类排序", required = true, example = "1")
34   - private Integer sort;
  27 + private String picUrl;
35 28  
36   - @ApiModelProperty(value = "分类描述", required = true, example = "描述")
37   - private String description;
38 29 }
... ...
yudao-ui-admin/src/api/mall/product/category.js
1 1 import request from '@/utils/request'
2 2  
3 3 // 创建商品分类
4   -export function createCategory(data) {
  4 +export function createProductCategory(data) {
5 5 return request({
6 6 url: '/product/category/create',
7 7 method: 'post',
... ... @@ -10,7 +10,7 @@ export function createCategory(data) {
10 10 }
11 11  
12 12 // 更新商品分类
13   -export function updateCategory(data) {
  13 +export function updateProductCategory(data) {
14 14 return request({
15 15 url: '/product/category/update',
16 16 method: 'put',
... ... @@ -19,7 +19,7 @@ export function updateCategory(data) {
19 19 }
20 20  
21 21 // 删除商品分类
22   -export function deleteCategory(id) {
  22 +export function deleteProductCategory(id) {
23 23 return request({
24 24 url: '/product/category/delete?id=' + id,
25 25 method: 'delete'
... ... @@ -27,37 +27,18 @@ export function deleteCategory(id) {
27 27 }
28 28  
29 29 // 获得商品分类
30   -export function getCategory(id) {
  30 +export function getProductCategory(id) {
31 31 return request({
32 32 url: '/product/category/get?id=' + id,
33 33 method: 'get'
34 34 })
35 35 }
36 36  
37   -// 获得商品分类
38   -export function listCategory(query) {
39   - return request({
40   - url: '/product/category/listByQuery',
41   - method: 'get',
42   - params: query
43   - })
44   -}
45   -
46   -// 获得商品分类分页
47   -export function getCategoryPage(query) {
  37 +// 获得商品分类列表
  38 +export function getProductCategoryList(query) {
48 39 return request({
49   - url: '/product/category/page',
  40 + url: '/product/category/list',
50 41 method: 'get',
51 42 params: query
52 43 })
53 44 }
54   -
55   -// 导出商品分类 Excel
56   -export function exportCategoryExcel(query) {
57   - return request({
58   - url: '/product/category/export-excel',
59   - method: 'get',
60   - params: query,
61   - responseType: 'blob'
62   - })
63   -}
... ...
yudao-ui-admin/src/views/mall/product/brand/index.vue
... ... @@ -118,7 +118,7 @@ import {
118 118 getBrandPage,
119 119 updateBrand
120 120 } from "@/api/mall/product/brand";
121   -import {listCategory} from "@/api/mall/product/category";
  121 +import {getProductCategoryList} from "@/api/mall/product/category";
122 122 import ImageUpload from '@/components/ImageUpload';
123 123 import Treeselect from "@riophae/vue-treeselect";
124 124 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
... ... @@ -194,7 +194,7 @@ export default {
194 194 },
195 195 /** 查询分类下拉树结构 */
196 196 getTreeselect() {
197   - listCategory().then(response => {
  197 + getProductCategoryList().then(response => {
198 198 this.categoryOptions = [];
199 199 const menu = {id: 0, name: '商品分类', children: []};
200 200 menu.children = this.handleTree(response.data, "id", "pid");
... ...
yudao-ui-admin/src/views/mall/product/category/index.vue
... ... @@ -6,12 +6,6 @@
6 6 <el-form-item label="分类名称" prop="name">
7 7 <el-input v-model="queryParams.name" placeholder="请输入分类名称" clearable @keyup.enter.native="handleQuery"/>
8 8 </el-form-item>
9   - <el-form-item label="开启状态" prop="status">
10   - <el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
11   - <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
12   - :key="dict.value" :label="dict.label" :value="dict.value"/>
13   - </el-select>
14   - </el-form-item>
15 9 <el-form-item>
16 10 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
17 11 <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
... ... @@ -28,27 +22,16 @@
28 22 <el-col :span="1.5">
29 23 <el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
30 24 </el-col>
31   - <el-col :span="1.5">
32   - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
33   - :loading="exportLoading"
34   - v-hasPermi="['product:category:export']">导出
35   - </el-button>
36   - </el-col>
37 25 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
38 26 </el-row>
39 27  
40 28 <!-- 列表 -->
41 29 <el-table v-if="refreshTable" v-loading="loading" :data="list" row-key="id" :default-expand-all="isExpandAll"
42 30 :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
43   - <el-table-column label="分类名称" align="center" prop="name"/>
44   - <el-table-column label="分类图标" align="center" prop="icon">
45   - <template slot-scope="scope">
46   - <svg-icon :icon-class="scope.row.icon" />
47   - </template>
48   - </el-table-column>
49   - <el-table-column label="分类图片" align="center" prop="bannerUrl">
  31 + <el-table-column label="分类名称" prop="name"/>
  32 + <el-table-column label="分类图片" align="center" prop="picUrl">
50 33 <template slot-scope="scope">
51   - <img v-if="scope.row.bannerUrl" :src="scope.row.bannerUrl" alt="分类图片" class="img-height"/>
  34 + <img v-if="scope.row.picUrl" :src="scope.row.picUrl" alt="分类图片" style="height: 100px"/>
52 35 </template>
53 36 </el-table-column>
54 37 <el-table-column label="分类排序" align="center" prop="sort"/>
... ... @@ -78,32 +61,22 @@
78 61 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
79 62 <el-form ref="form" :model="form" :rules="rules" label-width="80px">
80 63 <el-form-item label="上级分类" prop="parentId">
81   - <Treeselect v-model="form.parentId" :options="parentCategoryOptions" :normalizer="normalizer"
82   - :show-count="true"
83   - placeholder="上级分类"/>
  64 + <el-select v-model="form.parentId" placeholder="请选择上级分类" clearable size="small">
  65 + <el-option :key="0" label="顶级分类" :value="0"/>
  66 + <el-option v-for="item in list.filter(v => v.parentId === 0)" :key="item.id" :label="item.name" :value="item.id"/>
  67 + </el-select>
84 68 </el-form-item>
85 69 <el-form-item label="分类名称" prop="name">
86 70 <el-input v-model="form.name" placeholder="请输入分类名称"/>
87 71 </el-form-item>
88   - <el-form-item label="分类图标" prop="icon">
89   - <el-popover placement="bottom-start" width="460" trigger="click" @show="$refs['iconSelect'].reset()">
90   - <IconSelect ref="iconSelect" @selected="iconSelected"/>
91   - <el-input slot="reference" v-model="form.icon" placeholder="点击选择分类图标" readonly>
92   - <svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon"
93   - style="height: 32px;width: 16px;"/>
94   - <i v-else slot="prefix" class="el-icon-search el-input__icon"/>
95   - </el-input>
96   - </el-popover>
97   - </el-form-item>
98 72 <el-form-item label="分类图片" prop="bannerUrl">
99   - <ImageUpload v-model="form.bannerUrl" :limit="1"/>
  73 + <ImageUpload v-model="form.picUrl" :limit="1" :is-show-tip="false" />
  74 + <div v-if="form.parentId === 0" style="font-size: 10px">推荐 200x100 图片分辨率</div>
  75 + <div v-else style="font-size: 10px">推荐 100x100 图片分辨率</div>
100 76 </el-form-item>
101 77 <el-form-item label="分类排序" prop="sort">
102 78 <el-input-number v-model="form.sort" controls-position="right" :min="0" />
103 79 </el-form-item>
104   - <el-form-item label="分类描述">
105   - <editor v-model="form.description" :min-height="192"/>
106   - </el-form-item>
107 80 <el-form-item label="开启状态" prop="status">
108 81 <el-radio-group v-model="form.status">
109 82 <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
... ... @@ -111,6 +84,9 @@
111 84 </el-radio>
112 85 </el-radio-group>
113 86 </el-form-item>
  87 + <el-form-item label="分类描述">
  88 + <el-input v-model="form.description" type="textarea" placeholder="请输入分类描述" />
  89 + </el-form-item>
114 90 </el-form>
115 91 <div slot="footer" class="dialog-footer">
116 92 <el-button type="primary" @click="submitForm">确 定</el-button>
... ... @@ -122,34 +98,31 @@
122 98  
123 99 <script>
124 100 import {
125   - createCategory,
126   - deleteCategory,
  101 + createProductCategory,
  102 + deleteProductCategory,
127 103 exportCategoryExcel,
128   - getCategory,
129   - listCategory,
130   - updateCategory
  104 + getProductCategory,
  105 + getProductCategoryList,
  106 + updateProductCategory
131 107 } from "@/api/mall/product/category";
132 108 import Editor from '@/components/Editor';
133 109 import Treeselect from "@riophae/vue-treeselect";
134 110 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
135 111 import IconSelect from "@/components/IconSelect";
136 112 import ImageUpload from '@/components/ImageUpload';
  113 +import {CommonStatusEnum} from "@/utils/constants";
137 114  
138 115 export default {
139 116 name: "Category",
140 117 components: {
141   - Editor, Treeselect, IconSelect, ImageUpload
  118 + Editor, Treeselect, ImageUpload
142 119 },
143 120 data() {
144 121 return {
145 122 // 遮罩层
146 123 loading: true,
147   - // 导出遮罩层
148   - exportLoading: false,
149 124 // 显示搜索条件
150 125 showSearch: true,
151   - // 总条数
152   - total: 0,
153 126 // 商品分类列表
154 127 list: [],
155 128 // 商品分类树选项
... ... @@ -164,10 +137,7 @@ export default {
164 137 refreshTable: true,
165 138 // 查询参数
166 139 queryParams: {
167   - pageNo: 1,
168   - pageSize: 10,
169 140 name: null,
170   - status: null,
171 141 },
172 142 // 表单参数
173 143 form: {},
... ... @@ -175,8 +145,8 @@ export default {
175 145 rules: {
176 146 parentId: [{required: true, message: "请选择上级分类", trigger: "blur"}],
177 147 name: [{required: true, message: "分类名称不能为空", trigger: "blur"}],
178   - icon: [{required: true, message: "分类图标不能为空", trigger: "blur"}],
179   - bannerUrl: [{required: true, message: "分类图片不能为空", trigger: "blur"}],
  148 + picUrl: [{required: true, message: "分类图片不能为空", trigger: "blur"}],
  149 + sort: [{required: true, message: "分类排序不能为空", trigger: "blur"}],
180 150 status: [{required: true, message: "开启状态不能为空", trigger: "blur"}],
181 151 }
182 152 };
... ... @@ -191,35 +161,11 @@ export default {
191 161 // 处理查询参数
192 162 let params = {...this.queryParams};
193 163 // 执行查询
194   - listCategory(params).then(response => {
  164 + getProductCategoryList(params).then(response => {
195 165 this.list = this.handleTree(response.data, "id", "parentId");
196 166 this.loading = false;
197 167 });
198 168 },
199   - // 选择图标
200   - iconSelected(name) {
201   - this.form.icon = name;
202   - },
203   - /** 转换菜单数据结构 */
204   - normalizer(node) {
205   - if (node.children && !node.children.length) {
206   - delete node.children;
207   - }
208   - return {
209   - id: node.id,
210   - label: node.name,
211   - children: node.children
212   - };
213   - },
214   - /** 查询分类下拉树结构 */
215   - getTreeselect() {
216   - listCategory().then(response => {
217   - this.parentCategoryOptions = [];
218   - const menu = {id: 0, name: '主分类', children: []};
219   - menu.children = this.handleTree(response.data, "id", "parentId");
220   - this.parentCategoryOptions.push(menu);
221   - });
222   - },
223 169 /** 取消按钮 */
224 170 cancel() {
225 171 this.open = false;
... ... @@ -231,11 +177,10 @@ export default {
231 177 id: undefined,
232 178 parentId: undefined,
233 179 name: undefined,
234   - icon: undefined,
235   - bannerUrl: undefined,
236   - sort: undefined,
  180 + pirUrl: undefined,
  181 + sort: 0,
237 182 description: undefined,
238   - status: undefined,
  183 + status: CommonStatusEnum.ENABLE,
239 184 };
240 185 this.resetForm("form");
241 186 },
... ... @@ -260,16 +205,14 @@ export default {
260 205 /** 新增按钮操作 */
261 206 handleAdd() {
262 207 this.reset();
263   - this.getTreeselect();
264 208 this.open = true;
265 209 this.title = "添加商品分类";
266 210 },
267 211 /** 修改按钮操作 */
268 212 handleUpdate(row) {
269 213 this.reset();
270   - this.getTreeselect();
271 214 const id = row.id;
272   - getCategory(id).then(response => {
  215 + getProductCategory(id).then(response => {
273 216 this.form = response.data;
274 217 this.open = true;
275 218 this.title = "修改商品分类";
... ... @@ -283,7 +226,7 @@ export default {
283 226 }
284 227 // 修改的提交
285 228 if (this.form.id != null) {
286   - updateCategory(this.form).then(response => {
  229 + updateProductCategory(this.form).then(response => {
287 230 this.$modal.msgSuccess("修改成功");
288 231 this.open = false;
289 232 this.getList();
... ... @@ -291,7 +234,7 @@ export default {
291 234 return;
292 235 }
293 236 // 添加的提交
294   - createCategory(this.form).then(response => {
  237 + createProductCategory(this.form).then(response => {
295 238 this.$modal.msgSuccess("新增成功");
296 239 this.open = false;
297 240 this.getList();
... ... @@ -302,36 +245,13 @@ export default {
302 245 handleDelete(row) {
303 246 const id = row.id;
304 247 this.$modal.confirm('是否确认删除商品分类编号为"' + id + '"的数据项?').then(function () {
305   - return deleteCategory(id);
  248 + return deleteProductCategory(id);
306 249 }).then(() => {
307 250 this.getList();
308 251 this.$modal.msgSuccess("删除成功");
309 252 }).catch(() => {
310 253 });
311   - },
312   - /** 导出按钮操作 */
313   - handleExport() {
314   - // 处理查询参数
315   - let params = {...this.queryParams};
316   - params.pageNo = undefined;
317   - params.pageSize = undefined;
318   - // 执行导出
319   - this.$modal.confirm('是否确认导出所有商品分类数据项?').then(() => {
320   - this.exportLoading = true;
321   - return exportCategoryExcel(params);
322   - }).then(response => {
323   - this.$download.excel(response, '商品分类.xls');
324   - this.exportLoading = false;
325   - }).catch(() => {
326   - });
327 254 }
328 255 }
329 256 };
330 257 </script>
331   -
332   -<style scoped lang="scss">
333   -//
334   -.img-height {
335   - height: 150px;
336   -}
337   -</style>
... ...
yudao-ui-admin/src/views/mall/product/spu/index.vue
... ... @@ -283,12 +283,12 @@
283 283 <script>
284 284 import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu";
285 285 import {
286   - createCategory,
287   - deleteCategory,
  286 + createProductCategory,
  287 + deleteProductCategory,
288 288 exportCategoryExcel,
289   - getCategory,
290   - listCategory,
291   - updateCategory
  289 + getProductCategory,
  290 + getProductCategoryList,
  291 + updateProductCategory
292 292 } from "@/api/mall/product/category";
293 293 import {
294 294 createProperty,
... ... @@ -585,7 +585,7 @@ export default {
585 585 /** 查询分类 */
586 586 getListCategory() {
587 587 // 执行查询
588   - listCategory().then(response => {
  588 + getProductCategoryList().then(response => {
589 589 this.categoryList = this.handleTree(response.data, "id", "parentId");
590 590  
591 591 });
... ...