Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
c40ca133
authored
Aug 14, 2024
by
preschool
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of gitee.com:yudaocode/yudao-ui-admin-vue3
parents
cc1d2b19
521ae46c
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
106 additions
and
31 deletions
+106
-31
src/api/mall/product/property.ts
+10
-14
src/components/DictTag/src/DictTag.vue
+6
-6
src/views/mall/product/spu/components/SkuList.vue
+3
-3
src/views/mall/product/spu/form/ProductAttributes.vue
+32
-5
src/views/mall/product/spu/form/ProductPropertyAddForm.vue
+46
-1
src/views/mall/product/spu/form/SkuForm.vue
+9
-2
No files found.
src/api/mall/product/property.ts
View file @
c40ca133
...
@@ -24,20 +24,6 @@ export interface PropertyValueVO {
...
@@ -24,20 +24,6 @@ export interface PropertyValueVO {
remark
?:
string
remark
?:
string
}
}
/**
* 商品属性值的明细
*/
export
interface
PropertyValueDetailVO
{
/** 属性项的编号 */
propertyId
:
number
// 属性的编号
/** 属性的名称 */
propertyName
:
string
/** 属性值的编号 */
valueId
:
number
/** 属性值的名称 */
valueName
:
string
}
// ------------------------ 属性项 -------------------
// ------------------------ 属性项 -------------------
// 创建属性项
// 创建属性项
...
@@ -65,6 +51,11 @@ export const getPropertyPage = (params: PageParam) => {
...
@@ -65,6 +51,11 @@ export const getPropertyPage = (params: PageParam) => {
return
request
.
get
({
url
:
'/product/property/page'
,
params
})
return
request
.
get
({
url
:
'/product/property/page'
,
params
})
}
}
// 获得属性项精简列表
export
const
getPropertySimpleList
=
():
Promise
<
PropertyVO
[]
>
=>
{
return
request
.
get
({
url
:
'/product/property/simple-list'
})
}
// ------------------------ 属性值 -------------------
// ------------------------ 属性值 -------------------
// 获得属性值分页
// 获得属性值分页
...
@@ -91,3 +82,8 @@ export const updatePropertyValue = (data: PropertyValueVO) => {
...
@@ -91,3 +82,8 @@ export const updatePropertyValue = (data: PropertyValueVO) => {
export
const
deletePropertyValue
=
(
id
:
number
)
=>
{
export
const
deletePropertyValue
=
(
id
:
number
)
=>
{
return
request
.
delete
({
url
:
`/product/property/value/delete?id=
${
id
}
`
})
return
request
.
delete
({
url
:
`/product/property/value/delete?id=
${
id
}
`
})
}
}
// 获得属性值精简列表
export
const
getPropertyValueSimpleList
=
(
propertyId
:
number
):
Promise
<
PropertyValueVO
[]
>
=>
{
return
request
.
get
({
url
:
'/product/property/value/simple-list'
,
params
:
{
propertyId
}
})
}
src/components/DictTag/src/DictTag.vue
View file @
c40ca133
...
@@ -3,7 +3,7 @@ import { defineComponent, PropType, computed } from 'vue'
...
@@ -3,7 +3,7 @@ import { defineComponent, PropType, computed } from 'vue'
import
{
isHexColor
}
from
'@/utils/color'
import
{
isHexColor
}
from
'@/utils/color'
import
{
ElTag
}
from
'element-plus'
import
{
ElTag
}
from
'element-plus'
import
{
DictDataType
,
getDictOptions
}
from
'@/utils/dict'
import
{
DictDataType
,
getDictOptions
}
from
'@/utils/dict'
import
{
isArray
,
isString
,
isNumber
}
from
'@/utils/is'
import
{
isArray
,
isString
,
isNumber
,
isBoolean
}
from
'@/utils/is'
export
default
defineComponent
({
export
default
defineComponent
({
name
:
'DictTag'
,
name
:
'DictTag'
,
...
@@ -29,15 +29,15 @@ export default defineComponent({
...
@@ -29,15 +29,15 @@ export default defineComponent({
},
},
setup
(
props
)
{
setup
(
props
)
{
const
valueArr
:
any
=
computed
(()
=>
{
const
valueArr
:
any
=
computed
(()
=>
{
// 1.
是Number
类型的情况
// 1.
是 Number 类型和 Boolean
类型的情况
if
(
isNumber
(
props
.
value
))
{
if
(
isNumber
(
props
.
value
)
||
isBoolean
(
props
.
value
)
)
{
return
[
String
(
props
.
value
)]
return
[
String
(
props
.
value
)]
}
}
// 2.是字符串(进一步判断是否有包含分隔符号 -> props.sepSymbol )
// 2.
是字符串(进一步判断是否有包含分隔符号 -> props.sepSymbol )
else
if
(
isString
(
props
.
value
))
{
else
if
(
isString
(
props
.
value
))
{
return
props
.
value
.
split
(
props
.
separator
)
return
props
.
value
.
split
(
props
.
separator
)
}
}
// 3.数组
// 3.
数组
else
if
(
isArray
(
props
.
value
))
{
else
if
(
isArray
(
props
.
value
))
{
return
props
.
value
.
map
(
String
)
return
props
.
value
.
map
(
String
)
}
}
...
@@ -57,7 +57,7 @@ export default defineComponent({
...
@@ -57,7 +57,7 @@ export default defineComponent({
<
div
<
div
class
=
"dict-tag"
class
=
"dict-tag"
style
=
{{
style
=
{{
display
:
'flex'
,
display
:
'
inline-
flex'
,
gap
:
props
.
gutter
,
gap
:
props
.
gutter
,
justifyContent
:
'center'
,
justifyContent
:
'center'
,
alignItems
:
'center'
alignItems
:
'center'
...
...
src/views/mall/product/spu/components/SkuList.vue
View file @
c40ca133
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
>
>
<template
#
default=
"
{ row }">
<template
#
default=
"
{ row }">
<span
style=
"font-weight: bold; color: #40aaff"
>
<span
style=
"font-weight: bold; color: #40aaff"
>
{{
row
.
properties
[
index
]?.
valueName
}}
{{
row
.
properties
?.
[
index
]?.
valueName
}}
</span>
</span>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -168,7 +168,7 @@
...
@@ -168,7 +168,7 @@
>
>
<template
#
default=
"
{ row }">
<template
#
default=
"
{ row }">
<span
style=
"font-weight: bold; color: #40aaff"
>
<span
style=
"font-weight: bold; color: #40aaff"
>
{{
row
.
properties
[
index
]?.
valueName
}}
{{
row
.
properties
?.
[
index
]?.
valueName
}}
</span>
</span>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -248,7 +248,7 @@
...
@@ -248,7 +248,7 @@
>
>
<template
#
default=
"
{ row }">
<template
#
default=
"
{ row }">
<span
style=
"font-weight: bold; color: #40aaff"
>
<span
style=
"font-weight: bold; color: #40aaff"
>
{{
row
.
properties
[
index
]?.
valueName
}}
{{
row
.
properties
?.
[
index
]?.
valueName
}}
</span>
</span>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
...
src/views/mall/product/spu/form/ProductAttributes.vue
View file @
c40ca133
...
@@ -18,16 +18,28 @@
...
@@ -18,16 +18,28 @@
>
>
{{
value
.
name
}}
{{
value
.
name
}}
</el-tag>
</el-tag>
<el-input
<el-select
v-show=
"inputVisible(index)"
:id=
"`input$
{index}`"
:id=
"`input$
{index}`"
:ref="setInputRef"
:ref="setInputRef"
v-show="inputVisible(index)"
v-model="inputValue"
v-model="inputValue"
class="!w-20"
filterable
allow-create
default-first-option
:reserve-keyword="false"
size="small"
size="small"
class="!w-30"
@blur="handleInputConfirm(index, item.id)"
@blur="handleInputConfirm(index, item.id)"
@keyup.enter="handleInputConfirm(index, item.id)"
@keyup.enter="handleInputConfirm(index, item.id)"
@change="handleInputConfirm(index, item.id)"
>
<el-option
v-for=
"item2 in attributeOptions"
:key=
"item2.id"
:label=
"item2.name"
:value=
"item2.name"
/>
/>
</el-select>
<el-button
<el-button
v-show=
"!inputVisible(index)"
v-show=
"!inputVisible(index)"
class=
"button-new-tag ml-1"
class=
"button-new-tag ml-1"
...
@@ -42,7 +54,6 @@
...
@@ -42,7 +54,6 @@
</
template
>
</
template
>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
ElInput
}
from
'element-plus'
import
*
as
PropertyApi
from
'@/api/mall/product/property'
import
*
as
PropertyApi
from
'@/api/mall/product/property'
import
{
PropertyAndValues
}
from
'@/views/mall/product/spu/components'
import
{
PropertyAndValues
}
from
'@/views/mall/product/spu/components'
import
{
propTypes
}
from
'@/utils/propTypes'
import
{
propTypes
}
from
'@/utils/propTypes'
...
@@ -68,6 +79,7 @@ const setInputRef = (el: any) => {
...
@@ -68,6 +79,7 @@ const setInputRef = (el: any) => {
}
}
}
}
const
attributeList
=
ref
<
PropertyAndValues
[]
>
([])
// 商品属性列表
const
attributeList
=
ref
<
PropertyAndValues
[]
>
([])
// 商品属性列表
const
attributeOptions
=
ref
([]
as
PropertyApi
.
PropertyValueVO
[])
// 商品属性名称下拉框
const
props
=
defineProps
({
const
props
=
defineProps
({
propertyList
:
{
propertyList
:
{
type
:
Array
,
type
:
Array
,
...
@@ -100,15 +112,25 @@ const handleCloseProperty = (index: number) => {
...
@@ -100,15 +112,25 @@ const handleCloseProperty = (index: number) => {
}
}
/** 显示输入框并获取焦点 */
/** 显示输入框并获取焦点 */
const
showInput
=
async
(
index
)
=>
{
const
showInput
=
async
(
index
:
number
)
=>
{
attributeIndex
.
value
=
index
attributeIndex
.
value
=
index
inputRef
.
value
[
index
].
focus
()
inputRef
.
value
[
index
].
focus
()
// 获取属性下拉选项
await
getAttributeOptions
(
attributeList
.
value
[
index
].
id
)
}
}
/** 输入框失去焦点或点击回车时触发 */
/** 输入框失去焦点或点击回车时触发 */
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
handleInputConfirm
=
async
(
index
:
number
,
propertyId
:
number
)
=>
{
const
handleInputConfirm
=
async
(
index
:
number
,
propertyId
:
number
)
=>
{
if
(
inputValue
.
value
)
{
if
(
inputValue
.
value
)
{
// 重复添加校验
// TODO @芋艿:需要测试下
if
(
attributeList
.
value
[
index
].
values
.
find
((
item
)
=>
item
.
name
===
inputValue
.
value
))
{
message
.
warning
(
'已存在相同属性值,请重试'
)
attributeIndex
.
value
=
null
inputValue
.
value
=
''
return
}
// 保存属性值
// 保存属性值
try
{
try
{
const
id
=
await
PropertyApi
.
createPropertyValue
({
propertyId
,
name
:
inputValue
.
value
})
const
id
=
await
PropertyApi
.
createPropertyValue
({
propertyId
,
name
:
inputValue
.
value
})
...
@@ -122,4 +144,9 @@ const handleInputConfirm = async (index: number, propertyId: number) => {
...
@@ -122,4 +144,9 @@ const handleInputConfirm = async (index: number, propertyId: number) => {
attributeIndex
.
value
=
null
attributeIndex
.
value
=
null
inputValue
.
value
=
''
inputValue
.
value
=
''
}
}
/** 获取商品属性下拉选项 */
const
getAttributeOptions
=
async
(
propertyId
:
number
)
=>
{
attributeOptions
.
value
=
await
PropertyApi
.
getPropertyValueSimpleList
(
propertyId
)
}
</
script
>
</
script
>
src/views/mall/product/spu/form/ProductPropertyAddForm.vue
View file @
c40ca133
...
@@ -10,7 +10,22 @@
...
@@ -10,7 +10,22 @@
@
keydown
.
enter
.
prevent=
"submitForm"
@
keydown
.
enter
.
prevent=
"submitForm"
>
>
<el-form-item
label=
"属性名称"
prop=
"name"
>
<el-form-item
label=
"属性名称"
prop=
"name"
>
<el-input
v-model=
"formData.name"
placeholder=
"请输入名称"
/>
<el-select
v-model=
"formData.name"
filterable
allow-create
default-first-option
:reserve-keyword=
"false"
placeholder=
"请选择属性名称。如果不存在,可手动输入选择"
class=
"!w-360px"
>
<el-option
v-for=
"item in attributeOptions"
:key=
"item.id"
:label=
"item.name"
:value=
"item.name"
/>
</el-select>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
<template
#
footer
>
<template
#
footer
>
...
@@ -37,6 +52,7 @@ const formRules = reactive({
...
@@ -37,6 +52,7 @@ const formRules = reactive({
})
})
const
formRef
=
ref
()
// 表单 Ref
const
formRef
=
ref
()
// 表单 Ref
const
attributeList
=
ref
([])
// 商品属性列表
const
attributeList
=
ref
([])
// 商品属性列表
const
attributeOptions
=
ref
([]
as
PropertyApi
.
PropertyVO
[])
// 商品属性名称下拉框
const
props
=
defineProps
({
const
props
=
defineProps
({
propertyList
:
{
propertyList
:
{
type
:
Array
,
type
:
Array
,
...
@@ -60,11 +76,21 @@ watch(
...
@@ -60,11 +76,21 @@ watch(
const
open
=
async
()
=>
{
const
open
=
async
()
=>
{
dialogVisible
.
value
=
true
dialogVisible
.
value
=
true
resetForm
()
resetForm
()
// 加载列表
await
getAttributeOptions
()
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
/** 提交表单 */
const
submitForm
=
async
()
=>
{
const
submitForm
=
async
()
=>
{
// 情况一:如果是已存在的属性,直接结束,不提交表单新增
for
(
const
attrItem
of
attributeList
.
value
)
{
if
(
attrItem
.
name
===
formData
.
value
.
name
)
{
return
message
.
error
(
'该属性已存在,请勿重复添加'
)
}
}
// 情况二:如果是不存在的属性,则需要执行新增
// 校验表单
// 校验表单
if
(
!
formRef
)
return
if
(
!
formRef
)
return
const
valid
=
await
formRef
.
value
.
validate
()
const
valid
=
await
formRef
.
value
.
validate
()
...
@@ -80,6 +106,15 @@ const submitForm = async () => {
...
@@ -80,6 +106,15 @@ const submitForm = async () => {
...
formData
.
value
,
...
formData
.
value
,
values
:
[]
values
:
[]
})
})
// 判断最终提交的属性名称是否是用户下拉选择的 自己手动输入的属性名称就不执行emit获取该属性名下属性值列表
for
(
const
element
of
attributeOptions
.
value
)
{
if
(
element
.
name
===
formData
.
value
.
name
)
{
message
.
success
(
t
(
'common.createSuccess'
))
dialogVisible
.
value
=
false
return
}
}
// 关闭弹窗
message
.
success
(
t
(
'common.createSuccess'
))
message
.
success
(
t
(
'common.createSuccess'
))
dialogVisible
.
value
=
false
dialogVisible
.
value
=
false
}
finally
{
}
finally
{
...
@@ -94,4 +129,14 @@ const resetForm = () => {
...
@@ -94,4 +129,14 @@ const resetForm = () => {
}
}
formRef
.
value
?.
resetFields
()
formRef
.
value
?.
resetFields
()
}
}
/** 获取商品属性下拉选项 */
const
getAttributeOptions
=
async
()
=>
{
formLoading
.
value
=
true
try
{
attributeOptions
.
value
=
await
PropertyApi
.
getPropertySimpleList
()
}
finally
{
formLoading
.
value
=
false
}
}
</
script
>
</
script
>
src/views/mall/product/spu/form/SkuForm.vue
View file @
c40ca133
<!-- 商品发布 - 库存价格 -->
<!-- 商品发布 - 库存价格 -->
<
template
>
<
template
>
<el-form
ref=
"formRef"
:disabled=
"isDetail"
:model=
"formData"
:rules=
"rules"
label-width=
"120px"
>
<el-form
ref=
"formRef"
:disabled=
"isDetail"
:model=
"formData"
:rules=
"rules"
label-width=
"120px"
v-loading=
"formLoading"
>
<el-form-item
label=
"分销类型"
props=
"subCommissionType"
>
<el-form-item
label=
"分销类型"
props=
"subCommissionType"
>
<el-radio-group
<el-radio-group
v-model=
"formData.subCommissionType"
v-model=
"formData.subCommissionType"
...
@@ -94,7 +101,7 @@ const ruleConfig: RuleConfig[] = [
...
@@ -94,7 +101,7 @@ const ruleConfig: RuleConfig[] = [
]
]
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
formLoading
=
ref
(
false
)
const
props
=
defineProps
({
const
props
=
defineProps
({
propFormData
:
{
propFormData
:
{
type
:
Object
as
PropType
<
Spu
>
,
type
:
Object
as
PropType
<
Spu
>
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment