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
82b53b9b
authored
Jul 09, 2024
by
YunaiV
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【代码优化】AI:绘图 index.vue 代码梳理 30%(ImageList)
parent
80d87b8e
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
108 additions
and
117 deletions
+108
-117
src/api/ai/image/index.ts
+6
-11
src/utils/download.ts
+18
-19
src/views/ai/image/index/components/ImageCard.vue
+5
-10
src/views/ai/image/index/components/ImageList.vue
+79
-76
src/views/bpm/category/index.vue
+0
-1
No files found.
src/api/ai/image/index.ts
View file @
82b53b9b
...
...
@@ -14,16 +14,11 @@ export interface ImageVO {
errorMessage
:
string
// 错误信息
options
:
object
// 配置 Map<string, string>
taskId
:
number
// 任务编号
buttons
:
ImageM
j
ButtonsVO
[]
// mj 操作按钮
buttons
:
ImageM
idjourney
ButtonsVO
[]
// mj 操作按钮
createTime
:
string
// 创建时间
finishTime
:
string
// 完成时间
}
export
interface
ImagePageReqVO
{
pageNo
:
number
// 分页编号
pageSize
:
number
// 分页大小
}
export
interface
ImageDrawReqVO
{
platform
:
string
// 平台
prompt
:
string
// 提示词
...
...
@@ -43,22 +38,22 @@ export interface ImageMidjourneyImagineReqVO {
version
:
string
// 版本
}
export
interface
ImageM
j
ActionVO
{
export
interface
ImageM
idjourney
ActionVO
{
id
:
number
// 图片编号
customId
:
string
// MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
}
export
interface
ImageM
j
ButtonsVO
{
export
interface
ImageM
idjourney
ButtonsVO
{
customId
:
string
// MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
emoji
:
string
// 图标 emoji
label
:
string
// Make Variations 文本
style
:
number
// 样式: 2(Primary)、3(Green)
}
// AI
API 密钥
API
// AI
图片
API
export
const
ImageApi
=
{
// 获取【我的】绘图分页
getImagePageMy
:
async
(
params
:
ImagePageReqVO
)
=>
{
getImagePageMy
:
async
(
params
:
PageParam
)
=>
{
return
await
request
.
get
({
url
:
`/ai/image/my-page`
,
params
})
},
// 获取【我的】绘图记录
...
...
@@ -85,7 +80,7 @@ export const ImageApi = {
return
await
request
.
post
({
url
:
`/ai/image/midjourney/imagine`
,
data
})
},
// 【Midjourney】Action 操作(二次生成图片)
midjourneyAction
:
async
(
data
:
ImageM
j
ActionVO
)
=>
{
midjourneyAction
:
async
(
data
:
ImageM
idjourney
ActionVO
)
=>
{
return
await
request
.
post
({
url
:
`/ai/image/midjourney/action`
,
data
})
},
...
...
src/utils/download.ts
View file @
82b53b9b
...
...
@@ -32,26 +32,25 @@ const download = {
// 下载 Markdown 方法
markdown
:
(
data
:
Blob
,
fileName
:
string
)
=>
{
download0
(
data
,
fileName
,
'text/markdown'
)
},
// 下载图片(允许跨域)
image
:
(
url
:
string
)
=>
{
const
image
=
new
Image
()
image
.
setAttribute
(
'crossOrigin'
,
'anonymous'
)
image
.
src
=
url
image
.
onload
=
()
=>
{
const
canvas
=
document
.
createElement
(
'canvas'
)
canvas
.
width
=
image
.
width
canvas
.
height
=
image
.
height
const
ctx
=
canvas
.
getContext
(
'2d'
)
as
CanvasDrawImage
ctx
.
drawImage
(
image
,
0
,
0
,
image
.
width
,
image
.
height
)
const
url
=
canvas
.
toDataURL
(
'image/png'
)
const
a
=
document
.
createElement
(
'a'
)
a
.
href
=
url
a
.
download
=
'image.png'
a
.
click
()
}
}
}
export
default
download
/** 图片下载(通过浏览器图片下载) */
export
const
downloadImage
=
async
(
imageUrl
)
=>
{
const
image
=
new
Image
()
image
.
setAttribute
(
'crossOrigin'
,
'anonymous'
)
image
.
src
=
imageUrl
image
.
onload
=
()
=>
{
const
canvas
=
document
.
createElement
(
'canvas'
)
canvas
.
width
=
image
.
width
canvas
.
height
=
image
.
height
const
ctx
=
canvas
.
getContext
(
'2d'
)
as
CanvasDrawImage
ctx
.
drawImage
(
image
,
0
,
0
,
image
.
width
,
image
.
height
)
const
url
=
canvas
.
toDataURL
(
'image/png'
)
const
a
=
document
.
createElement
(
'a'
)
a
.
href
=
url
a
.
download
=
'image.png'
a
.
click
()
}
}
src/views/ai/image/index/components/ImageCard.vue
View file @
82b53b9b
...
...
@@ -30,12 +30,7 @@
:icon=
"RefreshRight"
@
click=
"handleBtnClick('regeneration', imageDetail)"
/>
<el-button
class=
"btn"
text
:icon=
"Delete"
@
click=
"handleBtnClick('delete', imageDetail)"
/>
<el-button
class=
"btn"
text
:icon=
"Delete"
@
click=
"handleBtnClick('delete', imageDetail)"
/>
<el-button
class=
"btn"
text
:icon=
"More"
@
click=
"handleBtnClick('more', imageDetail)"
/>
</div>
</div>
...
...
@@ -61,10 +56,10 @@
</el-card>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
Delete
,
Download
,
More
,
RefreshRight
}
from
'@element-plus/icons-vue'
import
{
ImageVO
,
ImageM
j
ButtonsVO
}
from
'@/api/ai/image'
import
{
Delete
,
Download
,
More
,
RefreshRight
}
from
'@element-plus/icons-vue'
import
{
ImageVO
,
ImageM
idjourney
ButtonsVO
}
from
'@/api/ai/image'
import
{
PropType
}
from
'vue'
import
{
ElLoading
,
LoadingOptionsResolved
}
from
'element-plus'
import
{
ElLoading
,
LoadingOptionsResolved
}
from
'element-plus'
import
{
AiImageStatusEnum
}
from
'@/views/ai/utils/constants'
const
cardImageRef
=
ref
<
any
>
()
// 卡片 image ref
...
...
@@ -98,7 +93,7 @@ const handleLoading = async (status: number) => {
}
/** mj 按钮 click */
const
handleMjBtnClick
=
async
(
button
:
ImageM
j
ButtonsVO
)
=>
{
const
handleMjBtnClick
=
async
(
button
:
ImageM
idjourney
ButtonsVO
)
=>
{
// 确认窗体
await
message
.
confirm
(
`确认操作 "
${
button
.
label
}
${
button
.
emoji
}
" ?`
)
emits
(
'onMjBtnClick'
,
button
,
props
.
imageDetail
)
...
...
src/views/ai/image/index/components/ImageList.vue
View file @
82b53b9b
...
...
@@ -2,22 +2,21 @@
<el-card
class=
"dr-task"
body-class=
"task-card"
shadow=
"never"
>
<template
#
header
>
绘画任务
</
template
>
<!-- 图片列表 -->
<div
class=
"task-image-list"
ref=
"image
Task
Ref"
>
<div
class=
"task-image-list"
ref=
"image
List
Ref"
>
<ImageCard
v-for=
"image in imageList"
:key=
"image.id"
:image-detail=
"image"
@
on-btn-click=
"handleImageB
t
nClick"
@
on-mj-btn-click=
"handleImageM
jBt
nClick"
@
on-btn-click=
"handleImageB
utto
nClick"
@
on-mj-btn-click=
"handleImageM
idjourneyButto
nClick"
/>
</div>
<div
class=
"task-image-pagination"
>
<el-pagination
background
layout=
"prev, pager, next"
:default-page-size=
"pageSize"
<Pagination
:total=
"pageTotal"
@
change=
"handlePageChange"
v-model:page=
"queryParams.pageNo"
v-model:limit=
"queryParams.pageSize"
@
pagination=
"getImageList"
/>
</div>
</el-card>
...
...
@@ -26,62 +25,63 @@
<ImageDetail
:show=
"isShowImageDetail"
:id=
"showImageDetailId"
@
handle-drawer-close=
"handleD
rawer
Close"
@
handle-drawer-close=
"handleD
etail
Close"
/>
</template>
<
script
setup
lang=
"ts"
>
import
{
ImageApi
,
ImageVO
,
ImageMjActionVO
,
ImageMjButtonsVO
}
from
'@/api/ai/image'
import
{
ImageApi
,
ImageVO
,
ImageMidjourneyActionVO
,
ImageMidjourneyButtonsVO
}
from
'@/api/ai/image'
import
ImageDetail
from
'./ImageDetail.vue'
import
ImageCard
from
'./ImageCard.vue'
import
{
ElLoading
,
LoadingOptionsResolved
}
from
'element-plus'
import
{
AiImageStatusEnum
}
from
'@/views/ai/utils/constants'
import
{
downloadImage
}
from
'@/utils/download'
import
download
from
'@/utils/download'
const
message
=
useMessage
()
// 消息弹窗
// 图片分页相关的参数
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
})
const
pageTotal
=
ref
<
number
>
(
0
)
// page size
const
imageList
=
ref
<
ImageVO
[]
>
([])
// image 列表
const
imageListLoadingInstance
=
ref
<
any
>
()
// image 列表是否正在加载中
const
imageListRef
=
ref
<
any
>
()
// ref
// 图片轮询相关的参数(正在生成中的)
const
inProgressImageMap
=
ref
<
{}
>
({})
// 监听的 image 映射,一般是生成中(需要轮询),key 为 image 编号,value 为 image
const
imageListInterval
=
ref
<
any
>
()
// image 列表定时器,刷新列表
const
isShowImageDetail
=
ref
<
boolean
>
(
false
)
// 是否显示 task 详情
const
showImageDetailId
=
ref
<
number
>
(
0
)
// 是否显示 task 详情
const
imageTaskRef
=
ref
<
any
>
()
// ref
const
imageTaskLoadingInstance
=
ref
<
any
>
()
// loading
const
imageTaskLoading
=
ref
<
boolean
>
(
false
)
// loading
const
pageNo
=
ref
<
number
>
(
1
)
// page no
const
pageSize
=
ref
<
number
>
(
10
)
// page size
const
pageTotal
=
ref
<
number
>
(
0
)
// page size
const
inProgressTimer
=
ref
<
any
>
()
// 生成中的 image 定时器,轮询生成进展
// 图片详情相关的参数
const
isShowImageDetail
=
ref
<
boolean
>
(
false
)
// 图片详情是否展示
const
showImageDetailId
=
ref
<
number
>
(
0
)
// 图片详情的图片编号
/**
抽屉 - close
*/
const
handleD
rawerClose
=
async
()
=>
{
isShowImageDetail
.
value
=
fals
e
/**
查看图片的详情
*/
const
handleD
etailOpen
=
async
()
=>
{
isShowImageDetail
.
value
=
tru
e
}
/**
任务 - detail
*/
const
handleD
rawerOpen
=
async
()
=>
{
isShowImageDetail
.
value
=
tru
e
/**
关闭图片的详情
*/
const
handleD
etailClose
=
async
()
=>
{
isShowImageDetail
.
value
=
fals
e
}
/**
* 获取 - image 列表
*/
const
getImageList
=
async
(
apply
:
boolean
=
false
)
=>
{
imageTaskLoading
.
value
=
true
/** 获得 image 图片列表 */
const
getImageList
=
async
()
=>
{
try
{
imageTaskLoadingInstance
.
value
=
ElLoading
.
service
({
target
:
imageTaskRef
.
value
,
// 1. 加载图片列表
imageListLoadingInstance
.
value
=
ElLoading
.
service
({
target
:
imageListRef
.
value
,
text
:
'加载中...'
}
as
LoadingOptionsResolved
)
const
{
list
,
total
}
=
await
ImageApi
.
getImagePageMy
({
pageNo
:
pageNo
.
value
,
pageSize
:
pageSize
.
value
})
if
(
apply
)
{
imageList
.
value
=
[...
imageList
.
value
,
...
list
]
}
else
{
imageList
.
value
=
list
}
const
{
list
,
total
}
=
await
ImageApi
.
getImagePageMy
(
queryParams
)
imageList
.
value
=
list
pageTotal
.
value
=
total
// 需要 watch 的数据
// 2. 计算需要轮询的图片
const
newWatImages
=
{}
imageList
.
value
.
forEach
((
item
)
=>
{
if
(
item
.
status
===
AiImageStatusEnum
.
IN_PROGRESS
)
{
...
...
@@ -90,9 +90,10 @@ const getImageList = async (apply: boolean = false) => {
})
inProgressImageMap
.
value
=
newWatImages
}
finally
{
if
(
imageTaskLoadingInstance
.
value
)
{
imageTaskLoadingInstance
.
value
.
close
()
imageTaskLoadingInstance
.
value
=
null
// 关闭正在“加载中”的 Loading
if
(
imageListLoadingInstance
.
value
)
{
imageListLoadingInstance
.
value
.
close
()
imageListLoadingInstance
.
value
=
null
}
}
}
...
...
@@ -119,50 +120,52 @@ const refreshWatchImages = async () => {
inProgressImageMap
.
value
=
newWatchImages
}
/** 图片 - btn click */
const
handleImageBtnClick
=
async
(
type
:
string
,
imageDetail
:
ImageVO
)
=>
{
// 获取 image detail id
showImageDetailId
.
value
=
imageDetail
.
id
// 处理不用 btn
/** 图片的点击事件 */
const
handleImageButtonClick
=
async
(
type
:
string
,
imageDetail
:
ImageVO
)
=>
{
// 详情
if
(
type
===
'more'
)
{
await
handleDrawerOpen
()
}
else
if
(
type
===
'delete'
)
{
showImageDetailId
.
value
=
imageDetail
.
id
await
handleDetailOpen
()
return
}
// 删除
if
(
type
===
'delete'
)
{
await
message
.
confirm
(
`是否删除照片?`
)
await
ImageApi
.
deleteImageMy
(
imageDetail
.
id
)
await
getImageList
()
message
.
success
(
'删除成功!'
)
}
else
if
(
type
===
'download'
)
{
await
downloadImage
(
imageDetail
.
picUrl
)
}
else
if
(
type
===
'regeneration'
)
{
// Midjourney 平台
console
.
log
(
'regeneration'
,
imageDetail
.
id
)
return
}
// 下载
if
(
type
===
'download'
)
{
await
download
.
image
(
imageDetail
.
picUrl
)
return
}
// 重新生成
if
(
type
===
'regeneration'
)
{
await
emits
(
'onRegeneration'
,
imageDetail
)
return
}
}
/** 图片 - mj btn click */
const
handleImageMjBtnClick
=
async
(
button
:
ImageMjButtonsVO
,
imageDetail
:
ImageVO
)
=>
{
// 1、构建 params 参数
/** 处理 Midjourney 按钮点击事件 */
const
handleImageMidjourneyButtonClick
=
async
(
button
:
ImageMidjourneyButtonsVO
,
imageDetail
:
ImageVO
)
=>
{
// 1. 构建 params 参数
const
data
=
{
id
:
imageDetail
.
id
,
customId
:
button
.
customId
}
as
ImageM
j
ActionVO
// 2
、
发送 action
}
as
ImageM
idjourney
ActionVO
// 2
.
发送 action
await
ImageApi
.
midjourneyAction
(
data
)
// 3
、
刷新列表
// 3
.
刷新列表
await
getImageList
()
}
// page change
const
handlePageChange
=
async
(
page
)
=>
{
pageNo
.
value
=
page
await
getImageList
(
false
)
}
/** 暴露组件方法 */
defineExpose
({
getImageList
})
defineExpose
({
getImageList
})
// 暴露组件方法
// emits
const
emits
=
defineEmits
([
'onRegeneration'
])
/** 组件挂在的时候 */
...
...
@@ -170,15 +173,15 @@ onMounted(async () => {
// 获取 image 列表
await
getImageList
()
// 自动刷新 image 列表
i
mageListInterval
.
value
=
setInterval
(
async
()
=>
{
i
nProgressTimer
.
value
=
setInterval
(
async
()
=>
{
await
refreshWatchImages
()
},
1000
*
3
)
})
/** 组件取消挂在的时候 */
onUnmounted
(
async
()
=>
{
if
(
i
mageListInterval
.
value
)
{
clearInterval
(
i
mageListInterval
.
value
)
if
(
i
nProgressTimer
.
value
)
{
clearInterval
(
i
nProgressTimer
.
value
)
}
})
</
script
>
...
...
src/views/bpm/category/index.vue
View file @
82b53b9b
...
...
@@ -126,7 +126,6 @@
<
script
setup
lang=
"ts"
>
import
{
getIntDictOptions
,
DICT_TYPE
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
download
from
'@/utils/download'
import
{
CategoryApi
,
CategoryVO
}
from
'@/api/bpm/category'
import
CategoryForm
from
'./CategoryForm.vue'
...
...
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