feat(category): 商品分类和规格属性升级Vue3完成

This commit is contained in:
郝先瑞
2022-01-03 13:51:19 +08:00
parent ddddb2f36e
commit f704162af1
4 changed files with 248 additions and 40 deletions

30
src/api/pms/attribute.ts Normal file
View File

@@ -0,0 +1,30 @@
import request from '@/utils/request'
/**
* 获取商品属性列表
*
* @param params
*/
export function listAttributes(params:object) {
return request({
url: '/mall-pms/api/v1/attributes',
method: 'get',
params: params
})
}
/**
* 批量修改商品属性
*
* @param data
*/
export function saveAttributeBatch(data:object) {
return request({
url: '/mall-pms/api/v1/attributes/batch',
method: 'post',
data: data
})
}

View File

@@ -1,13 +1,166 @@
<template> <template>
<div class="components-container">
<el-card class="box-card" shadow="always">
<el-row>
<el-col :span="12">
<el-tag type="success" v-if="category && category.name">{{ category.name }} {{ attributeTypeName }} </el-tag>
<el-tag v-else type="info"><i class="el-icon-info"></i> 请选择商品分类</el-tag>
</el-col>
<el-col :span="12" style="text-align: right">
<el-button type="primary" :icon="Check" size="mini" @click="submitForm">提交</el-button>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-form
ref="form"
:model="formData"
:disabled="category?.childrenLen>0"
label-width="100"
>
<el-form-item
v-for="(item, index) in formData.attributes"
:label="attributeTypeName + (index+1)"
:prop="'attributes.' + index + '.name'"
:rules="rules.attribute.name"
>
<el-input v-model="item.name" style="width: 300px"/>
<el-button
v-if="index===0"
type="success"
:icon="Plus"
circle
plain
size="mini"
@click.prevent="handleAdd(index)"
style="margin-left: 15px"
/>
<el-button
type="danger"
:icon="Delete"
plain
circle
size="mini"
@click.prevent="handleDelete(index)"
style="margin-left: 15px"
/>
</el-form-item>
</el-form>
</el-row>
</el-card>
</div>
</template> </template>
<script> <script setup lang="ts">
export default { import {listAttributes, saveAttributeBatch} from "@/api/pms/attribute";
name: "Attribute" import {computed, reactive, toRefs, watch} from "vue";
import {Plus, Check, Delete} from '@element-plus/icons'
import {ElMessage} from "element-plus";
import {listRoleMenuIds} from "@api/system/role";
import SvgIcon from '@/components/SvgIcon/index.vue';
const props = defineProps({
attributeType: {
type: Number,
default: 1
},
category: {
type: Object,
default: {
id: undefined,
name: '',
childrenLen: 0
}
}
})
const attributeTypeName = computed(() => props.attributeType === 1 ? '规格' : '属性')
const attributeNameValidator = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('请输入' + attributeTypeName.value + '名称'))
} else {
callback();
}
} }
const state = reactive({
formData: {
categoryId: undefined,
type: 1,
attributes: [{
id: undefined,
name: ''
}]
},
rules: {
attribute: {
name: [
{required: true, validator: attributeNameValidator, trigger: 'blur'}
]
}
}
})
const {formData, rules} = toRefs(state)
watch(() => props.category.id as any, (newVal, oldVal) => {
const categoryId = props.category.id
if (categoryId) {
listAttributes({categoryId: categoryId,type:props.attributeType}).then(response => {
const {data} = response
if (data && data.length > 0) {
state.formData.attributes = response.data
} else {
state.formData.attributes = [{
id: undefined,
name: ''
}]
}
})
} else {
state.formData.attributes = [{
id: undefined,
name: ''
}]
}
})
function handleAdd() {
state.formData.attributes.push({
id: undefined,
name: ''
})
}
function handleDelete(index: number) {
if (state.formData.attributes.length == 1) {
state.formData.attributes = [{
id: undefined,
name: ''
}]
return
}
state.formData.attributes.splice(index, 1)
}
function submitForm() {
state.formData.categoryId = props.category.id
state.formData.type = props.attributeType
saveAttributeBatch(state.formData).then(() => {
ElMessage.success('提交成功')
})
}
</script> </script>
<style scoped> <style scoped>
.components-container{
margin-bottom: 20px;
}
</style> </style>

View File

