Commit 35b2708c by 芋道源码 Committed by Gitee

!482 [代码优化]AI: 写作页面样式调整,目录更名writer => write,写作管理更改

Merge pull request !482 from hhhero/dev
parents 69940e27 c4ee9581
import { fetchEventSource } from '@microsoft/fetch-event-source' import { fetchEventSource } from '@microsoft/fetch-event-source'
import request from '@/config/axios'
import { getAccessToken } from '@/utils/auth' import { getAccessToken } from '@/utils/auth'
import { config } from '@/config/axios/config' import { config } from '@/config/axios/config'
import { AiWriteTypeEnum } from '@/views/ai/utils/constants' import { AiWriteTypeEnum } from '@/views/ai/utils/constants'
import request from '@/config/axios'
export interface WriteVO { export interface WriteVO {
type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复 type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
...@@ -21,45 +21,65 @@ export interface WriteVO { ...@@ -21,45 +21,65 @@ export interface WriteVO {
createTime?: Date // 创建时间 createTime?: Date // 创建时间
} }
// TODO @hhero:搞成 WriteApi,类似 ConversationApi 一样。这样更有类的概念,后续引入某个 Api,然后调用它的方法就可以了。 export interface AiWritePageReqVO extends PageParam {
export const writeStream = ({ userId?: number // 用户编号
data, type?: AiWriteTypeEnum // 写作类型
onClose, platform?: string // 平台
onMessage, createTime?: [string, string] // 创建时间
onError, }
ctrl
}: { export interface AiWriteRespVo {
data: WriteVO id: number
onMessage?: (res: any) => void userId: number
onError?: (...args: any[]) => void type: number
onClose?: (...args: any[]) => void platform: string
ctrl: AbortController model: string
}) => { prompt: string
const token = getAccessToken() generatedContent: string
return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, { originalContent: string
method: 'post', length: number
headers: { format: number
'Content-Type': 'application/json', tone: number
Authorization: `Bearer ${token}` language: number
}, errorMessage: string
openWhenHidden: true, createTime: string
body: JSON.stringify(data),
onmessage: onMessage,
onerror: onError,
onclose: onClose,
signal: ctrl.signal
})
} }
// AI 写作 API
export const WriteApi = { export const WriteApi = {
// 查询AI 写作分页 writeStream: ({
getWritePage: async (params: any) => { data,
return await request.get({ url: `/ai/write/page`, params }) 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 写作 getWritePage: (params: AiWritePageReqVO) => {
deleteWrite: async (id: number) => { return request.get<PageResult<AiWriteRespVo[]>>({ url: `/ai/write/page`, params })
return await request.delete({ url: `/ai/write/delete?id=` + id }) },
// 删除写作
deleteWrite(id: number) {
return request.delete({ url: `/ai/write/delete`, params: { id } })
} }
} }
...@@ -64,6 +64,12 @@ export enum AiWriteTypeEnum { ...@@ -64,6 +64,12 @@ export enum AiWriteTypeEnum {
REPLY // 回复 REPLY // 回复
} }
// 表格展示对照map
export const AiWriteTypeTableRender = {
[AiWriteTypeEnum.WRITING]: '撰写',
[AiWriteTypeEnum.REPLY]: '回复',
}
// ========== 【图片 UI】相关的枚举 ========== // ========== 【图片 UI】相关的枚举 ==========
export const ImageHotWords = [ export const ImageHotWords = [
'中国旗袍', '中国旗袍',
......
...@@ -24,26 +24,28 @@ ...@@ -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 @@ ...@@ -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 = { ...@@ -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] }
}
} }
/** 提交写作 */ /** 提交写作 */
......
<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 @@ ...@@ -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) => { ...@@ -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>
<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 @@ ...@@ -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) => { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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' }) ...@@ -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 = () => { ...@@ -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 {
......
...@@ -50,4 +50,9 @@ declare global { ...@@ -50,4 +50,9 @@ declare global {
name: string name: string
children?: Tree[] | any[] children?: Tree[] | any[]
} }
// 分页数据公共返回
interface PageResult<T> {
list: T // 数据
total: number // 总量
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment