feat: 添加商品分类管理页面
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
export const list=(queryParams:object)=>{
|
||||
/**
|
||||
* 获取商品分类列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listCategories(queryParams:object){
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories',
|
||||
method: 'get',
|
||||
@@ -8,7 +13,12 @@ export const list=(queryParams:object)=>{
|
||||
})
|
||||
}
|
||||
|
||||
export const cascadeList=(queryParams:object)=> {
|
||||
/**
|
||||
* 获取商品分类级联器树形列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listCascadeCategories(queryParams:object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/cascade',
|
||||
method: 'get',
|
||||
@@ -16,16 +26,24 @@ export const cascadeList=(queryParams:object)=> {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const detail=(id:number)=> {
|
||||
/**
|
||||
* 获取商品分类详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getCategoryDetail(id:number){
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const add=(data:object)=> {
|
||||
/**
|
||||
* 添加商品分类
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addCategory(data:object){
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories',
|
||||
method: 'post',
|
||||
@@ -33,7 +51,13 @@ export const add=(data:object)=> {
|
||||
})
|
||||
}
|
||||
|
||||
export function update(id:number, data:object) {
|
||||
/**
|
||||
* 修改商品分类
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateCategory(id:number, data:object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'put',
|
||||
@@ -41,14 +65,25 @@ export function update(id:number, data:object) {
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids:string) {
|
||||
/**
|
||||
* 删除商品分类
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteCategories(ids:string) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function patch(id:number, data:object) {
|
||||
/**
|
||||
* 选择性修改商品分类
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateCategoryPart(id:number, data:object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'patch',
|
||||
|
||||
13
src/views/pms/category/components/Attribute.vue
Normal file
13
src/views/pms/category/components/Attribute.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Attribute"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
278
src/views/pms/category/components/Category.vue
Normal file
278
src/views/pms/category/components/Category.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<!-- 商品分类层级最多为三层,level字段标识 -->
|
||||
<template>
|
||||
<div class="component-container">
|
||||
|
||||
<el-tree
|
||||
v-loading="loading"
|
||||
ref="categoryTreeRef"
|
||||
:data="categoryOptions"
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
node-key="id"
|
||||
:expand-on-click-node="false"
|
||||
default-expand-all
|
||||
:accordion="true"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
|
||||
<template #default="scope">
|
||||
<div class="custom-tree-node">
|
||||
<span>
|
||||
<el-image
|
||||
v-show="scope.data.level == 3"
|
||||
:src="scope.data.iconUrl"
|
||||
style="width: 30px; height: 30px;
|
||||
vertical-align: middle"
|
||||
/>
|
||||
{{ scope.data.name }}
|
||||
</span>
|
||||
<span>
|
||||
<el-button
|
||||
v-show="scope.data.level != 3 "
|
||||
type="primary"
|
||||
size="mini"
|
||||
icon="Plus"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleAdd(scope.data)"/>
|
||||
<el-button
|
||||
v-show="scope.data.id !== 0"
|
||||
type="warning"
|
||||
:icon="Edit"
|
||||
size="mini"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.data)"/>
|
||||
<el-button
|
||||
v-show="scope.data.id && (!scope.data.children || scope.data.children.length <= 0)"
|
||||
type="danger"
|
||||
size="mini"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.node, scope.data)"/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
||||
<el-dialog
|
||||
:title="dialog.title"
|
||||
v-model="dialog.visible"
|
||||
width="750px"
|
||||
>
|
||||
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
>
|
||||
<el-form-item label="上级分类" prop="parentId">
|
||||
<el-input v-model="parent.name" readonly/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input v-model="formData.name"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分类图标" prop="iconUrl">
|
||||
<single-upload v-model="formData.iconUrl"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="显示状态" prop="visible">
|
||||
<el-radio-group v-model="formData.visible">
|
||||
<el-radio :label="1">显示</el-radio>
|
||||
<el-radio :label="0">隐藏</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {listCategories, addCategory, updateCategory, deleteCategories} from '@/api/pms/category'
|
||||
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue'
|
||||
import {getCurrentInstance, onMounted, reactive, ref, toRefs, unref} from "vue";
|
||||
import {ElForm, ElMessage, ElMessageBox, ElTree} from "element-plus";
|
||||
|
||||
const emit = defineEmits(['categoryClick'])
|
||||
|
||||
const categoryTreeRef=ref(ElTree)
|
||||
const dataFormRef=ref(ElForm)
|
||||
|
||||
const state = reactive({
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
ids:[],
|
||||
queryParam: {},
|
||||
categoryOptions: [] as Array<any>,
|
||||
formData: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
parentId: 0,
|
||||
level: undefined,
|
||||
iconUrl: undefined,
|
||||
visible: 1,
|
||||
sort: 100
|
||||
},
|
||||
rules: {
|
||||
parentId: [{
|
||||
required: true, message: '请选择上级分类', trigger: 'blur'
|
||||
}],
|
||||
name: [{
|
||||
required: true, message: '请输入分类名称', trigger: 'blur'
|
||||
}]
|
||||
},
|
||||
dialog: {
|
||||
title: '',
|
||||
visible: false
|
||||
},
|
||||
parent: {},
|
||||
current: {}
|
||||
})
|
||||
|
||||
const {loading, categoryOptions, formData, rules, dialog} = toRefs(state)
|
||||
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true
|
||||
listCategories(state.queryParam).then(response => {
|
||||
state.categoryOptions = [{
|
||||
id: 0,
|
||||
name: '全部分类',
|
||||
parentId: 0,
|
||||
level: 0,
|
||||
children: response.data
|
||||
}]
|
||||
state.loading = false
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function handleNodeClick(row:any) {
|
||||
const categoryTree=unref(categoryTreeRef)
|
||||
const parentNode = categoryTree.getNode(row.parentId)
|
||||
|
||||
state.parent = {
|
||||
id: parentNode.key,
|
||||
name: parentNode.label,
|
||||
level: row.level
|
||||
}
|
||||
state.current = JSON.parse(JSON.stringify(row))
|
||||
emit('categoryClick', row)
|
||||
}
|
||||
|
||||
|
||||
function handleAdd(row: any) {
|
||||
resetForm()
|
||||
state.dialog = {
|
||||
title: '新增商品分类',
|
||||
visible: true
|
||||
}
|
||||
if (row.id != null) { // 行点击新增
|
||||
state.parent = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
level: row.level
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
resetForm()
|
||||
handleNodeClick(row)
|
||||
state.dialog = {
|
||||
title: '修改商品分类',
|
||||
visible: true
|
||||
}
|
||||
Object.assign( state.formData ,state.current)
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
const form = unref(dataFormRef)
|
||||
form.validate((valid: any) => {
|
||||
if (valid) {
|
||||
if (state.formData.id) {
|
||||
updateCategory(state.formData.id, state.formData).then(response => {
|
||||
ElMessage.success('修改成功')
|
||||
state.dialog.visible = false
|
||||
handleQuery()
|
||||
})
|
||||
} else {
|
||||
addCategory(state.formData).then(response => {
|
||||
ElMessage.success('新增成功')
|
||||
state.dialog.visible = false
|
||||
handleQuery()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleDelete(row: any) {
|
||||
const ids = [row.id || state.ids].join(',')
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteCategories(ids).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
handleQuery()
|
||||
})
|
||||
}).catch(() =>
|
||||
ElMessage.info('已取消删除')
|
||||
)
|
||||
}
|
||||
function resetForm() {
|
||||
state.formData = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
parentId: 0,
|
||||
level: undefined,
|
||||
iconUrl: undefined,
|
||||
visible: 1,
|
||||
sort: 100
|
||||
}
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
resetForm()
|
||||
state.dialog.visible = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.el-divider--horizontal {
|
||||
margin: 30px 0 15px;
|
||||
}
|
||||
</style>
|
||||
55
src/views/pms/category/index.vue
Normal file
55
src/views/pms/category/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="14" :xs="24">
|
||||
<el-card class="box-card" shadow="always">
|
||||
<template #header>
|
||||
<svg-icon color="#333" icon-class="menu"/>
|
||||
商品分类
|
||||
</template>
|
||||
<category ref="categoryRef" @categoryClick="handleCategoryClick"/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="10" :xs="24">
|
||||
<el-card class="box-card" shadow="always">
|
||||
<template #header>
|
||||
<svg-icon color="#333" icon-class="menu"/>
|
||||
商品属性
|
||||
</template>
|
||||
<!-- 商品规格 -->
|
||||
<attribute ref="specificationRef" :attributeType="1"/>
|
||||
<!-- 商品属性 -->
|
||||
<attribute ref="attributeRef" :attributeType="2"/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import Category from './components/Category.vue'
|
||||
import Attribute from './components/Attribute.vue'
|
||||
|
||||
import {reactive} from "vue";
|
||||
|
||||
const state = reactive({
|
||||
categoryId: undefined,
|
||||
categoryName: ''
|
||||
})
|
||||
|
||||
function handleCategoryClick(categoryRow: any) {
|
||||
if (categoryRow) {
|
||||
state.categoryId = categoryRow.id
|
||||
state.categoryName = categoryRow.name
|
||||
} else {
|
||||
state.categoryId = undefined
|
||||
state.categoryName =''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -108,7 +108,7 @@
|
||||
<script setup lang="ts">
|
||||
import {Search, Refresh} from '@element-plus/icons'
|
||||
import {page, removeGoods} from '@/api/pms/goods'
|
||||
import {cascadeList} from '@/api/pms/category'
|
||||
import {listCascadeCategories} from '@/api/pms/category'
|
||||
import {reactive, ref,onMounted, toRefs} from 'vue'
|
||||
import {ElMessage, ElMessageBox, ElTree} from 'element-plus'
|
||||
import { getCurrentInstance } from 'vue'
|
||||
@@ -152,7 +152,7 @@ function loadData() {
|
||||
}
|
||||
|
||||
function loadCategoryOptions() {
|
||||
cascadeList({}).then(response => {
|
||||
listCascadeCategories({}).then(response => {
|
||||
state.categoryOptions = ref(response.data)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user