@@ -13,19 +13,24 @@
:accordion="true" :accordion="true"
@node-click="handleNodeClick" @node-click="handleNodeClick"
> >
<template #default="scope"> <template #default="scope">
<div class="custom-tree-node"> <div class="custom-tree-node">
<span> <span>
<el-image <el-image
v-show="scope.data.level == 3" v-show="scope.data.level == 3 "
:src="scope.data.iconUrl" :src="scope.data.iconUrl"
style="width: 30px; height: 30px; style="width: 20px; height:20px; vertical-align: middle;margin-top: -5px"
vertical-align: middle" >
/> <template #error>
{{ scope.data.name }} <div class="image-slot">
</span> <Picture style="width: 20px; height:20px;"/>
<span> </div>
</template>
</el-image>
{{ scope.data.name }}
</span>
<span>
<el-button <el-button
v-show="scope.data.level != 3 " v-show="scope.data.level != 3 "
type="primary" type="primary"
@@ -49,7 +54,7 @@
:icon="Delete" :icon="Delete"
circle circle
plain plain
@click.stop="handleDelete(scope.node, scope.data)"/> @click.stop="handleDelete(scope.data)"/>
</span> </span>
</div> </div>
</template> </template>
@@ -65,6 +70,7 @@
ref="dataFormRef" ref="dataFormRef"
:model="formData" :model="formData"
:rules="rules" :rules="rules"
label-width="100px"
> >
<el-form-item label="上级分类" prop="parentId"> <el-form-item label="上级分类" prop="parentId">
<el-input v-model="parent.name" readonly/> <el-input v-model="parent.name" readonly/>
@@ -109,13 +115,13 @@ import {ElForm, ElMessage, ElMessageBox, ElTree} from "element-plus";
const emit = defineEmits(['categoryClick']) const emit = defineEmits(['categoryClick'])
const categoryTreeRef=ref(ElTree) const categoryTreeRef = ref(ElTree)
const dataFormRef=ref(ElForm) const dataFormRef = ref(ElForm)
const state = reactive({ const state = reactive({
// 遮罩层 // 遮罩层
loading: true, loading: true,
ids:[], ids: [],
queryParam: {}, queryParam: {},
categoryOptions: [] as Array<any>, categoryOptions: [] as Array<any>,
formData: { formData: {
@@ -143,8 +149,7 @@ const state = reactive({
current: {} current: {}
}) })
const {loading, categoryOptions, formData, rules, dialog} = toRefs(state) const {loading, categoryOptions, formData, rules, dialog, parent} = toRefs(state)
function handleQuery() { function handleQuery() {
state.loading = true state.loading = true
@@ -161,8 +166,8 @@ function handleQuery() {
} }
function handleNodeClick(row:any) { function handleNodeClick(row: any) {
const categoryTree=unref(categoryTreeRef) const categoryTree = unref(categoryTreeRef)
const parentNode = categoryTree.getNode(row.parentId) const parentNode = categoryTree.getNode(row.parentId)
state.parent = { state.parent = {
@@ -197,7 +202,7 @@ function handleUpdate(row: any) {
title: '修改商品分类', title: '修改商品分类',
visible: true visible: true
} }
Object.assign( state.formData ,state.current) Object.assign(state.formData, state.current)
} }
function submitForm() { function submitForm() {
@@ -211,7 +216,12 @@ function submitForm() {
handleQuery() handleQuery()
}) })
} else { } else {
addCategory(state.formData).then(response => { const parentCategory= state.parent as any
console.log('parent',parentCategory)
state.formData.parentId = parentCategory.id
state.formData.level = parentCategory.level+1
addCategory(state.formData).then(() => {
ElMessage.success('新增成功') ElMessage.success('新增成功')
state.dialog.visible = false state.dialog.visible = false
handleQuery() handleQuery()
@@ -232,10 +242,9 @@ function handleDelete(row: any) {
ElMessage.success('删除成功') ElMessage.success('删除成功')
handleQuery() handleQuery()
}) })
}).catch(() => })
ElMessage.info('已取消删除')
)
} }
function resetForm() { function resetForm() {
state.formData = { state.formData = {
id: undefined, id: undefined,
@@ -259,6 +268,10 @@ onMounted(() => {
</script> </script>
<style> <style>
.component-container {
height: 100%;
}
.custom-tree-node { .custom-tree-node {
flex: 1; flex: 1;
display: flex; display: flex;

View File

@@ -4,7 +4,7 @@
<el-col :span="14" :xs="24"> <el-col :span="14" :xs="24">
<el-card class="box-card" shadow="always"> <el-card class="box-card" shadow="always">
<template #header> <template #header>
<svg-icon color="#333" icon-class="menu"/> <svg-icon icon-class="menu"/>
商品分类 商品分类
</template> </template>
<category ref="categoryRef" @categoryClick="handleCategoryClick"/> <category ref="categoryRef" @categoryClick="handleCategoryClick"/>
@@ -14,13 +14,13 @@
<el-col :span="10" :xs="24"> <el-col :span="10" :xs="24">
<el-card class="box-card" shadow="always"> <el-card class="box-card" shadow="always">
<template #header> <template #header>
<svg-icon color="#333" icon-class="menu"/> <svg-icon icon-class="menu"/>
商品属性 {{category.name}} 规格属性
</template> </template>
<!-- 商品规格 --> <!-- 商品规格 -->
<attribute ref="specificationRef" :attributeType="1"/> <attribute ref="specificationRef" :attributeType="1" :category="category"/>
<!-- 商品属性 --> <!-- 商品属性 -->
<attribute ref="attributeRef" :attributeType="2"/> <attribute ref="attributeRef" :attributeType="2" :category="category"/>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
@@ -31,21 +31,33 @@
import Category from './components/Category.vue' import Category from './components/Category.vue'
import Attribute from './components/Attribute.vue' import Attribute from './components/Attribute.vue'
import SvgIcon from '@/components/SvgIcon/index.vue';
import {reactive} from "vue"; import {reactive, toRefs} from "vue";
const state = reactive({ const state = reactive({
categoryId: undefined, category:{
categoryName: '' id: undefined,
name: '',
childrenLen: 0
}
}) })
const {category}=toRefs(state)
function handleCategoryClick(categoryRow: any) { function handleCategoryClick(categoryRow: any) {
if (categoryRow) { if (categoryRow) {
state.categoryId = categoryRow.id state.category={
state.categoryName = categoryRow.name id: categoryRow.id,
name: categoryRow.name,
childrenLen: categoryRow.children.length
}
} else { } else {
state.categoryId = undefined state.category={
state.categoryName ='' id: undefined,
name: '',
childrenLen: 0
}
} }
} }
</script> </script>