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

This commit is contained in:
YunaiV 2022-07-30 20:28:01 +08:00
parent 6a0f713452
commit 969c387764
7 changed files with 48 additions and 176 deletions

View File

@ -20,25 +20,6 @@ SET NAMES utf8mb4;
-- ----------------------------
-- Table structure for product_category
-- ----------------------------
DROP TABLE IF EXISTS `product_category`;
CREATE TABLE `product_category`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类编号',
`parent_id` bigint NOT NULL COMMENT '父分类编号',
`name` varchar(255) NOT NULL COMMENT '分类名称',
`icon` varchar(100) NOT NULL DEFAULT '#' COMMENT '分类图标',
`banner_url` varchar(255) NOT NULL COMMENT '分类图片',
`sort` int DEFAULT '0' COMMENT '分类排序',
`description` varchar(1024) DEFAULT NULL COMMENT '分类描述',
`status` tinyint NOT NULL COMMENT '开启状态',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='商品分类';
-- ----------------------------
-- Table structure for product_brand
@ -83,6 +64,7 @@ INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `pa
VALUES ('分类删除', 'product:category:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('分类导出', 'product:category:export', 3, 5, @parentId, '', '', '', 0);
-- 品牌管理 菜单 SQL
INSERT INTO `system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`)
VALUES ('品牌管理', '', 2, 1, 2001, 'brand', '', 'mall/product/brand/index', 0);

View File

@ -35,6 +35,4 @@ public class AppCategoryController {
return success(CategoryConvert.INSTANCE.convertList03(list));
}
}

View File

@ -8,7 +8,7 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "App - 商品分类 列表 Request VO", description = "参数和 CategoryBaseVO 是一致的")
@ApiModel(value = "App - 商品分类 Response VO")
public class AppCategoryListRespVO {
@ApiModelProperty(value = "分类编号", required = true, example = "2")
@ -22,17 +22,8 @@ public class AppCategoryListRespVO {
@NotBlank(message = "分类名称不能为空")
private String name;
@ApiModelProperty(value = "分类图标")
@NotBlank(message = "分类图标不能为空")
private String icon;
@ApiModelProperty(value = "分类图片", required = true)
@NotBlank(message = "分类图片不能为空")
private String bannerUrl;
private String picUrl;
@ApiModelProperty(value = "分类排序", required = true, example = "1")
private Integer sort;
@ApiModelProperty(value = "分类描述", required = true, example = "描述")
private String description;
}

View File

@ -1,7 +1,7 @@
import request from '@/utils/request'
// 创建商品分类
export function createCategory(data) {
export function createProductCategory(data) {
return request({
url: '/product/category/create',
method: 'post',
@ -10,7 +10,7 @@ export function createCategory(data) {
}
// 更新商品分类
export function updateCategory(data) {
export function updateProductCategory(data) {
return request({
url: '/product/category/update',
method: 'put',
@ -19,7 +19,7 @@ export function updateCategory(data) {
}
// 删除商品分类
export function deleteCategory(id) {
export function deleteProductCategory(id) {
return request({
url: '/product/category/delete?id=' + id,
method: 'delete'
@ -27,37 +27,18 @@ export function deleteCategory(id) {
}
// 获得商品分类
export function getCategory(id) {
export function getProductCategory(id) {
return request({
url: '/product/category/get?id=' + id,
method: 'get'
})
}
// 获得商品分类
export function listCategory(query) {
// 获得商品分类列表
export function getProductCategoryList(query) {
return request({
url: '/product/category/listByQuery',
url: '/product/category/list',
method: 'get',
params: query
})
}
// 获得商品分类分页
export function getCategoryPage(query) {
return request({
url: '/product/category/page',
method: 'get',
params: query
})
}
// 导出商品分类 Excel
export function exportCategoryExcel(query) {
return request({
url: '/product/category/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -118,7 +118,7 @@ import {
getBrandPage,
updateBrand
} from "@/api/mall/product/brand";
import {listCategory} from "@/api/mall/product/category";
import {getProductCategoryList} from "@/api/mall/product/category";
import ImageUpload from '@/components/ImageUpload';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
@ -194,7 +194,7 @@ export default {
},
/** 查询分类下拉树结构 */
getTreeselect() {
listCategory().then(response => {
getProductCategoryList().then(response => {
this.categoryOptions = [];
const menu = {id: 0, name: '商品分类', children: []};
menu.children = this.handleTree(response.data, "id", "pid");

View File

@ -6,12 +6,6 @@
<el-form-item label="分类名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入分类名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
@ -28,27 +22,16 @@
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
:loading="exportLoading"
v-hasPermi="['product:category:export']">导出
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-if="refreshTable" v-loading="loading" :data="list" row-key="id" :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column label="分类名称" align="center" prop="name"/>
<el-table-column label="分类图标" align="center" prop="icon">
<el-table-column label="分类名称" prop="name"/>
<el-table-column label="分类图片" align="center" prop="picUrl">
<template slot-scope="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column label="分类图片" align="center" prop="bannerUrl">
<template slot-scope="scope">
<img v-if="scope.row.bannerUrl" :src="scope.row.bannerUrl" alt="分类图片" class="img-height"/>
<img v-if="scope.row.picUrl" :src="scope.row.picUrl" alt="分类图片" style="height: 100px"/>
</template>
</el-table-column>
<el-table-column label="分类排序" align="center" prop="sort"/>
@ -78,32 +61,22 @@
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="上级分类" prop="parentId">
<Treeselect v-model="form.parentId" :options="parentCategoryOptions" :normalizer="normalizer"
:show-count="true"
placeholder="上级分类"/>
<el-select v-model="form.parentId" placeholder="请选择上级分类" clearable size="small">
<el-option :key="0" label="顶级分类" :value="0"/>
<el-option v-for="item in list.filter(v => v.parentId === 0)" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="分类名称" prop="name">
<el-input v-model="form.name" placeholder="请输入分类名称"/>
</el-form-item>
<el-form-item label="分类图标" prop="icon">
<el-popover placement="bottom-start" width="460" trigger="click" @show="$refs['iconSelect'].reset()">
<IconSelect ref="iconSelect" @selected="iconSelected"/>
<el-input slot="reference" v-model="form.icon" placeholder="点击选择分类图标" readonly>
<svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon"
style="height: 32px;width: 16px;"/>
<i v-else slot="prefix" class="el-icon-search el-input__icon"/>
</el-input>
</el-popover>
</el-form-item>
<el-form-item label="分类图片" prop="bannerUrl">
<ImageUpload v-model="form.bannerUrl" :limit="1"/>
<ImageUpload v-model="form.picUrl" :limit="1" :is-show-tip="false" />
<div v-if="form.parentId === 0" style="font-size: 10px">推荐 200x100 图片分辨率</div>
<div v-else style="font-size: 10px">推荐 100x100 图片分辨率</div>
</el-form-item>
<el-form-item label="分类排序" prop="sort">
<el-input-number v-model="form.sort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="分类描述">
<editor v-model="form.description" :min-height="192"/>
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
@ -111,6 +84,9 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分类描述">
<el-input v-model="form.description" type="textarea" placeholder="请输入分类描述" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@ -122,34 +98,31 @@
<script>
import {
createCategory,
deleteCategory,
createProductCategory,
deleteProductCategory,
exportCategoryExcel,
getCategory,
listCategory,
updateCategory
getProductCategory,
getProductCategoryList,
updateProductCategory
} from "@/api/mall/product/category";
import Editor from '@/components/Editor';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import IconSelect from "@/components/IconSelect";
import ImageUpload from '@/components/ImageUpload';
import {CommonStatusEnum} from "@/utils/constants";
export default {
name: "Category",
components: {
Editor, Treeselect, IconSelect, ImageUpload
Editor, Treeselect, ImageUpload
},
data() {
return {
//
loading: true,
//
exportLoading: false,
//
showSearch: true,
//
total: 0,
//
list: [],
//
@ -164,10 +137,7 @@ export default {
refreshTable: true,
//
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
status: null,
},
//
form: {},
@ -175,8 +145,8 @@ export default {
rules: {
parentId: [{required: true, message: "请选择上级分类", trigger: "blur"}],
name: [{required: true, message: "分类名称不能为空", trigger: "blur"}],
icon: [{required: true, message: "分类图不能为空", trigger: "blur"}],
bannerUrl: [{required: true, message: "分类图片不能为空", trigger: "blur"}],
picUrl: [{required: true, message: "分类图不能为空", trigger: "blur"}],
sort: [{required: true, message: "分类排序不能为空", trigger: "blur"}],
status: [{required: true, message: "开启状态不能为空", trigger: "blur"}],
}
};
@ -191,35 +161,11 @@ export default {
//
let params = {...this.queryParams};
//
listCategory(params).then(response => {
getProductCategoryList(params).then(response => {
this.list = this.handleTree(response.data, "id", "parentId");
this.loading = false;
});
},
//
iconSelected(name) {
this.form.icon = name;
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.name,
children: node.children
};
},
/** 查询分类下拉树结构 */
getTreeselect() {
listCategory().then(response => {
this.parentCategoryOptions = [];
const menu = {id: 0, name: '主分类', children: []};
menu.children = this.handleTree(response.data, "id", "parentId");
this.parentCategoryOptions.push(menu);
});
},
/** 取消按钮 */
cancel() {
this.open = false;
@ -231,11 +177,10 @@ export default {
id: undefined,
parentId: undefined,
name: undefined,
icon: undefined,
bannerUrl: undefined,
sort: undefined,
pirUrl: undefined,
sort: 0,
description: undefined,
status: undefined,
status: CommonStatusEnum.ENABLE,
};
this.resetForm("form");
},
@ -260,16 +205,14 @@ export default {
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.getTreeselect();
this.open = true;
this.title = "添加商品分类";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.getTreeselect();
const id = row.id;
getCategory(id).then(response => {
getProductCategory(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改商品分类";
@ -283,7 +226,7 @@ export default {
}
//
if (this.form.id != null) {
updateCategory(this.form).then(response => {
updateProductCategory(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
@ -291,7 +234,7 @@ export default {
return;
}
//
createCategory(this.form).then(response => {
createProductCategory(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
@ -302,36 +245,13 @@ export default {
handleDelete(row) {
const id = row.id;
this.$modal.confirm('是否确认删除商品分类编号为"' + id + '"的数据项?').then(function () {
return deleteCategory(id);
return deleteProductCategory(id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
});
},
/** 导出按钮操作 */
handleExport() {
//
let params = {...this.queryParams};
params.pageNo = undefined;
params.pageSize = undefined;
//
this.$modal.confirm('是否确认导出所有商品分类数据项?').then(() => {
this.exportLoading = true;
return exportCategoryExcel(params);
}).then(response => {
this.$download.excel(response, '商品分类.xls');
this.exportLoading = false;
}).catch(() => {
});
}
}
};
</script>
<style scoped lang="scss">
//
.img-height {
height: 150px;
}
</style>

View File

@ -283,12 +283,12 @@
<script>
import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu";
import {
createCategory,
deleteCategory,
createProductCategory,
deleteProductCategory,
exportCategoryExcel,
getCategory,
listCategory,
updateCategory
getProductCategory,
getProductCategoryList,
updateProductCategory
} from "@/api/mall/product/category";
import {
createProperty,
@ -585,7 +585,7 @@ export default {
/** 查询分类 */
getListCategory() {
//
listCategory().then(response => {
getProductCategoryList().then(response => {
this.categoryList = this.handleTree(response.data, "id", "parentId");
});