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