Files
moc/src/views/my/initiateChange/modules/changeTraining.vue
T

121 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 变更培训内容 -->
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { AiError, aiTraining } from "@/service/api/ai";
import Footer from './footer.vue';
const themeStore = useThemeStore();
const props = defineProps(['type','isAiOpen','title','currentId','formInfo', 'currentForm', 'confirmed','members'])
const emit = defineEmits(['save','submit','confirmTab']);
watch(() => props.currentForm, (newVal:any) => {
// 过滤出需要的字段
const {
attachments,
change_id,
created_at,
id,
updated_at,
...rest
} = newVal;
form.value = rest;
})
const footerRef = ref<any>(null);
const aiFail = (e: any) => {
if (e instanceof AiError) window.$message?.warning(`AI 分析失败:${e.message},可手动填写`);
else window.$message?.warning("AI 分析失败,可手动填写");
};
// 是否是ai生成
const isAiGenerated = ref<boolean>(false);
const form = ref<{ content: string }>({
content: ''
});
// 重新生成变更培训内容(footer 派发)
const onRegenerate = async () => {
const info = props.formInfo;
if (!info?.description) {
return window.$message?.warning("缺少变更描述,请先在 [变更预识别] 里面输入变更描述");
}
footerRef.value?.setRegenerateLoading(true);
try {
const res = await aiTraining(info.description, (info.compare_rows ?? []).map((x: any) => ({ item: x.item, before_text: x.before_text, after_text: x.after_text })));
if (res?.training_text) {
form.value.content = res.training_text;
isAiGenerated.value = true;
window.$message?.success("变更培训内容已由 AI 生成,可直接修改");
} else {
window.$message?.warning("AI 未返回培训内容,请手动填写");
}
} catch (e: any) {
aiFail(e);
} finally {
footerRef.value?.setRegenerateLoading(false);
}
}
// 保存草稿
const saveDraft = () => {
emit('save');
}
// 提交
const submitConfirm = () => {
emit('submit', props.type);
}
// // 确认标签内容
const confirmTab = (tab:string, val:boolean) => {
emit('confirmTab', tab, val);
}
defineExpose({form, onRegenerate})
</script>
<template>
<div class="p-4">
<div class="space-y-4 scroll">
<div class="flex flex-wrap items-center gap-3 mb-3 min-h-[22px]">
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
<Icon icon="lucide:graduation-cap" class="size-16px text-violet-500" />
变更培训内容
</span>
<span v-if="isAiGenerated" class="inline-flex items-center gap-1 rounded-full border border-violet-200 bg-violet-100 px-2 py-0.5 text-xs font-medium text-violet-700">
✨ AI 生成 · 需人工确认
</span>
<span v-if="isAiGenerated" class="ml-auto text-xs text-slate-400">AI 生成内容均可点击修改自定义</span>
</div>
<!-- 培训内容 -->
<div class="border" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
<div class="flex flex-wrap items-center gap-2 bg-slate-100 px-3 py-2">
<span class="text-sm font-medium text-slate-700">培训内容</span>
<span class="text-[11px] text-slate-400">含培训对象、培训方式、变更内容、操作方式、潜在风险与应对措施,一个文本框自动分段换行</span>
<span class="ml-auto text-[11px] text-slate-400">内容支持直接修改</span>
</div>
<NInput v-model:value="form.content" type="textarea" :bordered="false" :autosize="{minRows: 4}" class="font-mono text-sm" placeholder="" />
</div>
</div>
</div>
<Footer
ref="footerRef"
:type="props.type"
:currentId="props.currentId"
:title="props.title"
:isAiOpen="props.isAiOpen"
:confirmed="props.confirmed"
:members="props.members"
@save="saveDraft"
@submit="submitConfirm"
@confirmTab="confirmTab"
@regenerate="onRegenerate"
/>
</template>
<style scoped lang="scss">
.scroll {
height: calc(100vh - 393px);
overflow-y: auto;
}
</style>