Merge branch 'dev' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev
commit
10f6a2b158
|
@ -0,0 +1,85 @@
|
||||||
|
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||||
|
|
||||||
|
import { getAccessToken } from '@/utils/auth'
|
||||||
|
import { config } from '@/config/axios/config'
|
||||||
|
import { AiWriteTypeEnum } from '@/views/ai/utils/constants'
|
||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export interface WriteVO {
|
||||||
|
type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
|
||||||
|
prompt: string // 写作内容提示 1。撰写 2回复
|
||||||
|
originalContent: string // 原文
|
||||||
|
length: number // 长度
|
||||||
|
format: number // 格式
|
||||||
|
tone: number // 语气
|
||||||
|
language: number // 语言
|
||||||
|
userId?: number // 用户编号
|
||||||
|
platform?: string // 平台
|
||||||
|
model?: string // 模型
|
||||||
|
generatedContent?: string // 生成的内容
|
||||||
|
errorMessage: string // 错误信息
|
||||||
|
createTime?: Date // 创建时间
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AiWritePageReqVO extends PageParam {
|
||||||
|
userId?: number // 用户编号
|
||||||
|
type?: AiWriteTypeEnum // 写作类型
|
||||||
|
platform?: string // 平台
|
||||||
|
createTime?: [string, string] // 创建时间
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AiWriteRespVo {
|
||||||
|
id: number
|
||||||
|
userId: number
|
||||||
|
type: number
|
||||||
|
platform: string
|
||||||
|
model: string
|
||||||
|
prompt: string
|
||||||
|
generatedContent: string
|
||||||
|
originalContent: string
|
||||||
|
length: number
|
||||||
|
format: number
|
||||||
|
tone: number
|
||||||
|
language: number
|
||||||
|
errorMessage: string
|
||||||
|
createTime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WriteApi = {
|
||||||
|
writeStream: ({
|
||||||
|
data,
|
||||||
|
onClose,
|
||||||
|
onMessage,
|
||||||
|
onError,
|
||||||
|
ctrl
|
||||||
|
}: {
|
||||||
|
data: WriteVO
|
||||||
|
onMessage?: (res: any) => void
|
||||||
|
onError?: (...args: any[]) => void
|
||||||
|
onClose?: (...args: any[]) => void
|
||||||
|
ctrl: AbortController
|
||||||
|
}) => {
|
||||||
|
const token = getAccessToken()
|
||||||
|
return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
openWhenHidden: true,
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
onmessage: onMessage,
|
||||||
|
onerror: onError,
|
||||||
|
onclose: onClose,
|
||||||
|
signal: ctrl.signal
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取写作列表
|
||||||
|
getWritePage: (params: AiWritePageReqVO) => {
|
||||||
|
return request.get<PageResult<AiWriteRespVo[]>>({ url: `/ai/write/page`, params })
|
||||||
|
},
|
||||||
|
// 删除写作
|
||||||
|
deleteWrite(id: number) {
|
||||||
|
return request.delete({ url: `/ai/write/delete`, params: { id } })
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +0,0 @@
|
||||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|
||||||
import request from '@/config/axios'
|
|
||||||
|
|
||||||
import { getAccessToken } from '@/utils/auth'
|
|
||||||
import { config } from '@/config/axios/config'
|
|
||||||
import { AiWriteTypeEnum } from '@/views/ai/utils/constants'
|
|
||||||
|
|
||||||
export interface WriteVO {
|
|
||||||
type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
|
|
||||||
prompt: string // 写作内容提示 1。撰写 2回复
|
|
||||||
originalContent: string // 原文
|
|
||||||
length: number // 长度
|
|
||||||
format: number // 格式
|
|
||||||
tone: number // 语气
|
|
||||||
language: number // 语言
|
|
||||||
userId?: number // 用户编号
|
|
||||||
platform?: string // 平台
|
|
||||||
model?: string // 模型
|
|
||||||
generatedContent?: string // 生成的内容
|
|
||||||
errorMessage: string // 错误信息
|
|
||||||
createTime?: Date // 创建时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hhero:搞成 WriteApi,类似 ConversationApi 一样。这样更有类的概念,后续引入某个 Api,然后调用它的方法就可以了。
|
|
||||||
export const writeStream = ({
|
|
||||||
data,
|
|
||||||
onClose,
|
|
||||||
onMessage,
|
|
||||||
onError,
|
|
||||||
ctrl
|
|
||||||
}: {
|
|
||||||
data: WriteVO
|
|
||||||
onMessage?: (res: any) => void
|
|
||||||
onError?: (...args: any[]) => void
|
|
||||||
onClose?: (...args: any[]) => void
|
|
||||||
ctrl: AbortController
|
|
||||||
}) => {
|
|
||||||
const token = getAccessToken()
|
|
||||||
return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, {
|
|
||||||
method: 'post',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${token}`
|
|
||||||
},
|
|
||||||
openWhenHidden: true,
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
onmessage: onMessage,
|
|
||||||
onerror: onError,
|
|
||||||
onclose: onClose,
|
|
||||||
signal: ctrl.signal
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI 写作 API
|
|
||||||
export const WriteApi = {
|
|
||||||
// 查询AI 写作分页
|
|
||||||
getWritePage: async (params: any) => {
|
|
||||||
return await request.get({ url: `/ai/write/page`, params })
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除AI 写作
|
|
||||||
deleteWrite: async (id: number) => {
|
|
||||||
return await request.delete({ url: `/ai/write/delete?id=` + id })
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,7 +36,13 @@
|
||||||
<el-text tag="b">平台</el-text>
|
<el-text tag="b">平台</el-text>
|
||||||
</div>
|
</div>
|
||||||
<el-space wrap class="group-item-body">
|
<el-space wrap class="group-item-body">
|
||||||
<el-select v-model="otherPlatform" placeholder="Select" size="large" class="!w-350px" @change="handlerPlatformChange">
|
<el-select
|
||||||
|
v-model="otherPlatform"
|
||||||
|
placeholder="Select"
|
||||||
|
size="large"
|
||||||
|
class="!w-350px"
|
||||||
|
@change="handlerPlatformChange"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in OtherPlatformEnum"
|
v-for="item in OtherPlatformEnum"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
|
@ -52,12 +58,7 @@
|
||||||
</div>
|
</div>
|
||||||
<el-space wrap class="group-item-body">
|
<el-space wrap class="group-item-body">
|
||||||
<el-select v-model="model" placeholder="Select" size="large" class="!w-350px">
|
<el-select v-model="model" placeholder="Select" size="large" class="!w-350px">
|
||||||
<el-option
|
<el-option v-for="item in models" :key="item.key" :label="item.name" :value="item.key" />
|
||||||
v-for="item in models"
|
|
||||||
:key="item.key"
|
|
||||||
:label="item.name"
|
|
||||||
:value="item.key"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,12 +78,14 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ImageApi, ImageDrawReqVO, ImageVO} from '@/api/ai/image'
|
import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
|
||||||
import {
|
import {
|
||||||
AiPlatformEnum,
|
AiPlatformEnum,
|
||||||
|
ChatGlmModels,
|
||||||
ImageHotWords,
|
ImageHotWords,
|
||||||
ImageModelVO,
|
ImageModelVO,
|
||||||
OtherPlatformEnum,
|
OtherPlatformEnum,
|
||||||
|
QianFanModels,
|
||||||
TongYiWanXiangModels
|
TongYiWanXiangModels
|
||||||
} from '@/views/ai/utils/constants'
|
} from '@/views/ai/utils/constants'
|
||||||
|
|
||||||
|
@ -96,10 +99,9 @@ const prompt = ref<string>('') // 提示词
|
||||||
const width = ref<number>(512) // 图片宽度
|
const width = ref<number>(512) // 图片宽度
|
||||||
const height = ref<number>(512) // 图片高度
|
const height = ref<number>(512) // 图片高度
|
||||||
const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) // 平台
|
const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) // 平台
|
||||||
const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // 模型
|
const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // 模型 TongYiWanXiangModels、QianFanModels
|
||||||
const model = ref<string>(models.value[0].key) // 模型
|
const model = ref<string>(models.value[0].key) // 模型
|
||||||
|
|
||||||
|
|
||||||
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
|
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
|
||||||
|
|
||||||
/** 选择热词 */
|
/** 选择热词 */
|
||||||
|
@ -131,9 +133,8 @@ const handleGenerateImage = async () => {
|
||||||
prompt: prompt.value, // 提示词
|
prompt: prompt.value, // 提示词
|
||||||
width: width.value, // 图片宽度
|
width: width.value, // 图片宽度
|
||||||
height: height.value, // 图片高度
|
height: height.value, // 图片高度
|
||||||
options: {
|
options: {}
|
||||||
}
|
} as unknown as ImageDrawReqVO
|
||||||
} as ImageDrawReqVO
|
|
||||||
await ImageApi.drawImage(form)
|
await ImageApi.drawImage(form)
|
||||||
} finally {
|
} finally {
|
||||||
// 回调
|
// 回调
|
||||||
|
@ -148,21 +149,24 @@ const settingValues = async (detail: ImageVO) => {
|
||||||
prompt.value = detail.prompt
|
prompt.value = detail.prompt
|
||||||
width.value = detail.width
|
width.value = detail.width
|
||||||
height.value = detail.height
|
height.value = detail.height
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 平台切换 */
|
/** 平台切换 */
|
||||||
const handlerPlatformChange = async (platform) => {
|
const handlerPlatformChange = async (platform: string) => {
|
||||||
// 切换平台,切换模型、风格
|
// 切换平台,切换模型、风格
|
||||||
if (AiPlatformEnum.YI_YAN === platform) {
|
if (AiPlatformEnum.TONG_YI === platform) {
|
||||||
models.value = TongYiWanXiangModels
|
models.value = TongYiWanXiangModels
|
||||||
|
} else if (AiPlatformEnum.YI_YAN === platform) {
|
||||||
|
models.value = QianFanModels
|
||||||
|
} else if (AiPlatformEnum.ZHI_PU === platform) {
|
||||||
|
models.value = ChatGlmModels
|
||||||
} else {
|
} else {
|
||||||
models.value = []
|
models.value = []
|
||||||
}
|
}
|
||||||
// 切换平台,默认选择一个风格
|
// 切换平台,默认选择一个风格
|
||||||
if (models.value.length > 0) {
|
if (models.value.length > 0) {
|
||||||
model.value = models.value[0].key
|
model.value = models.value[0].key
|
||||||
} else {
|
} else {
|
||||||
model.value = ''
|
model.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ const platformOptions = [
|
||||||
value: AiPlatformEnum.STABLE_DIFFUSION
|
value: AiPlatformEnum.STABLE_DIFFUSION
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '其他',
|
label: '其它',
|
||||||
value: 'other'
|
value: 'other'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -88,6 +88,7 @@ const handleRegeneration = async (image: ImageVO) => {
|
||||||
} else if (image.platform === AiPlatformEnum.STABLE_DIFFUSION) {
|
} else if (image.platform === AiPlatformEnum.STABLE_DIFFUSION) {
|
||||||
stableDiffusionRef.value.settingValues(image)
|
stableDiffusionRef.value.settingValues(image)
|
||||||
}
|
}
|
||||||
|
// TODO @fan:貌似 other 重新设置不行?
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,21 @@ export const AiPlatformEnum = {
|
||||||
Ollama: 'Ollama',
|
Ollama: 'Ollama',
|
||||||
STABLE_DIFFUSION: 'StableDiffusion', // Stability AI
|
STABLE_DIFFUSION: 'StableDiffusion', // Stability AI
|
||||||
MIDJOURNEY: 'Midjourney', // Midjourney
|
MIDJOURNEY: 'Midjourney', // Midjourney
|
||||||
SUNO: 'Suno', // Suno AI
|
SUNO: 'Suno' // Suno AI
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OtherPlatformEnum:ImageModelVO [] = [
|
export const OtherPlatformEnum: ImageModelVO[] = [
|
||||||
{
|
{
|
||||||
key: AiPlatformEnum.TONG_YI,
|
key: AiPlatformEnum.TONG_YI,
|
||||||
name: '通义万相'
|
name: '通义万相'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: AiPlatformEnum.YI_YAN,
|
key: AiPlatformEnum.YI_YAN,
|
||||||
name: '百度图片'
|
name: '百度千帆'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: AiPlatformEnum.ZHI_PU,
|
||||||
|
name: '智谱 AI'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -60,6 +64,12 @@ export enum AiWriteTypeEnum {
|
||||||
REPLY // 回复
|
REPLY // 回复
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 表格展示对照map
|
||||||
|
export const AiWriteTypeTableRender = {
|
||||||
|
[AiWriteTypeEnum.WRITING]: '撰写',
|
||||||
|
[AiWriteTypeEnum.REPLY]: '回复',
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 【图片 UI】相关的枚举 ==========
|
// ========== 【图片 UI】相关的枚举 ==========
|
||||||
export const ImageHotWords = [
|
export const ImageHotWords = [
|
||||||
'中国旗袍',
|
'中国旗袍',
|
||||||
|
@ -200,54 +210,6 @@ export const StableDiffusionStylePresets: ImageModelVO[] = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// todo @芋艿 这些是通义的风格,看要不要删除
|
|
||||||
export const TongYiWanXiangStylePresets: ImageModelVO[] = [
|
|
||||||
{
|
|
||||||
key: '-1',
|
|
||||||
name: '上传图像风格'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '0',
|
|
||||||
name: '复古漫画'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
name: '3D童话'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
name: '二次元'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '3',
|
|
||||||
name: '小清新'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '4',
|
|
||||||
name: '未来科技'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '5',
|
|
||||||
name: '国画古风'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '6',
|
|
||||||
name: '将军百战'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '7',
|
|
||||||
name: '炫彩卡通'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '8',
|
|
||||||
name: '清雅国风'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '9',
|
|
||||||
name: '喜迎新年'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export const TongYiWanXiangModels: ImageModelVO[] = [
|
export const TongYiWanXiangModels: ImageModelVO[] = [
|
||||||
{
|
{
|
||||||
key: 'wanx-v1',
|
key: 'wanx-v1',
|
||||||
|
@ -259,6 +221,20 @@ export const TongYiWanXiangModels: ImageModelVO[] = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const QianFanModels: ImageModelVO[] = [
|
||||||
|
{
|
||||||
|
key: 'sd_xl',
|
||||||
|
name: 'sd_xl'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ChatGlmModels: ImageModelVO[] = [
|
||||||
|
{
|
||||||
|
key: 'cogview-3',
|
||||||
|
name: 'cogview-3'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [
|
export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [
|
||||||
{
|
{
|
||||||
key: 'NONE',
|
key: 'NONE',
|
||||||
|
@ -318,7 +294,7 @@ export const Dall3StyleList: ImageModelVO[] = [
|
||||||
|
|
||||||
export interface ImageSizeVO {
|
export interface ImageSizeVO {
|
||||||
key: string
|
key: string
|
||||||
name: string
|
name?: string
|
||||||
style: string
|
style: string
|
||||||
width: string
|
width: string
|
||||||
height: string
|
height: string
|
||||||
|
|
|
@ -24,26 +24,28 @@
|
||||||
</h3>
|
</h3>
|
||||||
</DefineLabel>
|
</DefineLabel>
|
||||||
|
|
||||||
<div class="relative" v-bind="$attrs">
|
<div class="flex flex-col" v-bind="$attrs">
|
||||||
<!-- tab -->
|
<!-- tab -->
|
||||||
<div
|
<div class="w-full pt-2 bg-[#f5f7f9] flex justify-center">
|
||||||
class="absolute left-1/2 top-2 -translate-x-1/2 w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
|
<div class="w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10">
|
||||||
>
|
<div
|
||||||
<div
|
class="flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full"
|
||||||
class="flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full"
|
:class="
|
||||||
:class="selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'"
|
selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'
|
||||||
>
|
"
|
||||||
<ReuseTab
|
>
|
||||||
v-for="tab in tabs"
|
<ReuseTab
|
||||||
:key="tab.value"
|
v-for="tab in tabs"
|
||||||
:text="tab.text"
|
:key="tab.value"
|
||||||
:active="tab.value === selectedTab"
|
:text="tab.text"
|
||||||
:itemClick="() => switchTab(tab.value)"
|
:active="tab.value === selectedTab"
|
||||||
/>
|
:itemClick="() => switchTab(tab.value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="px-7 pb-2 pt-[46px] overflow-y-auto lg:block w-[380px] box-border bg-[#ECEDEF] h-full"
|
class="px-7 pb-2 flex-grow overflow-y-auto lg:block w-[380px] box-border bg-[#f5f7f9] h-full"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<template v-if="selectedTab === 1">
|
<template v-if="selectedTab === 1">
|
||||||
|
@ -102,7 +104,7 @@
|
||||||
import { createReusableTemplate } from '@vueuse/core'
|
import { createReusableTemplate } from '@vueuse/core'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import Tag from './Tag.vue'
|
import Tag from './Tag.vue'
|
||||||
import { WriteVO } from '@/api/ai/writer'
|
import { WriteVO } from 'src/api/ai/write'
|
||||||
import { omit } from 'lodash-es'
|
import { omit } from 'lodash-es'
|
||||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { AiWriteTypeEnum, WriteExample } from '@/views/ai/utils/constants'
|
import { AiWriteTypeEnum, WriteExample } from '@/views/ai/utils/constants'
|
||||||
|
@ -177,10 +179,18 @@ const initData: WriteVO = {
|
||||||
}
|
}
|
||||||
const formData = ref<WriteVO>({ ...initData })
|
const formData = ref<WriteVO>({ ...initData })
|
||||||
|
|
||||||
|
/** 用来记录切换之前所填写的数据,切换的时候给赋值回来 **/
|
||||||
|
const recordFormData = {} as Record<AiWriteTypeEnum, WriteVO>
|
||||||
|
|
||||||
/** 切换tab **/
|
/** 切换tab **/
|
||||||
const switchTab = (value: TabType) => {
|
const switchTab = (value: TabType) => {
|
||||||
selectedTab.value = value
|
if (value !== selectedTab.value) {
|
||||||
formData.value = { ...initData }
|
// 保存之前的久数据
|
||||||
|
recordFormData[selectedTab.value] = formData.value
|
||||||
|
selectedTab.value = value
|
||||||
|
// 将之前的旧数据赋值回来
|
||||||
|
formData.value = { ...initData, ...recordFormData[value] }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 提交写作 */
|
/** 提交写作 */
|
|
@ -1,17 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full box-border flex flex-col px-7">
|
<el-card class="my-card h-full">
|
||||||
<h3 class="m-0 h-14 -mx-7 px-7 shrink-0 flex items-center justify-between bg-[#ecedef]">
|
<template #header
|
||||||
<span>预览</span>
|
><h3 class="m-0 px-7 shrink-0 flex items-center justify-between">
|
||||||
<!-- 展示在右上角 -->
|
<span>预览</span>
|
||||||
<el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
|
<!-- 展示在右上角 -->
|
||||||
<template #icon>
|
<el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
|
||||||
<Icon icon="ph:copy-bold" />
|
<template #icon>
|
||||||
</template>
|
<Icon icon="ph:copy-bold" />
|
||||||
复制
|
</template>
|
||||||
</el-button>
|
复制
|
||||||
</h3>
|
</el-button>
|
||||||
|
</h3></template
|
||||||
|
>
|
||||||
|
|
||||||
<div ref="contentRef" class="hide-scroll-bar flex-grow box-border overflow-y-auto">
|
<div ref="contentRef" class="hide-scroll-bar h-full box-border overflow-y-auto">
|
||||||
<div class="w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7">
|
<div class="w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7">
|
||||||
<!-- 终止生成内容的按钮 -->
|
<!-- 终止生成内容的按钮 -->
|
||||||
<el-button
|
<el-button
|
||||||
|
@ -36,7 +38,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -102,4 +104,17 @@ watch(copied, (val) => {
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.my-card{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
:deep(.el-card__body) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
@extend .hide-scroll-bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- TODO @hhhero:整体没啥问题了。感觉整体框框的样子可以优化下,可以参考下绘图界面。例如说:1)写作的“预览”和绘图的“绘图任务”的 header;2)左右的边界,有个竖线之类的。 -->
|
<div class="absolute top-0 left-0 right-0 bottom-0 flex">
|
||||||
<div class="h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex">
|
|
||||||
<Left
|
<Left
|
||||||
:is-writing="isWriting"
|
:is-writing="isWriting"
|
||||||
class="h-full"
|
class="h-full"
|
||||||
|
@ -21,7 +20,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Left from './components/Left.vue'
|
import Left from './components/Left.vue'
|
||||||
import Right from './components/Right.vue'
|
import Right from './components/Right.vue'
|
||||||
import * as WriteApi from '@/api/ai/writer'
|
import { WriteApi } from '@/api/ai/write'
|
||||||
import { WriteExample } from '@/views/ai/utils/constants'
|
import { WriteExample } from '@/views/ai/utils/constants'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
@ -66,7 +65,7 @@ const submit = (data) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 点击示例触发 */
|
/** 点击示例触发 */
|
||||||
const handleExampleClick = (type: keyof typeof WriteExampleDataJson) => {
|
const handleExampleClick = (type: keyof typeof WriteExample) => {
|
||||||
writeResult.value = WriteExample[type].data
|
writeResult.value = WriteExample[type].data
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="平台" prop="platform">
|
<el-form-item label="平台" prop="platform">
|
||||||
<el-select v-model="queryParams.status" placeholder="请选择平台" clearable class="!w-240px">
|
<el-select v-model="queryParams.platform" placeholder="请选择平台" clearable class="!w-240px">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)"
|
v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
|
@ -70,6 +70,7 @@
|
||||||
>
|
>
|
||||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<!-- TODO @YunaiV 目前没有导出接口,需要导出吗 -->
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
plain
|
plain
|
||||||
|
@ -103,7 +104,13 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="模型" align="center" prop="model" width="180" />
|
<el-table-column label="模型" align="center" prop="model" width="180" />
|
||||||
<el-table-column label="生成内容提示" align="center" prop="prompt" width="180" />
|
<el-table-column
|
||||||
|
label="生成内容提示"
|
||||||
|
align="center"
|
||||||
|
prop="prompt"
|
||||||
|
width="180"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
<el-table-column label="生成的内容" align="center" prop="generatedContent" width="180" />
|
<el-table-column label="生成的内容" align="center" prop="generatedContent" width="180" />
|
||||||
<el-table-column label="原文" align="center" prop="originalContent" width="180" />
|
<el-table-column label="原文" align="center" prop="originalContent" width="180" />
|
||||||
<el-table-column label="长度" align="center" prop="length">
|
<el-table-column label="长度" align="center" prop="length">
|
||||||
|
@ -136,6 +143,7 @@
|
||||||
<el-table-column label="错误信息" align="center" prop="errorMessage" />
|
<el-table-column label="错误信息" align="center" prop="errorMessage" />
|
||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<!-- TODO @YunaiV 目前没有修改接口,写作要可以更改吗-->
|
||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
|
@ -168,8 +176,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
// TODO 芋艿:这里应该是 write
|
import { useRouter } from 'vue-router'
|
||||||
import { WriteApi, WriteVO } from '@/api/ai/writer'
|
import { WriteApi, AiWritePageReqVO, AiWriteRespVo } from '@/api/ai/write'
|
||||||
import * as UserApi from '@/api/system/user'
|
import * as UserApi from '@/api/system/user'
|
||||||
|
|
||||||
/** AI 写作列表 */
|
/** AI 写作列表 */
|
||||||
|
@ -177,17 +185,18 @@ defineOptions({ name: 'AiWriteManager' })
|
||||||
|
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
|
const router = useRouter() // 路由
|
||||||
|
|
||||||
const loading = ref(true) // 列表的加载中
|
const loading = ref(true) // 列表的加载中
|
||||||
const list = ref<WriteVO[]>([]) // 列表的数据
|
const list = ref<AiWriteRespVo[]>([]) // 列表的数据
|
||||||
const total = ref(0) // 列表的总页数
|
const total = ref(0) // 列表的总页数
|
||||||
const queryParams = reactive({
|
const queryParams = reactive<AiWritePageReqVO>({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
type: undefined,
|
type: undefined,
|
||||||
platform: undefined,
|
platform: undefined,
|
||||||
createTime: []
|
createTime: undefined
|
||||||
})
|
})
|
||||||
const queryFormRef = ref() // 搜索的表单
|
const queryFormRef = ref() // 搜索的表单
|
||||||
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
|
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
|
||||||
|
@ -216,6 +225,15 @@ const resetQuery = () => {
|
||||||
handleQuery()
|
handleQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 新增方法,跳转到写作页面 **/
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'create':
|
||||||
|
router.push('/ai/write')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -28,9 +28,7 @@ const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
// ======================= WebSocket start =======================
|
// ======================= WebSocket start =======================
|
||||||
const server = ref(
|
const server = ref(
|
||||||
(import.meta.env.VITE_BASE_URL + '/infra/ws/').replace('http', 'ws') +
|
(import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') + '?token=' + getAccessToken()
|
||||||
'?token=' +
|
|
||||||
getAccessToken()
|
|
||||||
) // WebSocket 服务地址
|
) // WebSocket 服务地址
|
||||||
|
|
||||||
/** 发起 WebSocket 连接 */
|
/** 发起 WebSocket 连接 */
|
||||||
|
|
|
@ -50,4 +50,9 @@ declare global {
|
||||||
name: string
|
name: string
|
||||||
children?: Tree[] | any[]
|
children?: Tree[] | any[]
|
||||||
}
|
}
|
||||||
|
// 分页数据公共返回
|
||||||
|
interface PageResult<T> {
|
||||||
|
list: T // 数据
|
||||||
|
total: number // 总量
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue