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
f3883e76
authored
Aug 10, 2026
by
renyizhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
商品导入
parent
04340bf7
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
225 additions
and
3 deletions
+225
-3
src/api/compute/resourcespu/index.ts
+25
-0
src/views/compute/resourcespu/ResourceSpuForm.vue
+0
-1
src/views/compute/resourcespu/index.vue
+200
-2
No files found.
src/api/compute/resourcespu/index.ts
View file @
f3883e76
...
...
@@ -71,3 +71,28 @@ export const ResourceSpuApi = {
return
await
request
.
download
({
url
:
`/compute/resource-spu/export-excel`
,
params
})
}
}
// ========== 阶段 8 - 批量导入(弹窗两步式:模板下载 + 上传导入) ==========
/** 算力资源 SPU 导入 - 失败行 */
export
interface
ResourceSpuImportRowVO
{
rowIndex
?:
number
name
?:
string
message
?:
string
}
/** 算力资源 SPU 导入 - 响应 */
export
interface
ResourceSpuImportRespVO
{
createNames
?:
string
[]
failureRows
?:
ResourceSpuImportRowVO
[]
}
// 下载算力资源 SPU 导入模板
export
const
getResourceSpuImportTemplate
=
()
=>
{
return
request
.
download
({
url
:
'/compute/resource-spu/get-import-template'
})
}
// 上传 Excel 导入算力资源 SPU
export
const
importResourceSpu
=
async
(
formData
:
FormData
)
=>
{
return
await
request
.
upload
({
url
:
`/compute/resource-spu/import`
,
data
:
formData
})
}
src/views/compute/resourcespu/ResourceSpuForm.vue
View file @
f3883e76
...
...
@@ -265,7 +265,6 @@ const formRules = reactive({
initUsername
:
[{
required
:
true
,
message
:
'初始用户名不能为空'
,
trigger
:
'blur'
}],
initPassword
:
[{
required
:
true
,
message
:
'初始密码不能为空'
,
trigger
:
'blur'
}],
categoryId
:
[{
required
:
true
,
message
:
'算力资源分类编号不能为空'
,
trigger
:
'blur'
}],
picUrl
:
[{
required
:
true
,
message
:
'商品封面图不能为空'
,
trigger
:
'blur'
}],
sales
:
[{
required
:
true
,
message
:
'商品销量不能为空'
,
trigger
:
'blur'
}],
status
:
[{
required
:
true
,
message
:
'状态(0 下架,1 上架,2 回收)不能为空'
,
trigger
:
'blur'
}]
})
...
...
src/views/compute/resourcespu/index.vue
View file @
f3883e76
...
...
@@ -124,6 +124,14 @@
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
<el-button
type=
"success"
plain
@
click=
"openImportDialog"
v-hasPermi=
"['compute:resource-spu:import']"
>
<Icon
icon=
"ep:upload"
class=
"mr-5px"
/>
批量导入
</el-button>
<!--
<el-button
type=
"success"
plain
...
...
@@ -244,16 +252,117 @@
@
pagination=
"getList"
/>
</ContentWrap>
<!-- 批量导入 - 两步式弹窗(阶段 8) -->
<Dialog
v-model=
"importDialogVisible"
title=
"批量导入算力资源 SPU"
width=
"720"
:close-on-click-modal=
"false"
>
<el-steps
:active=
"importStep"
align-center
finish-status=
"success"
class=
"mb-20px"
>
<el-step
title=
"上传文件"
description=
"下载模板并填写商品信息"
/>
<el-step
title=
"导入结果"
description=
"查看成功/失败明细"
/>
</el-steps>
<!-- Step 1:下载模板 + 上传文件 -->
<div
v-show=
"importStep === 0"
>
<el-alert
title=
"操作说明"
type=
"info"
:closable=
"false"
show-icon
class=
"mb-12px"
>
<
template
#
default
>
<div>
1. 点击「下载 Excel 模板」,按模板列填写商品信息;规格列名必须与字典「算力资源配置类别」一致(如 CPU / GPU / RAM)
</div>
<div>
2. 商品名称、分类、封面图为必填;至少需要 1 个规格;同名商品会报错,不支持 update
</div>
<div>
3. 分类填写分类 ID(数字),可在分类管理中查看
</div>
</
template
>
</el-alert>
<el-button
:loading=
"templateLoading"
@
click=
"downloadImportTemplate"
>
<Icon
icon=
"ep:download"
class=
"mr-5px"
/>
下载 Excel 模板
</el-button>
<el-upload
ref=
"importUploadRef"
v-model:file-list=
"importFileList"
:auto-upload=
"false"
:limit=
"1"
:on-exceed=
"handleImportExceed"
accept=
".xlsx, .xls"
action=
"none"
drag
class=
"mt-12px"
>
<Icon
icon=
"ep:upload"
/>
<div
class=
"el-upload__text"
>
将文件拖到此处,或
<em>
点击上传
</em></div>
<
template
#
tip
>
<div
class=
"el-upload__tip text-center"
>
<span>
仅允许导入 xls、xlsx 格式文件。
</span>
</div>
</
template
>
</el-upload>
</div>
<!-- Step 2:结果展示 -->
<div
v-show=
"importStep === 1"
>
<el-alert
:title=
"`成功创建 ${importResult.createNames?.length || 0} 个,失败 ${importResult.failureRows?.length || 0} 个`"
:type=
"(importResult.failureRows?.length || 0) > 0 ? 'warning' : 'success'"
:closable=
"false"
show-icon
class=
"mb-12px"
/>
<el-table
v-if=
"(importResult.failureRows?.length || 0) > 0"
:data=
"importResult.failureRows"
border
max-height=
"320"
class=
"mb-12px"
>
<el-table-column
label=
"Excel 行号"
prop=
"rowIndex"
width=
"100"
align=
"center"
/>
<el-table-column
label=
"商品名称"
prop=
"name"
min-width=
"180"
/>
<el-table-column
label=
"失败原因"
prop=
"message"
min-width=
"280"
/>
</el-table>
<div
v-if=
"(importResult.failureRows?.length || 0) > 0"
>
<el-link
type=
"primary"
:underline=
"false"
@
click=
"downloadFailureExcel"
>
<Icon
icon=
"ep:download"
class=
"mr-5px"
/>
下载失败行 Excel
</el-link>
</div>
</div>
<
template
#
footer
>
<el-button
v-if=
"importStep === 0"
@
click=
"importDialogVisible = false"
>
取 消
</el-button>
<el-button
v-if=
"importStep === 0"
type=
"primary"
:loading=
"importLoading"
:disabled=
"importFileList.length === 0"
@
click=
"submitImport"
>
开始导入
</el-button>
<el-button
v-if=
"importStep === 1"
@
click=
"resetImportDialog"
>
重新导入
</el-button>
<el-button
v-if=
"importStep === 1"
type=
"primary"
@
click=
"importDialogVisible = false"
>
关 闭
</el-button>
</
template
>
</Dialog>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
,
reactive
,
onMounted
,
onActivated
}
from
'vue'
import
{
ref
,
reactive
,
onMounted
,
onActivated
,
nextTick
}
from
'vue'
import
{
isEmpty
}
from
'@/utils/is'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
download
from
'@/utils/download'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
ResourceSpuApi
,
ResourceSpu
}
from
'@/api/compute/resourcespu'
import
{
ResourceSpuApi
,
ResourceSpu
,
getResourceSpuImportTemplate
,
importResourceSpu
,
ResourceSpuImportRespVO
}
from
'@/api/compute/resourcespu'
import
{
DICT_TYPE
,
getIntDictOptions
,
getStrDictOptions
}
from
'@/utils/dict'
import
type
{
UploadUserFile
,
UploadRawFile
}
from
'element-plus'
const
{
push
}
=
useRouter
()
...
...
@@ -372,6 +481,95 @@ const handleExport = async () => {
}
}
// ========== 阶段 8 - 批量导入(弹窗两步式) ==========
const
importDialogVisible
=
ref
(
false
)
// 导入弹窗是否显示
const
importStep
=
ref
(
0
)
// 0=上传,1=结果
const
importFileList
=
ref
<
UploadUserFile
[]
>
([])
// 上传文件列表
const
importLoading
=
ref
(
false
)
// 导入中
const
templateLoading
=
ref
(
false
)
// 下载模板中
const
importUploadRef
=
ref
()
// upload 组件 ref
const
importResult
=
ref
<
ResourceSpuImportRespVO
>
({
createNames
:
[],
failureRows
:
[]
})
/** 打开导入弹窗 */
const
openImportDialog
=
()
=>
{
resetImportDialog
()
importDialogVisible
.
value
=
true
}
/** 重置导入弹窗状态 */
const
resetImportDialog
=
async
()
=>
{
importStep
.
value
=
0
importFileList
.
value
=
[]
importResult
.
value
=
{
createNames
:
[],
failureRows
:
[]
}
await
nextTick
()
importUploadRef
.
value
?.
clearFiles
()
}
/** 下载导入模板 */
const
downloadImportTemplate
=
async
()
=>
{
templateLoading
.
value
=
true
try
{
const
data
=
await
getResourceSpuImportTemplate
()
download
.
excel
(
data
,
'算力资源SPU导入模板.xls'
)
}
catch
{
}
finally
{
templateLoading
.
value
=
false
}
}
/** 文件超出限制提示 */
const
handleImportExceed
=
(
files
:
UploadUserFile
[])
=>
{
message
.
error
(
'最多只能上传一个文件!'
)
}
/** 提交导入 */
const
submitImport
=
async
()
=>
{
if
(
importFileList
.
value
.
length
===
0
)
{
message
.
error
(
'请上传文件'
)
return
}
importLoading
.
value
=
true
try
{
const
formData
=
new
FormData
()
const
raw
=
importFileList
.
value
[
0
].
raw
as
UploadRawFile
formData
.
append
(
'file'
,
raw
)
const
res
:
any
=
await
importResourceSpu
(
formData
)
if
(
res
&&
res
.
data
)
{
importResult
.
value
=
res
.
data
}
else
{
importResult
.
value
=
{
createNames
:
[],
failureRows
:
[]
}
}
importStep
.
value
=
1
// 有成功就刷新列表
if
((
importResult
.
value
.
createNames
?.
length
||
0
)
>
0
)
{
await
getList
()
}
}
catch
(
e
:
any
)
{
message
.
error
(
'导入失败:'
+
(
e
?.
message
||
'请稍后重试'
))
}
finally
{
importLoading
.
value
=
false
}
}
/** 下载失败行 Excel(占位实现:纯前端导出 .xls 文本,后续可改为后端生成) */
const
downloadFailureExcel
=
()
=>
{
const
rows
=
importResult
.
value
.
failureRows
||
[]
const
head
=
[
'行号'
,
'商品名称'
,
'失败原因'
]
const
lines
:
string
[]
=
[]
lines
.
push
(
head
.
join
(
'\t'
))
rows
.
forEach
((
r
)
=>
{
lines
.
push
([
r
.
rowIndex
,
r
.
name
||
''
,
r
.
message
||
''
].
join
(
'\t'
))
})
const
content
=
lines
.
join
(
'\n'
)
// 用 Excel 可识别的 BOM 头
const
blob
=
new
Blob
([
'\ufeff'
+
content
],
{
type
:
'application/vnd.ms-excel;charset=utf-8'
})
download
.
excel
(
blob
,
'算力资源SPU导入失败行.xls'
)
}
/** 初始化 **/
onMounted
(
async
()
=>
{
try
{
...
...
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