image-20230104123514646 image-20230104123514646 image-20230104123514646

需要完成如上功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
<template>
<div>
<!-- 调用三级分类全局组件 -->
<Category :scene="scene" />
<el-card style="margin: 10px 0px">
<div v-show="scene == 0">
<!-- 如果没有获取到c3Id 不会有属性列表值 button设置为display -->
<el-button
@click="addAttr"
type="primary"
size="default"
icon="Plus"
:disabled="categoryStore.c3Id ? false : true"
>
添加属性
</el-button>
<el-table border style="margin: 10px 0px" :data="attrArr">
<el-table-column
label="序号"
type="index"
align="center"
width="80px"
></el-table-column>
<el-table-column
label="属性名称"
width="120px"
prop="attrName"
></el-table-column>
<el-table-column label="属性值名称">
<template #="{ row, $index }">
<el-tag
style="margin: 5px"
v-for="(item, index) in row.attrValueList"
:key="item.id"
>
{{ item.valueName }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="120px">
<!-- row:已有的属性对象 -->
<template #="{ row, $index }">
<!-- 修改已有属性的按钮 -->
<el-button
type="primary"
size="small"
icon="Edit"
@click="updateAttr(row)"
></el-button>
<el-popconfirm
:title="`你确定删除${row.attrName}?`"
width="200px"
@confirm="deleteAttr(row.id)"
>
<template #reference>
<el-button
type="primary"
size="small"
icon="Delete"
></el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- 当scene == 1时 展示窗口 -->
<div v-show="scene == 1">
<!-- 展示添加属性与修改数据的结构 -->
<el-form :inline="true">
<el-form-item label="属性名称">
<el-input
placeholder="请你输入属性名称"
v-model="attrParams.attrName"
></el-input>
</el-form-item>
</el-form>
<!-- 当检测到有属性值的时候 下面的添加属性值按钮display -->
<el-button
@click="addAttrValue"
:disabled="attrParams.attrName ? false : true"
type="primary"
size="default"
icon="Plus"
>
添加属性值
</el-button>
<el-button type="primary" size="default" @click="cancel">
取消
</el-button>
<el-table
border
style="margin: 10px 0px"
:data="attrParams.attrValueList"
>
<el-table-column
label="序号"
width="80px"
type="index"
align="center"
></el-table-column>
<el-table-column label="属性值名称">
<!-- row:即为当前属性值对象 -->
<template #="{ row, $index }">
<el-input
:ref="(vc: any) => inputArr[$index] = vc"
v-if="row.flag"
@blur="toLook(row, $index)"
size="small"
placeholder="请你输入属性值名称"
v-model="row.valueName"
></el-input>
<div v-else @click="toEdit(row, $index)">{{ row.valueName }}</div>
</template>
</el-table-column>
<el-table-column label="属性值操作">
<template #="{ row, index }">
<el-button
type="primary"
size="small"
icon="Delete"
@click="attrParams.attrValueList.splice(index, 1)"
></el-button>
</template>
</el-table-column>
</el-table>
<el-button
type="primary"
size="default"
@click="save"
:disabled="attrParams.attrValueList.length > 0 ? false : true"
>
保存
</el-button>
<el-button type="primary" size="default" @click="cancel">
取消
</el-button>
</div>
</el-card>
</div>
</template>

<script setup lang="ts">
//组合式API函数watch
import { watch, ref, reactive, nextTick } from 'vue'
//引入获取已有属性与属性值接口
import { reqAttr, reqAddOrUpdateAttr, reqRemoveAttr } from '@/api/product/attr'
import type { AttrResponseData, Attr, AttrValue } from '@/api/product/attr/type'
//获取分类的仓库
import useCategoryStore from '@/store/modules/category'
import { ElMessage } from 'element-plus'
let categoryStore = useCategoryStore()
//存储已有的属性与属性值
let attrArr = ref<Attr[]>([])
//定义card组件内容切换变量
let scene = ref<number>(0) //scene=0,显示table,scene=1,展示添加与修改属性结构
//收集新增的属性的数据
let attrParams = reactive<Attr>({
attrName: '', //新增的属性的名字
attrValueList: [
//新增的属性值数组
],
categoryId: '', //三级分类的ID
categoryLevel: 3, //代表的是三级分类
})
//准备一个数组:将来存储对应的组件实例el-input
let inputArr = ref<any>([])
//监听仓库三级分类ID变化
watch(
() => categoryStore.c3Id,
() => {
//清空上一次查询的属性与属性值
attrArr.value = []
//保证三级分类得有才能发请求
if (!categoryStore.c3Id) return
//获取分类的ID
getAttr()
},
)
//获取已有的属性与属性值方法
const getAttr = async () => {
const { c1Id, c2Id, c3Id } = categoryStore
console.log(categoryStore)
//获取分类下的已有的属性与属性值
let result: AttrResponseData = await reqAttr(c1Id, c2Id, c3Id)
if (result.code == 200) {
attrArr.value = result.data
console.log(attrArr.value)
}
}
//添加属性按钮的回调
const addAttr = () => {
//每一次点击的时候,先清空一下数据再收集数据
Object.assign(attrParams, {
attrName: '', //新增的属性的名字
attrValueList: [
//新增的属性值数组
],
categoryId: categoryStore.c3Id, //三级分类的ID
categoryLevel: 3, //代表的是三级分类
})
//切换为添加与修改属性的结构
scene.value = 1
}
//table表格修改已有属性按钮的回调
const updateAttr = (row: Attr) => {
//切换为添加与修改属性的结构
scene.value = 1
//将已有的属性对象赋值给attrParams对象即为
//ES6->Object.assign进行对象的合并
Object.assign(attrParams, JSON.parse(JSON.stringify(row)))
}
//取消按钮的回调
const cancel = () => {
scene.value = 0
}
//添加属性值按钮的回调
const addAttrValue = () => {
//点击添加属性值按钮的时候,向数组添加一个属性值对象
attrParams.attrValueList.push({
valueName: '',
flag: true, //控制每一个属性值编辑模式与切换模式的切换
})
//获取最后el-input组件聚焦
nextTick(() => {
inputArr.value[attrParams.attrValueList.length - 1].focus()
})
}
//保存按钮的回调
const save = async () => {
//发请求
let result: any = await reqAddOrUpdateAttr(attrParams)
//添加属性|修改已有的属性已经成功
if (result.code == 200) {
//切换场景
scene.value = 0
//提示信息
ElMessage({
type: 'success',
message: attrParams.id ? '修改成功' : '添加成功',
})
//获取全部已有的属性与属性值
getAttr()
} else {
ElMessage({
type: 'error',
message: attrParams.id ? '修改失败' : '添加失败',
})
}
}

//属性值表单元素失却焦点事件回调
const toLook = (row: AttrValue, $index: number) => {
//非法情况判断1
if (row.valueName.trim() == '') {
//删除调用对应属性值为空的元素
attrParams.attrValueList.splice($index, 1)
//提示信息
ElMessage({
type: 'error',
message: '属性值不能为空',
})
return
}
//非法情况2
let repeat = attrParams.attrValueList.find((item) => {
//切记把当前失却焦点属性值对象从当前数组扣除判断
if (item != row) {
return item.valueName === row.valueName
}
})

if (repeat) {
//将重复的属性值从数组当中干掉
attrParams.attrValueList.splice($index, 1)
//提示信息
ElMessage({
type: 'error',
message: '属性值不能重复',
})
return
}
//相应的属性值对象flag:变为false,展示div
row.flag = false
}

//属性值div点击事件
const toEdit = (row: AttrValue, $index: number) => {
//相应的属性值对象flag:变为true,展示input
row.flag = true
//nextTick:响应式数据发生变化,获取更新的DOM(组件实例)
nextTick(() => {
inputArr.value[$index].focus()
})
}

//删除某一个已有的属性方法回调
const deleteAttr = async (attrId: number) => {
//发相应的删除已有的属性的请求
let result: any = await reqRemoveAttr(attrId)
//删除成功
if (result.code == 200) {
ElMessage({
type: 'success',
message: '删除成功',
})
//获取一次已有的属性与属性值
getAttr()
} else {
ElMessage({
type: 'error',
message: '删除失败',
})
}
}

//路由组件销毁的时候,把仓库分类相关的数据清空
// onBeforeUnmount(() => {
// //清空仓库的数据
// categoryStore.$reset()
// })
</script>

<style scoped></style>

其中这边的添加属性与属性值的编辑模式如下:

  • 添加属性值功能逻辑:
  • 该控件的展示与否需要通过属性名称是否有值来确认,当有值时,该控件展示
  • 该按钮的点击执行函数如下
1
2
3
4
5
6
7
8
9
10
11
12
//添加属性值按钮的回调
const addAttrValue = () => {
//点击添加属性值按钮的时候,向数组添加一个属性值对象
attrParams.attrValueList.push({
valueName: '',
flag: true, //控制每一个属性值编辑模式与切换模式的切换
})
//获取最后el-input组件聚焦
nextTick(() => {
inputArr.value[attrParams.attrValueList.length - 1].focus()
})
}
  • 其中flag用来控制展开与否 flag为true时展开 为flase时显示属性值数据
  • image-20230104123514646
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<el-table-column label="属性值名称">
<!-- row:即为当前属性值对象 -->
<template #="{ row, $index }">
<el-input
:ref="(vc: any) => inputArr[$index] = vc"
v-if="row.flag"
@blur="toLook(row, $index)"
size="small"
placeholder="请你输入属性值名称"
v-model="row.valueName"
></el-input>
<div v-else @click="toEdit(row, $index)">{{ row.valueName }}</div>
</template>
</el-table-column>

当我们点击属性值时跳转到toEdit函数 对属性值进行编辑

1
2
3
4
5
6
7
8
9
//属性值div点击事件
const toEdit = (row: AttrValue, $index: number) => {
//相应的属性值对象flag:变为true,展示input
row.flag = true
//nextTick:响应式数据发生变化,获取更新的DOM(组件实例)
nextTick(() => {
inputArr.value[$index].focus()
})
}

当我们输入完数据 表单blur时执行toLook函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//属性值表单元素失却焦点事件回调
const toLook = (row: AttrValue, $index: number) => {
//非法情况判断1
if (row.valueName.trim() == '') {
//删除调用对应属性值为空的元素
attrParams.attrValueList.splice($index, 1)
//提示信息
ElMessage({
type: 'error',
message: '属性值不能为空',
})
return
}
//非法情况2
let repeat = attrParams.attrValueList.find((item) => {
//遍历判断是否跟当前值重复
//切记把当前失却焦点属性值对象从当前数组扣除判断
if (item != row) {
return item.valueName === row.valueName
}
})

if (repeat) {
//将重复的属性值从数组当中干掉
attrParams.attrValueList.splice($index, 1)
//提示信息
ElMessage({
type: 'error',
message: '属性值不能重复',
})
return
}
//相应的属性值对象flag:变为false,展示div
row.flag = false
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<div v-show="scene == 1">
<!-- 展示添加属性与修改数据的结构 -->
<el-form :inline="true">
<el-form-item label="属性名称">
<el-input
placeholder="请你输入属性名称"
v-model="attrParams.attrName"
></el-input>
</el-form-item>
</el-form>
<el-button
@click="addAttrValue"
:disabled="attrParams.attrName ? false : true"
type="primary"
size="default"
icon="Plus"
>
添加属性值
</el-button>
<el-button type="primary" size="default" @click="cancel">
取消
</el-button>
<el-table
border
style="margin: 10px 0px"
:data="attrParams.attrValueList"
>
<el-table-column
label="序号"
width="80px"
type="index"
align="center"
></el-table-column>
<el-table-column label="属性值名称">
<!-- row:即为当前属性值对象 -->
<template #="{ row, $index }">
<el-input
:ref="(vc: any) => inputArr[$index] = vc"
v-if="row.flag"
@blur="toLook(row, $index)"
size="small"
placeholder="请你输入属性值名称"
v-model="row.valueName"
></el-input>
<div v-else @click="toEdit(row, $index)">{{ row.valueName }}</div>
</template>
</el-table-column>
<el-table-column label="属性值操作">
<template #="{ row, index }">
<el-button
type="primary"
size="small"
icon="Delete"
@click="attrParams.attrValueList.splice(index, 1)"
></el-button>
</template>
</el-table-column>
</el-table>
<el-button
type="primary"
size="default"
@click="save"
:disabled="attrParams.attrValueList.length > 0 ? false : true"
>
保存
</el-button>
<el-button type="primary" size="default" @click="cancel">
取消
</el-button>
</div>

其中保存执行函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//保存按钮的回调
const save = async () => {
//发请求
let result: any = await reqAddOrUpdateAttr(attrParams)
//添加属性|修改已有的属性已经成功
if (result.code == 200) {
//切换场景
scene.value = 0
//提示信息
ElMessage({
type: 'success',
message: attrParams.id ? '修改成功' : '添加成功',
})
//获取全部已有的属性与属性值
getAttr()
} else {
ElMessage({
type: 'error',
message: attrParams.id ? '修改失败' : '添加失败',
})
}
}