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 request from '@/config/axios'
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:回复
......@@ -21,45 +21,65 @@ export interface WriteVO {
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
})
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
}
// AI 写作 API
export const WriteApi = {
// 查询AI 写作分页
getWritePage: async (params: any) => {
return await request.get({ url: `/ai/write/page`, params })
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 写作
deleteWrite: async (id: number) => {
return await request.delete({ url: `/ai/write/delete?id=` + id })
// 获取写作列表
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 } })
}
}
......@@ -64,6 +64,12 @@ export enum AiWriteTypeEnum {
REPLY // 回复
}
// 表格展示对照map
export const AiWriteTypeTableRender = {
[AiWriteTypeEnum.WRITING]: '撰写',
[AiWriteTypeEnum.REPLY]: '回复',
}
// ========== 【图片 UI】相关的枚举 ==========
export const ImageHotWords = [
'中国旗袍',
......
......@@ -24,26 +24,28 @@
</h3>
</DefineLabel>
<div class="relative" v-bind="$attrs">
<div class="flex flex-col" v-bind="$attrs">
<!-- tab -->
<div
class="absolute left-1/2 top-2 -translate-x-1/2 w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
>
<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="selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'"
>
<ReuseTab
v-for="tab in tabs"
:key="tab.value"
:text="tab.text"
:active="tab.value === selectedTab"
:itemClick="() => switchTab(tab.value)"
/>
<div class="w-full pt-2 bg-[#f5f7f9] flex justify-center">
<div class="w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10">
<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="
selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'
"
>
<ReuseTab
v-for="tab in tabs"
:key="tab.value"
:text="tab.text"
:active="tab.value === selectedTab"
:itemClick="() => switchTab(tab.value)"
/>
</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>
<template v-if="selectedTab === 1">
......@@ -102,7 +104,7 @@
import { createReusableTemplate } from '@vueuse/core'
import { ref } from '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 { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { AiWriteTypeEnum, WriteExample } from '@/views/ai/utils/constants'
......@@ -177,10 +179,18 @@ const initData: WriteVO = {
}
const formData = ref<WriteVO>({ ...initData })
/** 用来记录切换之前所填写的数据,切换的时候给赋值回来 **/
const recordFormData = {} as Record<AiWriteTypeEnum, WriteVO>
/** 切换tab **/
const switchTab = (value: TabType) => {
selectedTab.value = value
formData.value = { ...initData }
if (value !== selectedTab.value) {
// 保存之前的久数据
recordFormData[selectedTab.value] = formData.value
selectedTab.value = value
// 将之前的旧数据赋值回来
formData.value = { ...initData, ...recordFormData[value] }
}
}
/** 提交写作 */
......
<template>
<div class="h-full box-border flex flex-col px-7">
<h3 class="m-0 h-14 -mx-7 px-7 shrink-0 flex items-center justify-between bg-[#ecedef]">
<span>预览</span>
<!-- 展示在右上角 -->
<el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
<template #icon>
<Icon icon="ph:copy-bold" />
</template>
复制
</el-button>
</h3>
<el-card class="my-card h-full">
<template #header
><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>
<Icon icon="ph:copy-bold" />
</template>
复制
</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">
<!-- 终止生成内容的按钮 -->
<el-button
......@@ -36,7 +38,7 @@
/>
</div>
</div>
</div>
</el-card>
</template>
<script setup lang="ts">
......@@ -102,4 +104,17 @@ watch(copied, (val) => {
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>
<template>
<!-- TODO @hhhero:整体没啥问题了。感觉整体框框的样子可以优化下,可以参考下绘图界面。例如说:1)写作的“预览”和绘图的“绘图任务”的 header;2)左右的边界,有个竖线之类的。 -->
<div class="h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex">
<div class="absolute top-0 left-0 right-0 bottom-0 flex">
<Left
:is-writing="isWriting"
class="h-full"
......@@ -21,7 +20,7 @@
<script setup lang="ts">
import Left from './components/Left.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'
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
}
......
......@@ -39,7 +39,7 @@
</el-select>
</el-form-item>
<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
v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)"
:key="dict.value"
......@@ -70,6 +70,7 @@
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<!-- TODO @YunaiV 目前没有导出接口,需要导出吗 -->
<el-button
type="success"
plain
......@@ -103,7 +104,13 @@
</template>
</el-table-column>
<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="originalContent" width="180" />
<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">
<template #default="scope">
<!-- TODO @YunaiV 目前没有修改接口,写作要可以更改吗-->
<el-button
link
type="primary"
......@@ -168,8 +176,8 @@
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
// TODO 芋艿:这里应该是 write
import { WriteApi, WriteVO } from '@/api/ai/writer'
import { useRouter } from 'vue-router'
import { WriteApi, AiWritePageReqVO, AiWriteRespVo } from '@/api/ai/write'
import * as UserApi from '@/api/system/user'
/** AI 写作列表 */
......@@ -177,17 +185,18 @@ defineOptions({ name: 'AiWriteManager' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const router = useRouter() // 路由
const loading = ref(true) // 列表的加载中
const list = ref<WriteVO[]>([]) // 列表的数据
const list = ref<AiWriteRespVo[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
const queryParams = reactive<AiWritePageReqVO>({
pageNo: 1,
pageSize: 10,
userId: undefined,
type: undefined,
platform: undefined,
createTime: []
createTime: undefined
})
const queryFormRef = ref() // 搜索的表单
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
......@@ -216,6 +225,15 @@ const resetQuery = () => {
handleQuery()
}
/** 新增方法,跳转到写作页面 **/
const openForm = (type: string, id?: number) => {
switch (type) {
case 'create':
router.push('/ai/write')
break
}
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
......
......@@ -50,4 +50,9 @@ declare global {
name: string
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