Skip to content

Commit 5730707

Browse files
committed
[代码优化]AI: 写作添加注释,增加可读性,调整代码,方便后续调整
1 parent 6224602 commit 5730707

File tree

8 files changed

+154
-174
lines changed

8 files changed

+154
-174
lines changed

src/api/ai/writer/index.ts

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,14 @@ import { fetchEventSource } from '@microsoft/fetch-event-source'
33
import { getAccessToken } from '@/utils/auth'
44
import { config } from '@/config/axios/config'
55

6-
// TODO @hhhero:可以改成 WriteVO 哈,主要是保持一致
7-
export interface WriteParams {
8-
// TODO @hhhero:注释。每个属性的后面哈。会更简洁一点
9-
/**
10-
* 1:撰写 2:回复
11-
*/
12-
type: 1 | 2
13-
/**
14-
* 写作内容提示 1。撰写 2回复
15-
*/
16-
prompt: string
17-
/**
18-
* 原文
19-
*/
20-
originalContent: string
21-
/**
22-
* 长度
23-
*/
24-
length: number
25-
/**
26-
* 格式
27-
*/
28-
format: number
29-
/**
30-
* 语气
31-
*/
32-
tone: number
33-
/**
34-
* 语言
35-
*/
36-
language: number
6+
export interface WriteVO {
7+
type: 1 | 2 // 1:撰写 2:回复
8+
prompt: string // 写作内容提示 1。撰写 2回复
9+
originalContent: string // 原文
10+
length: number // 长度
11+
format: number // 格式
12+
tone: number // 语气
13+
language: number // 语言
3714
}
3815

3916
export const writeStream = ({
@@ -43,7 +20,7 @@ export const writeStream = ({
4320
onError,
4421
ctrl
4522
}: {
46-
data: WriteParams
23+
data: WriteVO
4724
onMessage?: (res: any) => void
4825
onError?: (...args: any[]) => void
4926
onClose?: (...args: any[]) => void

src/views/ai/utils/constants.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,11 @@ export const AiMusicStatusEnum = {
4040
SUCCESS: 20, // 已完成
4141
FAIL: 30 // 已失败
4242
}
43+
44+
/**
45+
* AI 写作类型的枚举
46+
*/
47+
export enum AiWriteTypeEnum {
48+
WRITING = 1, // 撰写
49+
REPLY // 回复
50+
}

src/views/ai/utils/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,16 @@
1111
export const hasChinese = async (str) => {
1212
return /[\u4e00-\u9fa5]/.test(str)
1313
}
14+
15+
/** 写作点击示例时的数据 **/
16+
export const WriteExampleDataJson = {
17+
write: {
18+
prompt: 'vue',
19+
data: 'Vue.js 是一种用于构建用户界面的渐进式 JavaScript 框架。它的核心库只关注视图层,易于上手,同时也便于与其他库或已有项目整合。\n\nVue.js 的特点包括:\n- 响应式的数据绑定:Vue.js 会自动将数据与 DOM 同步,使得状态管理变得更加简单。\n- 组件化:Vue.js 允许开发者通过小型、独立和通常可复用的组件构建大型应用。\n- 虚拟 DOM:Vue.js 使用虚拟 DOM 实现快速渲染,提高了性能。\n\n在 Vue.js 中,一个典型的应用结构可能包括:\n1. 根实例:每个 Vue 应用都需要一个根实例作为入口点。\n2. 组件系统:可以创建自定义的可复用组件。\n3. 指令:特殊的带有前缀 v- 的属性,为 DOM 元素提供特殊的行为。\n4. 插值:用于文本内容,将数据动态地插入到 HTML。\n5. 计算属性和侦听器:用于处理数据的复杂逻辑和响应数据变化。\n6. 条件渲染:根据条件决定元素的渲染。\n7. 列表渲染:用于显示列表数据。\n8. 事件处理:响应用户交互。\n9. 表单输入绑定:处理表单输入和验证。\n10. 组件生命周期钩子:在组件的不同阶段执行特定的函数。\n\nVue.js 还提供了官方的路由器 Vue Router 和状态管理库 Vuex,以支持构建复杂的单页应用(SPA)。\n\n在开发过程中,开发者通常会使用 Vue CLI,这是一个强大的命令行工具,用于快速生成 Vue 项目脚手架,集成了诸如 Babel、Webpack 等现代前端工具,以及热重载、代码检测等开发体验优化功能。\n\nVue.js 的生态系统还包括大量的第三方库和插件,如 Vuetify(UI 组件库)、Vue Test Utils(测试工具)等,这些都极大地丰富了 Vue.js 的开发生态。\n\n总的来说,Vue.js 是一个灵活、高效的前端框架,适合从小型项目到大型企业级应用的开发。它的易用性、灵活性和强大的社区支持使其成为许多开发者的首选框架之一。'
20+
},
21+
reply: {
22+
originalContent: '领导,我想请假',
23+
prompt: '不批',
24+
data: '您的请假申请已收悉,经核实和考虑,暂时无法批准您的请假申请。\n\n如有特殊情况或紧急事务,请及时与我联系。\n\n祝工作顺利。\n\n谢谢。'
25+
}
26+
}

src/views/ai/writer/components/Left.vue

Lines changed: 42 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
</h3>
2525
</DefineLabel>
2626

27-
<!-- TODO 小屏幕的时候是定位在左边的,大屏是分开的 -->
27+
<!-- TODO @hhhero 小屏幕的时候是定位在左边的,大屏是分开的 -->
2828
<div class="relative" v-bind="$attrs">
2929
<!-- tab -->
3030
<div
3131
class="absolute left-1/2 top-2 -translate-x-1/2 w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
3232
>
3333
<div
3434
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"
35-
:class="selectedTab === 2 && 'after:transform after:translate-x-[100%]'"
35+
:class="selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'"
3636
>
3737
<ReuseTab
3838
v-for="tab in tabs"
@@ -53,7 +53,7 @@
5353
type="textarea"
5454
:rows="5"
5555
:maxlength="500"
56-
v-model="writeForm.prompt"
56+
v-model="formData.prompt"
5757
placeholder="请输入写作内容"
5858
showWordLimit
5959
/>
@@ -65,7 +65,7 @@
6565
type="textarea"
6666
:rows="5"
6767
:maxlength="500"
68-
v-model="writeForm.originalContent"
68+
v-model="formData.originalContent"
6969
placeholder="请输入原文"
7070
showWordLimit
7171
/>
@@ -75,20 +75,20 @@
7575
type="textarea"
7676
:rows="5"
7777
:maxlength="500"
78-
v-model="writeForm.prompt"
78+
v-model="formData.prompt"
7979
placeholder="请输入回复内容"
8080
showWordLimit
8181
/>
8282
</template>
8383

8484
<ReuseLabel label="长度" />
85-
<Tag v-model="writeForm.length" :tags="writeTags.lenTags" />
85+
<Tag v-model="formData.length" :tags="getIntDictOptions('ai_write_length')" />
8686
<ReuseLabel label="格式" />
87-
<Tag v-model="writeForm.format" :tags="writeTags.formatTags" />
87+
<Tag v-model="formData.format" :tags="getIntDictOptions('ai_write_format')" />
8888
<ReuseLabel label="语气" />
89-
<Tag v-model="writeForm.tone" :tags="writeTags.toneTags" />
89+
<Tag v-model="formData.tone" :tags="getIntDictOptions('ai_write_tone')" />
9090
<ReuseLabel label="语言" />
91-
<Tag v-model="writeForm.language" :tags="writeTags.langTags" />
91+
<Tag v-model="formData.language" :tags="getIntDictOptions('ai_write_language')" />
9292

9393
<div class="flex items-center justify-center mt-3">
9494
<el-button :disabled="isWriting">重置</el-button>
@@ -103,12 +103,13 @@
103103
import { createReusableTemplate } from '@vueuse/core'
104104
import { ref } from 'vue'
105105
import Tag from './Tag.vue'
106-
import { WriteParams } from '@/api/ai/writer'
106+
import { WriteVO } from '@/api/ai/writer'
107107
import { omit } from 'lodash-es'
108108
import { getIntDictOptions } from '@/utils/dict'
109-
import dataJson from '../data.json'
109+
import { WriteExampleDataJson } from '@/views/ai/utils/utils'
110+
import { AiWriteTypeEnum } from "@/views/ai/utils/constants";
110111
111-
type TabType = WriteParams['type']
112+
type TabType = WriteVO['type']
112113
113114
const message = useMessage()
114115
@@ -117,33 +118,47 @@ defineProps<{
117118
}>()
118119
119120
const emits = defineEmits<{
120-
(e: 'submit', params: Partial<WriteParams>)
121+
(e: 'submit', params: Partial<WriteVO>)
121122
(e: 'example', param: 'write' | 'reply')
122123
}>()
123124
124125
const example = (type: 'write' | 'reply') => {
125-
writeForm.value = {
126+
formData.value = {
126127
...initData,
127-
...omit(dataJson[type], ['data'])
128+
...omit(WriteExampleDataJson[type], ['data'])
128129
}
129130
emits('example', type)
130131
}
131132
132-
const selectedTab = ref<TabType>(1)
133+
const selectedTab = ref<TabType>(AiWriteTypeEnum.WRITING)
133134
const tabs: {
134135
text: string
135136
value: TabType
136137
}[] = [
137-
{ text: '撰写', value: 1 }, // TODO @hhhero:1、2 这个枚举到 constants 里。方便后续万一要调整
138-
{ text: '回复', value: 2 }
138+
{ text: '撰写', value: AiWriteTypeEnum.WRITING },
139+
{ text: '回复', value: AiWriteTypeEnum.REPLY }
139140
]
140141
const [DefineTab, ReuseTab] = createReusableTemplate<{
141142
active?: boolean
142143
text: string
143144
itemClick: () => void
144145
}>()
145146
146-
const initData: WriteParams = {
147+
/**
148+
* 可以在template里边定义可复用的组件,DefineLabel,ReuseLabel是采用的解构赋值,都是Vue组件
149+
* 直接通过组件的形式使用,<DefineLabel v-slot="{ label, hint, hintClick }">中间是需要复用的组件代码</DefineLabel>,通过<ReuseLabel />来使用定义的组件
150+
* DefineLabel里边的v-slot="{ label, hint, hintClick }“相当于是解构了组件的prop,需要注意的是boolean类型,需要显式的赋值比如 <ReuseLabel :flag="true" />
151+
* 事件也得以prop形式传入,不能是@event的形式,比如下面的hintClick需要<ReuseLabel :hintClick="() => { doSomething }"/>
152+
* @see https://vueuse.org/createReusableTemplate
153+
*/
154+
const [DefineLabel, ReuseLabel] = createReusableTemplate<{
155+
label: string
156+
class?: string
157+
hint?: string
158+
hintClick?: () => void
159+
}>()
160+
161+
const initData: WriteVO = {
147162
type: 1,
148163
prompt: '',
149164
originalContent: '',
@@ -152,49 +167,26 @@ const initData: WriteParams = {
152167
length: 1,
153168
format: 1
154169
}
155-
// TODO @hhhero:这个字段,要不叫 formData,和其他模块保持一致。然后 initData 和它也更好对应上
156-
const writeForm = ref<WriteParams>({ ...initData })
157-
158-
// TODO @hhhero:这种一次性的变量,要不直接 vue template 直接调用。目的是:让 ts 这块,更专注逻辑哈。
159-
const writeTags = {
160-
// 长度 TODO @hhhero:注释放在和面哈;
161-
// TODO @hhhero:一般 length 不用缩写哈。更完整会更容易阅读;
162-
lenTags: getIntDictOptions('ai_write_length'),
163-
// 格式
164-
165-
formatTags: getIntDictOptions('ai_write_format'),
166-
// 语气
167-
168-
toneTags: getIntDictOptions('ai_write_tone'),
169-
// 语言
170-
langTags: getIntDictOptions('ai_write_language')
171-
//
172-
}
173-
174-
// TODO @hhhero:这个写法不错。要不写个简单的注释,我怕很多人不懂哈。
175-
const [DefineLabel, ReuseLabel] = createReusableTemplate<{
176-
label: string
177-
class?: string
178-
hint?: string
179-
hintClick?: () => void
180-
}>()
181-
170+
const formData = ref<WriteVO>({ ...initData })
171+
/** 切换tab **/
182172
const switchTab = (value: TabType) => {
183173
selectedTab.value = value
184-
writeForm.value = { ...initData }
174+
formData.value = { ...initData }
185175
}
186176
187177
const submit = () => {
188-
if (selectedTab.value === 2 && !writeForm.value.originalContent) {
178+
if (selectedTab.value === 2 && !formData.value.originalContent) {
189179
message.warning('请输入原文')
190180
return
191181
}
192-
if (!writeForm.value.prompt) {
182+
if (!formData.value.prompt) {
193183
message.warning(`请输入${selectedTab.value === 1 ? '写作' : '回复'}内容`)
194184
return
195185
}
196186
emits('submit', {
197-
...(selectedTab.value === 1 ? omit(writeForm.value, ['originalContent']) : writeForm.value),
187+
/** 撰写的时候没有 originalContent 字段**/
188+
...(selectedTab.value === 1 ? omit(formData.value, ['originalContent']) : formData.value),
189+
/** 使用选中tab值覆盖当前的type类型 **/
198190
type: selectedTab.value
199191
})
200192
}

src/views/ai/writer/components/Right.vue

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
<el-button
66
color="#846af7"
77
v-show="showCopy"
8-
@click="copyMsg"
9-
class="absolute top-2 right-2 copy-btn"
10-
:data-clipboard-target="inputId"
8+
@click="copyContent"
9+
class="absolute top-2 right-2"
1110
>
1211
复制
1312
</el-button>
@@ -23,7 +22,7 @@
2322
<el-input
2423
id="inputId"
2524
type="textarea"
26-
v-model="compMsg"
25+
v-model="compContent"
2726
autosize
2827
:input-style="{ boxShadow: 'none' }"
2928
resize="none"
@@ -41,25 +40,27 @@ const message = useMessage()
4140
const { copied, copy } = useClipboard()
4241
4342
const props = defineProps({
44-
msg: {
43+
content: {
44+
// 生成的结果
4545
type: String,
4646
default: ''
4747
},
4848
isWriting: {
49+
// 是否正在生成文章
4950
type: Boolean,
5051
default: false
5152
}
5253
})
5354
54-
const emits = defineEmits(['update:msg', 'stopStream'])
55+
const emits = defineEmits(['update:content', 'stopStream'])
5556
56-
// TODO @hhhero:是不是 Msg 改成 Content 这种哈。或者 Message。
57-
const compMsg = computed({
57+
// 通过计算属性,双向绑定,更改生成的内容,考虑到用户想要更改生成文章的情况
58+
const compContent = computed({
5859
get() {
59-
return props.msg
60+
return props.content
6061
},
6162
set(val) {
62-
emits('update:msg', val)
63+
emits('update:content', val)
6364
}
6465
})
6566
@@ -72,12 +73,12 @@ defineExpose({
7273
})
7374
7475
/** 点击复制的时候复制内容 */
75-
const showCopy = computed(() => props.msg && !props.isWriting) // 是否展示拷贝
76-
const inputId = computed(() => getCurrentInstance()?.uid) // TODO @hhhero:这个可以写个注释哈
77-
const copyMsg = () => {
78-
copy(props.msg)
76+
const showCopy = computed(() => props.content && !props.isWriting) // 是否展示复制按钮,在生成内容完成的时候展示
77+
const copyContent = () => {
78+
copy(props.content)
7979
}
8080
81+
// 复制成功的时候copied.value为true
8182
watch(copied, (val) => {
8283
if (val) {
8384
message.success('复制成功')

src/views/ai/writer/data.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)