Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
corporateCulture-qd
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王立鹏
corporateCulture-qd
Commits
ca28f62e
Commit
ca28f62e
authored
Feb 06, 2026
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 20331】 feat: 优化选择标签组件、增加上传excel的组件
parent
0f477de8
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
161 additions
and
71 deletions
+161
-71
index.vue
src/components/common/SelectTags/index.vue
+86
-70
types.ts
src/components/common/SelectTags/types.ts
+2
-1
index.vue
src/components/common/UploadExcel/index.vue
+73
-0
No files found.
src/components/common/SelectTags/index.vue
View file @
ca28f62e
<
template
>
// 选中的可能是 可能是 多选: [id1,id2] 或者 'id1,id2' 单选 'id1' 单选 number这种不考虑处理了
<div
class=
"tag-selector"
>
<!-- 已选标签区域 -->
<div
class=
"selected-tags"
>
<!-- 添加标签按钮 -->
<el-popover
placement=
"top"
:width=
"300"
trigger=
"click"
>
<template
#
reference
>
<el-button
class=
"button-new-tag"
size=
"small"
>
+ 添加标签
</el-button>
</
template
>
<!-- 暂时不加搜索输入框 -->
<!-- <div class="search-section mb-4">
<el-input
v-model="searchKeyword"
placeholder="Enter键添加标签"
class="search-input"
clearable
@keyup.enter="addTagFromSearch"
>
<template #suffix>
<span class="text-gray-400 text-sm"
>{{ searchKeyword.length }} / {{ maxTagLength }}</span
>
</template>
</el-input>
</div> -->
<!-- 推荐标签区域 -->
<div
class=
"recommended-section"
>
<div
class=
"section-title mb-3 text-gray-600 text-sm"
>
官方标签列表
</div>
<div
class=
"tags-grid"
>
<el-tag
v-for=
"tag in filteredRecommendedTags"
:key=
"tag.id"
:type=
"arryrOfModelValue.includes(tag.id) ? 'primary' : 'info'"
:effect=
"arryrOfModelValue.includes(tag.id) ? 'dark' : 'plain'"
class=
"tag-item cursor-pointer mr-2 mb-2"
@
click=
"toggleTag(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
</div>
</el-popover>
<div
class=
"flex flex-wrap gap-2 mt-2"
>
<el-tag
v-for=
"tag in selectedTags"
:key=
"tag.id"
closable
type=
"primary"
@
close=
"removeTag(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
</div>
</div>
</template>
// 选中的可能是 可能是 多选 [id1,id2] 或者 'id1,id2' 或者 (单选 number这种不考虑处理了
可以在父组件自己处理)
<
script
setup
lang=
"ts"
generic=
"T extends string | number[] | number"
>
<
script
setup
lang=
"ts"
generic=
"T extends string | number[] | number"
>
import
{
useTagsStore
}
from
'@/stores/tags'
import
{
useTagsStore
}
from
'@/stores/tags'
import
{
storeToRefs
}
from
'pinia'
import
{
storeToRefs
}
from
'pinia'
import
type
{
TagItemDto
}
from
'@/api/tag/types'
import
type
{
TagItemDto
}
from
'@/api/tag/types'
import
type
{
SelectTagProps
}
from
'./types'
import
type
{
SelectTagProps
}
from
'./types'
const
{
maxSelectedTags
=
1
,
filterTagsFn
,
tagType
=
'culture'
}
=
defineProps
<
SelectTagProps
>
()
import
{
TagTypeEnum
}
from
'@/constants'
const
{
maxSelectedTags
=
1
,
filterTagsFn
,
tagType
=
TagTypeEnum
.
CULTURE_TAG
,
}
=
defineProps
<
SelectTagProps
>
()
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
selected
:
[
tag
?:
TagItemDto
]
selected
:
[
tag
?:
TagItemDto
]
}
>
()
}
>
()
const
tagsStore
=
useTagsStore
()
const
tagsStore
=
useTagsStore
()
const
{
tagList
:
cultureTagList
,
relatedScenariosTagList
}
=
storeToRefs
(
tagsStore
)
const
{
tagList
:
cultureTagList
,
const
tagList
=
computed
<
TagItemDto
[]
>
(()
=>
relatedScenariosTagList
,
tagType
===
'culture'
?
cultureTagList
.
value
:
relatedScenariosTagList
.
value
,
yearRecommendTagList
,
)
}
=
storeToRefs
(
tagsStore
)
const
tagList
=
computed
<
TagItemDto
[]
>
(()
=>
{
if
(
tagType
===
TagTypeEnum
.
CULTURE_TAG
)
{
return
cultureTagList
.
value
}
else
if
(
tagType
===
TagTypeEnum
.
SCENE_TAG
)
{
return
relatedScenariosTagList
.
value
}
else
if
(
tagType
===
TagTypeEnum
.
YEAR_TAG
)
{
return
yearRecommendTagList
.
value
}
return
[]
})
const
filterTags
=
computed
(()
=>
{
const
filterTags
=
computed
(()
=>
{
if
(
filterTagsFn
)
{
if
(
filterTagsFn
)
{
...
@@ -136,10 +92,10 @@ const filteredRecommendedTags = computed(() => {
...
@@ -136,10 +92,10 @@ const filteredRecommendedTags = computed(() => {
const
addTag
=
(
tagId
:
number
)
=>
{
const
addTag
=
(
tagId
:
number
)
=>
{
if
(
arryrOfModelValue
.
value
.
length
>=
maxSelectedTags
)
if
(
arryrOfModelValue
.
value
.
length
>=
maxSelectedTags
)
return
ElMessage
.
warning
(
`最多只能选择
${
maxSelectedTags
}
个标签`
)
return
ElMessage
.
warning
(
{
message
:
`最多只能选择
${
maxSelectedTags
}
个标签`
,
plain
:
true
}
)
// 不能直接push 触发不了computed 的 set
// 不能直接push 触发不了computed 的 set
arryrOfModelValue
.
value
=
[...
arryrOfModelValue
.
value
,
tagId
]
arryrOfModelValue
.
value
=
[...
arryrOfModelValue
.
value
,
tagId
]
ElMessage
.
success
(
'标签添加成功'
)
ElMessage
.
success
(
{
message
:
'标签添加成功'
,
plain
:
true
}
)
emit
(
'selected'
,
filterTags
.
value
.
find
((
tag
)
=>
tag
.
id
===
tagId
)
!
)
emit
(
'selected'
,
filterTags
.
value
.
find
((
tag
)
=>
tag
.
id
===
tagId
)
!
)
}
}
...
@@ -160,3 +116,63 @@ const toggleTag = (tagId: number) => {
...
@@ -160,3 +116,63 @@ const toggleTag = (tagId: number) => {
}
}
}
}
</
script
>
</
script
>
<
template
>
<div
class=
"tag-selector"
>
<!-- 已选标签区域 -->
<div
class=
"selected-tags"
>
<!-- 添加标签按钮 -->
<el-popover
placement=
"top"
:width=
"300"
trigger=
"click"
>
<template
#
reference
>
<el-button
class=
"button-new-tag"
size=
"small"
>
+ 添加标签
</el-button>
</
template
>
<!-- 暂时不加搜索输入框 -->
<!-- <div class="search-section mb-4">
<el-input
v-model="searchKeyword"
placeholder="Enter键添加标签"
class="search-input"
clearable
@keyup.enter="addTagFromSearch"
>
<template #suffix>
<span class="text-gray-400 text-sm"
>{{ searchKeyword.length }} / {{ maxTagLength }}</span
>
</template>
</el-input>
</div> -->
<!-- 推荐标签区域 -->
<div
class=
"recommended-section"
>
<div
class=
"section-title mb-3 text-gray-600 text-sm"
>
官方标签列表
</div>
<div
class=
"tags-grid"
>
<el-tag
v-for=
"tag in filteredRecommendedTags"
:key=
"tag.id"
:type=
"arryrOfModelValue.includes(tag.id) ? 'primary' : 'info'"
:effect=
"arryrOfModelValue.includes(tag.id) ? 'dark' : 'plain'"
class=
"tag-item cursor-pointer mr-2 mb-2"
@
click=
"toggleTag(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
</div>
</el-popover>
<div
class=
"flex flex-wrap gap-2 mt-2"
>
<el-tag
v-for=
"tag in selectedTags"
:key=
"tag.id"
closable
type=
"primary"
@
close=
"removeTag(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
</div>
</div>
</template>
src/components/common/SelectTags/types.ts
View file @
ca28f62e
import
type
{
TagItemDto
}
from
'@/api/tag/types'
import
type
{
TagItemDto
}
from
'@/api/tag/types'
import
{
TagTypeEnum
}
from
'@/constants'
export
type
SelectTagProps
=
{
export
type
SelectTagProps
=
{
maxSelectedTags
?:
number
maxSelectedTags
?:
number
filterTagsFn
?:
(
tags
:
TagItemDto
[])
=>
TagItemDto
[]
filterTagsFn
?:
(
tags
:
TagItemDto
[])
=>
TagItemDto
[]
tagType
?:
'culture'
|
'related_scenarios'
tagType
?:
TagTypeEnum
}
}
src/components/common/UploadExcel/index.vue
0 → 100644
View file @
ca28f62e
// 导入excel相关
<
script
setup
lang=
"tsx"
generic=
"T"
>
import
type
{
BackendServiceResult
}
from
'@/utils/request/types'
const
props
=
defineProps
<
{
api
:
(
file
:
File
,
onProgress
?:
(
progress
:
number
)
=>
void
)
=>
Promise
<
BackendServiceResult
<
T
[]
>>
}
>
()
const
emit
=
defineEmits
<
{
success
:
[]
error
:
[
errorList
:
T
[]]
}
>
()
const
fileInput
=
useTemplateRef
<
HTMLInputElement
>
(
'fileInput'
)
const
uploadProgress
=
ref
(
0
)
const
handleChange
=
async
(
e
:
Event
)
=>
{
uploadProgress
.
value
=
0
const
file
=
(
e
.
target
as
HTMLInputElement
).
files
?.[
0
]
if
(
!
file
)
return
const
notificationInstance
=
ElNotification
({
title
:
'上传文件进度'
,
message
:
()
=>
(
<
div
>
<
el
-
progress
indeterminate
percentage
=
{
uploadProgress
.
value
}
duration
=
{
0
}
status
=
{
uploadProgress
.
value
===
100
?
'success'
:
''
}
/
>
<
/div
>
),
duration
:
0
,
})
try
{
await
props
.
api
(
file
,
(
progress
)
=>
{
uploadProgress
.
value
=
progress
})
setTimeout
(()
=>
{
ElMessage
.
success
(
'上传成功'
)
},
1000
)
emit
(
'success'
)
}
catch
(
error
:
any
)
{
// 解析失败信息
console
.
error
(
error
)
if
(
error
.
code
===
501
)
{
// 部分上传的数据不对 有错误
emit
(
'error'
,
error
.
data
as
T
[])
}
else
{
console
.
error
(
error
)
emit
(
'error'
,
[])
}
}
finally
{
;(
e
.
target
as
HTMLInputElement
).
value
=
''
setTimeout
(()
=>
{
notificationInstance
.
close
()
setTimeout
(()
=>
{
uploadProgress
.
value
=
0
},
300
)
},
1500
)
}
}
</
script
>
<
template
>
<el-button
:loading=
"uploadProgress > 0"
type=
"primary"
@
click=
"fileInput?.click()"
>
<input
type=
"file"
accept=
".xlsx"
ref=
"fileInput"
@
change=
"handleChange"
class=
"hidden"
/>
<el-icon
v-show=
"uploadProgress === 0"
><IEpUpload
/></el-icon>
导入
</el-button>
</
template
>
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