[代码优化]AI: 写作添加预览header,调整生成内容区域布局,将右边铺满
parent
5730707be9
commit
9e628ba59d
|
@ -91,7 +91,7 @@
|
||||||
<Tag v-model="formData.language" :tags="getIntDictOptions('ai_write_language')" />
|
<Tag v-model="formData.language" :tags="getIntDictOptions('ai_write_language')" />
|
||||||
|
|
||||||
<div class="flex items-center justify-center mt-3">
|
<div class="flex items-center justify-center mt-3">
|
||||||
<el-button :disabled="isWriting">重置</el-button>
|
<el-button :disabled="isWriting" @click="reset">重置</el-button>
|
||||||
<el-button :loading="isWriting" @click="submit" color="#846af7">生成</el-button>
|
<el-button :loading="isWriting" @click="submit" color="#846af7">生成</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -120,8 +120,10 @@ defineProps<{
|
||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
(e: 'submit', params: Partial<WriteVO>)
|
(e: 'submit', params: Partial<WriteVO>)
|
||||||
(e: 'example', param: 'write' | 'reply')
|
(e: 'example', param: 'write' | 'reply')
|
||||||
|
(e: 'reset')
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
/** 点击示例的时候,将定义好的文章作为示例展示出来 **/
|
||||||
const example = (type: 'write' | 'reply') => {
|
const example = (type: 'write' | 'reply') => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
...initData,
|
...initData,
|
||||||
|
@ -129,7 +131,11 @@ const example = (type: 'write' | 'reply') => {
|
||||||
}
|
}
|
||||||
emits('example', type)
|
emits('example', type)
|
||||||
}
|
}
|
||||||
|
/** 重置,将表单值作为初选值 **/
|
||||||
|
const reset = () => {
|
||||||
|
formData.value = {...initData}
|
||||||
|
emits('reset')
|
||||||
|
}
|
||||||
const selectedTab = ref<TabType>(AiWriteTypeEnum.WRITING)
|
const selectedTab = ref<TabType>(AiWriteTypeEnum.WRITING)
|
||||||
const tabs: {
|
const tabs: {
|
||||||
text: string
|
text: string
|
||||||
|
|
|
@ -1,24 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full box-border py-6 px-7">
|
<div class="h-full box-border flex flex-col px-7">
|
||||||
<div class="w-full h-full relative bg-white box-border p-3 sm:p-16 pr-0">
|
<h3 class="m-0 h-14 -mx-7 px-7 shrink-0 flex items-center justify-between bg-[#ecedef]">
|
||||||
|
<span>预览</span>
|
||||||
<!-- 展示在右上角 -->
|
<!-- 展示在右上角 -->
|
||||||
<el-button
|
<el-button
|
||||||
color="#846af7"
|
color="#846af7"
|
||||||
v-show="showCopy"
|
v-show="showCopy"
|
||||||
@click="copyContent"
|
@click="copyContent"
|
||||||
class="absolute top-2 right-2"
|
size="small"
|
||||||
>
|
>
|
||||||
|
<template #icon>
|
||||||
|
<Icon icon="ph:copy-bold" />
|
||||||
|
</template>
|
||||||
复制
|
复制
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 展示在下面中间的位置 -->
|
|
||||||
<el-button
|
|
||||||
v-show="isWriting"
|
</h3>
|
||||||
class="absolute bottom-2 left-1/2 -translate-x-1/2"
|
|
||||||
@click="emits('stopStream')"
|
<div ref="contentRef" class="hide-scroll-bar flex-grow 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>
|
<el-button
|
||||||
<div ref="contentRef" class="w-full h-full pr-3 sm:pr-16 overflow-y-auto">
|
v-show="isWriting"
|
||||||
|
class="absolute bottom-2 sm:bottom-5 left-1/2 -translate-x-1/2 z-36"
|
||||||
|
@click="emits('stopStream')"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<Icon icon="material-symbols:stop" />
|
||||||
|
</template>
|
||||||
|
终止生成
|
||||||
|
</el-button>
|
||||||
<el-input
|
<el-input
|
||||||
id="inputId"
|
id="inputId"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
|
@ -85,3 +98,15 @@ watch(copied, (val) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.hide-scroll-bar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex">
|
<div class="h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex">
|
||||||
<Left :is-writing="isWriting" class="h-full" @submit="submit" @example="handleExampleClick" />
|
<Left
|
||||||
<!-- TODO @hhhero:顶部应该有个预览的 header -->
|
:is-writing="isWriting"
|
||||||
<!-- TODO @hhhero:整个 Right 组件的框,没铺满的感觉? -->
|
class="h-full"
|
||||||
|
@submit="submit"
|
||||||
|
@reset="reset"
|
||||||
|
@example="handleExampleClick"
|
||||||
|
/>
|
||||||
<Right
|
<Right
|
||||||
:is-writing="isWriting"
|
:is-writing="isWriting"
|
||||||
@stop-stream="stopStream"
|
@stop-stream="stopStream"
|
||||||
|
@ -14,54 +18,59 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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 * as WriteApi from '@/api/ai/writer'
|
||||||
import { WriteExampleDataJson } from '@/views/ai/utils/utils'
|
import { WriteExampleDataJson } from '@/views/ai/utils/utils'
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
const writeResult = ref('') // 写作结果
|
const writeResult = ref('') // 写作结果
|
||||||
const isWriting = ref(false) // 是否正在写作中
|
const isWriting = ref(false) // 是否正在写作中
|
||||||
const abortController = ref<AbortController>() // // 写作进行中 abort 控制器(控制 stream 写作)
|
const abortController = ref<AbortController>() // // 写作进行中 abort 控制器(控制 stream 写作)
|
||||||
|
|
||||||
/** 停止 stream 生成 */
|
/** 停止 stream 生成 */
|
||||||
const stopStream = () => {
|
const stopStream = () => {
|
||||||
abortController.value?.abort()
|
abortController.value?.abort()
|
||||||
isWriting.value = false
|
isWriting.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 执行写作 */
|
/** 执行写作 */
|
||||||
const rightRef = ref<InstanceType<typeof Right>>()
|
const rightRef = ref<InstanceType<typeof Right>>()
|
||||||
const submit = (data) => {
|
const submit = (data) => {
|
||||||
abortController.value = new AbortController()
|
abortController.value = new AbortController()
|
||||||
writeResult.value = ''
|
writeResult.value = ''
|
||||||
isWriting.value = true
|
isWriting.value = true
|
||||||
WriteApi.writeStream({
|
WriteApi.writeStream({
|
||||||
data,
|
data,
|
||||||
onMessage: async (res) => {
|
onMessage: async (res) => {
|
||||||
const { code, data, msg } = JSON.parse(res.data)
|
const { code, data, msg } = JSON.parse(res.data)
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
message.alert(`写作异常! ${msg}`)
|
message.alert(`写作异常! ${msg}`)
|
||||||
stopStream()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeResult.value = writeResult.value + data
|
|
||||||
nextTick(() => {
|
|
||||||
rightRef.value?.scrollToBottom()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
ctrl: abortController.value,
|
|
||||||
onClose: stopStream,
|
|
||||||
onError: (...err) => {
|
|
||||||
console.error('写作异常', ...err)
|
|
||||||
stopStream()
|
stopStream()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
})
|
writeResult.value = writeResult.value + data
|
||||||
}
|
nextTick(() => {
|
||||||
|
rightRef.value?.scrollToBottom()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ctrl: abortController.value,
|
||||||
|
onClose: stopStream,
|
||||||
|
onError: (...err) => {
|
||||||
|
console.error('写作异常', ...err)
|
||||||
|
stopStream()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/** 点击示例触发 */
|
/** 点击示例触发 */
|
||||||
const handleExampleClick = (type: keyof typeof WriteExampleDataJson) => {
|
const handleExampleClick = (type: keyof typeof WriteExampleDataJson) => {
|
||||||
writeResult.value = WriteExampleDataJson[type].data
|
writeResult.value = WriteExampleDataJson[type].data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 点击重置的时候清空写作的结果**/
|
||||||
|
const reset = () => {
|
||||||
|
writeResult.value = ''
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue