发起变更AI功能接线:变更预识别生成申请单、各标签页重新生成(申请表/培训内容/PSSR检查/验收评价)对接ai-server并适配新字段渲染;修复等级判定表AI评分重复点击总分累加问题
This commit is contained in:
@@ -1,74 +1,106 @@
|
||||
<!-- 变更培训内容 -->
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import Footer from './footer.vue';
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
const props = defineProps(['type','isAiOpen','title','currentId'])
|
||||
const emit = defineEmits(['save','submit','confirmTab']);
|
||||
// 是否是ai生成
|
||||
const isAiGenerated = ref<boolean>(false);
|
||||
const form = ref<{ content: string }>({
|
||||
content: ''
|
||||
});
|
||||
|
||||
// 保存草稿
|
||||
const saveDraft = () => {
|
||||
emit('save');
|
||||
}
|
||||
// 提交
|
||||
const submitConfirm = () => {
|
||||
emit('submit', props.type);
|
||||
}
|
||||
// // 确认标签内容
|
||||
const confirmTab = (tab:string, val:boolean) => {
|
||||
emit('confirmTab', tab, val);
|
||||
}
|
||||
|
||||
defineExpose({form})
|
||||
</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"
|
||||
@save="saveDraft"
|
||||
@submit="submitConfirm"
|
||||
@confirmTab="confirmTab"
|
||||
/>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.scroll {
|
||||
height: calc(100vh - 393px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
<!-- 变更培训内容 -->
|
||||
<script setup lang="ts">
|
||||
import { ref } 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'])
|
||||
const emit = defineEmits(['save','submit','confirmTab']);
|
||||
|
||||
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})
|
||||
</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"
|
||||
@save="saveDraft"
|
||||
@submit="submitConfirm"
|
||||
@confirmTab="confirmTab"
|
||||
@regenerate="onRegenerate"
|
||||
/>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.scroll {
|
||||
height: calc(100vh - 393px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user