Skip to content

Commit 82b53b9

Browse files
committed
【代码优化】AI:绘图 index.vue 代码梳理 30%(ImageList)
1 parent 80d87b8 commit 82b53b9

File tree

5 files changed

+108
-117
lines changed

5 files changed

+108
-117
lines changed

src/api/ai/image/index.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,11 @@ export interface ImageVO {
1414
errorMessage: string // 错误信息
1515
options: object // 配置 Map<string, string>
1616
taskId: number // 任务编号
17-
buttons: ImageMjButtonsVO[] // mj 操作按钮
17+
buttons: ImageMidjourneyButtonsVO[] // mj 操作按钮
1818
createTime: string // 创建时间
1919
finishTime: string // 完成时间
2020
}
2121

22-
export interface ImagePageReqVO {
23-
pageNo: number // 分页编号
24-
pageSize: number // 分页大小
25-
}
26-
2722
export interface ImageDrawReqVO {
2823
platform: string // 平台
2924
prompt: string // 提示词
@@ -43,22 +38,22 @@ export interface ImageMidjourneyImagineReqVO {
4338
version: string // 版本
4439
}
4540

46-
export interface ImageMjActionVO {
41+
export interface ImageMidjourneyActionVO {
4742
id: number // 图片编号
4843
customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
4944
}
5045

51-
export interface ImageMjButtonsVO {
46+
export interface ImageMidjourneyButtonsVO {
5247
customId: string // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
5348
emoji: string // 图标 emoji
5449
label: string // Make Variations 文本
5550
style: number // 样式: 2(Primary)、3(Green)
5651
}
5752

58-
// AI API 密钥 API
53+
// AI 图片 API
5954
export const ImageApi = {
6055
// 获取【我的】绘图分页
61-
getImagePageMy: async (params: ImagePageReqVO) => {
56+
getImagePageMy: async (params: PageParam) => {
6257
return await request.get({ url: `/ai/image/my-page`, params })
6358
},
6459
// 获取【我的】绘图记录
@@ -85,7 +80,7 @@ export const ImageApi = {
8580
return await request.post({ url: `/ai/image/midjourney/imagine`, data })
8681
},
8782
// 【Midjourney】Action 操作(二次生成图片)
88-
midjourneyAction: async (data: ImageMjActionVO) => {
83+
midjourneyAction: async (data: ImageMidjourneyActionVO) => {
8984
return await request.post({ url: `/ai/image/midjourney/action`, data })
9085
},
9186

src/utils/download.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,25 @@ const download = {
3232
// 下载 Markdown 方法
3333
markdown: (data: Blob, fileName: string) => {
3434
download0(data, fileName, 'text/markdown')
35+
},
36+
// 下载图片(允许跨域)
37+
image: (url: string) => {
38+
const image = new Image()
39+
image.setAttribute('crossOrigin', 'anonymous')
40+
image.src = url
41+
image.onload = () => {
42+
const canvas = document.createElement('canvas')
43+
canvas.width = image.width
44+
canvas.height = image.height
45+
const ctx = canvas.getContext('2d') as CanvasDrawImage
46+
ctx.drawImage(image, 0, 0, image.width, image.height)
47+
const url = canvas.toDataURL('image/png')
48+
const a = document.createElement('a')
49+
a.href = url
50+
a.download = 'image.png'
51+
a.click()
52+
}
3553
}
3654
}
3755

3856
export default download
39-
40-
/** 图片下载(通过浏览器图片下载) */
41-
export const downloadImage = async (imageUrl) => {
42-
const image = new Image()
43-
image.setAttribute('crossOrigin', 'anonymous')
44-
image.src = imageUrl
45-
image.onload = () => {
46-
const canvas = document.createElement('canvas')
47-
canvas.width = image.width
48-
canvas.height = image.height
49-
const ctx = canvas.getContext('2d') as CanvasDrawImage
50-
ctx.drawImage(image, 0, 0, image.width, image.height)
51-
const url = canvas.toDataURL('image/png')
52-
const a = document.createElement('a')
53-
a.href = url
54-
a.download = 'image.png'
55-
a.click()
56-
}
57-
}

src/views/ai/image/index/components/ImageCard.vue

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@
3030
:icon="RefreshRight"
3131
@click="handleBtnClick('regeneration', imageDetail)"
3232
/>
33-
<el-button
34-
class="btn"
35-
text
36-
:icon="Delete"
37-
@click="handleBtnClick('delete', imageDetail)"
38-
/>
33+
<el-button class="btn" text :icon="Delete" @click="handleBtnClick('delete', imageDetail)" />
3934
<el-button class="btn" text :icon="More" @click="handleBtnClick('more', imageDetail)" />
4035
</div>
4136
</div>
@@ -61,10 +56,10 @@
6156
</el-card>
6257
</template>
6358
<script setup lang="ts">
64-
import {Delete, Download, More, RefreshRight} from '@element-plus/icons-vue'
65-
import { ImageVO, ImageMjButtonsVO } from '@/api/ai/image'
59+
import { Delete, Download, More, RefreshRight } from '@element-plus/icons-vue'
60+
import { ImageVO, ImageMidjourneyButtonsVO } from '@/api/ai/image'
6661
import { PropType } from 'vue'
67-
import {ElLoading, LoadingOptionsResolved} from 'element-plus'
62+
import { ElLoading, LoadingOptionsResolved } from 'element-plus'
6863
import { AiImageStatusEnum } from '@/views/ai/utils/constants'
6964
7065
const cardImageRef = ref<any>() // 卡片 image ref
@@ -98,7 +93,7 @@ const handleLoading = async (status: number) => {
9893
}
9994
10095
/** mj 按钮 click */
101-
const handleMjBtnClick = async (button: ImageMjButtonsVO) => {
96+
const handleMjBtnClick = async (button: ImageMidjourneyButtonsVO) => {
10297
// 确认窗体
10398
await message.confirm(`确认操作 "${button.label} ${button.emoji}" ?`)
10499
emits('onMjBtnClick', button, props.imageDetail)

src/views/ai/image/index/components/ImageList.vue

Lines changed: 79 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,21 @@
22
<el-card class="dr-task" body-class="task-card" shadow="never">
33
<template #header>绘画任务</template>
44
<!-- 图片列表 -->
5-
<div class="task-image-list" ref="imageTaskRef">
5+
<div class="task-image-list" ref="imageListRef">
66
<ImageCard
77
v-for="image in imageList"
88
:key="image.id"
99
:image-detail="image"
10-
@on-btn-click="handleImageBtnClick"
11-
@on-mj-btn-click="handleImageMjBtnClick"
10+
@on-btn-click="handleImageButtonClick"
11+
@on-mj-btn-click="handleImageMidjourneyButtonClick"
1212
/>
1313
</div>
1414
<div class="task-image-pagination">
15-
<el-pagination
16-
background
17-
layout="prev, pager, next"
18-
:default-page-size="pageSize"
15+
<Pagination
1916
:total="pageTotal"
20-
@change="handlePageChange"
17+
v-model:page="queryParams.pageNo"
18+
v-model:limit="queryParams.pageSize"
19+
@pagination="getImageList"
2120
/>
2221
</div>
2322
</el-card>
@@ -26,62 +25,63 @@
2625
<ImageDetail
2726
:show="isShowImageDetail"
2827
:id="showImageDetailId"
29-
@handle-drawer-close="handleDrawerClose"
28+
@handle-drawer-close="handleDetailClose"
3029
/>
3130
</template>
3231
<script setup lang="ts">
33-
import { ImageApi, ImageVO, ImageMjActionVO, ImageMjButtonsVO } from '@/api/ai/image'
32+
import {
33+
ImageApi,
34+
ImageVO,
35+
ImageMidjourneyActionVO,
36+
ImageMidjourneyButtonsVO
37+
} from '@/api/ai/image'
3438
import ImageDetail from './ImageDetail.vue'
3539
import ImageCard from './ImageCard.vue'
3640
import { ElLoading, LoadingOptionsResolved } from 'element-plus'
3741
import { AiImageStatusEnum } from '@/views/ai/utils/constants'
38-
import { downloadImage } from '@/utils/download'
42+
import download from '@/utils/download'
3943
4044
const message = useMessage() // 消息弹窗
4145
46+
// 图片分页相关的参数
47+
const queryParams = reactive({
48+
pageNo: 1,
49+
pageSize: 10
50+
})
51+
const pageTotal = ref<number>(0) // page size
4252
const imageList = ref<ImageVO[]>([]) // image 列表
53+
const imageListLoadingInstance = ref<any>() // image 列表是否正在加载中
54+
const imageListRef = ref<any>() // ref
55+
// 图片轮询相关的参数(正在生成中的)
4356
const inProgressImageMap = ref<{}>({}) // 监听的 image 映射,一般是生成中(需要轮询),key 为 image 编号,value 为 image
44-
const imageListInterval = ref<any>() // image 列表定时器,刷新列表
45-
const isShowImageDetail = ref<boolean>(false) // 是否显示 task 详情
46-
const showImageDetailId = ref<number>(0) // 是否显示 task 详情
47-
const imageTaskRef = ref<any>() // ref
48-
const imageTaskLoadingInstance = ref<any>() // loading
49-
const imageTaskLoading = ref<boolean>(false) // loading
50-
const pageNo = ref<number>(1) // page no
51-
const pageSize = ref<number>(10) // page size
52-
const pageTotal = ref<number>(0) // page size
57+
const inProgressTimer = ref<any>() // 生成中的 image 定时器,轮询生成进展
58+
// 图片详情相关的参数
59+
const isShowImageDetail = ref<boolean>(false) // 图片详情是否展示
60+
const showImageDetailId = ref<number>(0) // 图片详情的图片编号
5361
54-
/** 抽屉 - close */
55-
const handleDrawerClose = async () => {
56-
isShowImageDetail.value = false
62+
/** 查看图片的详情 */
63+
const handleDetailOpen = async () => {
64+
isShowImageDetail.value = true
5765
}
5866
59-
/** 任务 - detail */
60-
const handleDrawerOpen = async () => {
61-
isShowImageDetail.value = true
67+
/** 关闭图片的详情 */
68+
const handleDetailClose = async () => {
69+
isShowImageDetail.value = false
6270
}
6371
64-
/**
65-
* 获取 - image 列表
66-
*/
67-
const getImageList = async (apply: boolean = false) => {
68-
imageTaskLoading.value = true
72+
/** 获得 image 图片列表 */
73+
const getImageList = async () => {
6974
try {
70-
imageTaskLoadingInstance.value = ElLoading.service({
71-
target: imageTaskRef.value,
75+
// 1. 加载图片列表
76+
imageListLoadingInstance.value = ElLoading.service({
77+
target: imageListRef.value,
7278
text: '加载中...'
7379
} as LoadingOptionsResolved)
74-
const { list, total } = await ImageApi.getImagePageMy({
75-
pageNo: pageNo.value,
76-
pageSize: pageSize.value
77-
})
78-
if (apply) {
79-
imageList.value = [...imageList.value, ...list]
80-
} else {
81-
imageList.value = list
82-
}
80+
const { list, total } = await ImageApi.getImagePageMy(queryParams)
81+
imageList.value = list
8382
pageTotal.value = total
84-
// 需要 watch 的数据
83+
84+
// 2. 计算需要轮询的图片
8585
const newWatImages = {}
8686
imageList.value.forEach((item) => {
8787
if (item.status === AiImageStatusEnum.IN_PROGRESS) {
@@ -90,9 +90,10 @@ const getImageList = async (apply: boolean = false) => {
9090
})
9191
inProgressImageMap.value = newWatImages
9292
} finally {
93-
if (imageTaskLoadingInstance.value) {
94-
imageTaskLoadingInstance.value.close()
95-
imageTaskLoadingInstance.value = null
93+
// 关闭正在“加载中”的 Loading
94+
if (imageListLoadingInstance.value) {
95+
imageListLoadingInstance.value.close()
96+
imageListLoadingInstance.value = null
9697
}
9798
}
9899
}
@@ -119,66 +120,68 @@ const refreshWatchImages = async () => {
119120
inProgressImageMap.value = newWatchImages
120121
}
121122
122-
/** 图片 - btn click */
123-
const handleImageBtnClick = async (type: string, imageDetail: ImageVO) => {
124-
// 获取 image detail id
125-
showImageDetailId.value = imageDetail.id
126-
// 处理不用 btn
123+
/** 图片的点击事件 */
124+
const handleImageButtonClick = async (type: string, imageDetail: ImageVO) => {
125+
// 详情
127126
if (type === 'more') {
128-
await handleDrawerOpen()
129-
} else if (type === 'delete') {
127+
showImageDetailId.value = imageDetail.id
128+
await handleDetailOpen()
129+
return
130+
}
131+
// 删除
132+
if (type === 'delete') {
130133
await message.confirm(`是否删除照片?`)
131134
await ImageApi.deleteImageMy(imageDetail.id)
132135
await getImageList()
133136
message.success('删除成功!')
134-
} else if (type === 'download') {
135-
await downloadImage(imageDetail.picUrl)
136-
} else if (type === 'regeneration') {
137-
// Midjourney 平台
138-
console.log('regeneration', imageDetail.id)
137+
return
138+
}
139+
// 下载
140+
if (type === 'download') {
141+
await download.image(imageDetail.picUrl)
142+
return
143+
}
144+
// 重新生成
145+
if (type === 'regeneration') {
139146
await emits('onRegeneration', imageDetail)
147+
return
140148
}
141149
}
142150
143-
/** 图片 - mj btn click */
144-
const handleImageMjBtnClick = async (button: ImageMjButtonsVO, imageDetail: ImageVO) => {
145-
// 1、构建 params 参数
151+
/** 处理 Midjourney 按钮点击事件 */
152+
const handleImageMidjourneyButtonClick = async (
153+
button: ImageMidjourneyButtonsVO,
154+
imageDetail: ImageVO
155+
) => {
156+
// 1. 构建 params 参数
146157
const data = {
147158
id: imageDetail.id,
148159
customId: button.customId
149-
} as ImageMjActionVO
150-
// 2发送 action
160+
} as ImageMidjourneyActionVO
161+
// 2. 发送 action
151162
await ImageApi.midjourneyAction(data)
152-
// 3刷新列表
163+
// 3. 刷新列表
153164
await getImageList()
154165
}
155166
156-
// page change
157-
const handlePageChange = async (page) => {
158-
pageNo.value = page
159-
await getImageList(false)
160-
}
161-
162-
/** 暴露组件方法 */
163-
defineExpose({ getImageList })
167+
defineExpose({ getImageList }) // 暴露组件方法
164168
165-
// emits
166169
const emits = defineEmits(['onRegeneration'])
167170
168171
/** 组件挂在的时候 */
169172
onMounted(async () => {
170173
// 获取 image 列表
171174
await getImageList()
172175
// 自动刷新 image 列表
173-
imageListInterval.value = setInterval(async () => {
176+
inProgressTimer.value = setInterval(async () => {
174177
await refreshWatchImages()
175178
}, 1000 * 3)
176179
})
177180
178181
/** 组件取消挂在的时候 */
179182
onUnmounted(async () => {
180-
if (imageListInterval.value) {
181-
clearInterval(imageListInterval.value)
183+
if (inProgressTimer.value) {
184+
clearInterval(inProgressTimer.value)
182185
}
183186
})
184187
</script>

src/views/bpm/category/index.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@
126126
<script setup lang="ts">
127127
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
128128
import { dateFormatter } from '@/utils/formatTime'
129-
import download from '@/utils/download'
130129
import { CategoryApi, CategoryVO } from '@/api/bpm/category'
131130
import CategoryForm from './CategoryForm.vue'
132131

0 commit comments

Comments
 (0)