feat: 增强知识库索引与设置页面模块化拆分
扩展知识库索引任务和 RAG 检索支持增量入库和文档去重,优 化本体检测和规则匹配精度,前端设置页面拆分为 LLM、邮件 和 Hermes 员工同步子面板并重构样式,新增日志详情组件和 知识入库日志模型,补充单元测试覆盖。
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ATTACHMENT_ASSOCIATION_CONFIRM_HREF,
|
||||
buildAttachmentAssociationConfirmationMessage
|
||||
buildAttachmentAssociationConfirmationMessage,
|
||||
buildUnsavedDraftAttachmentConfirmationMessage
|
||||
} from './travelReimbursementAttachmentModel.js'
|
||||
|
||||
export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
@@ -103,10 +104,9 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
}
|
||||
|
||||
function buildConfirmedAssociationText(message) {
|
||||
return String(message?.text || '').replace(
|
||||
`[确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF})`,
|
||||
'已确认'
|
||||
)
|
||||
return String(message?.text || '')
|
||||
.replace(`[确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF})`, '已确认')
|
||||
.replace(`[确定](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF})`, '已确定')
|
||||
}
|
||||
|
||||
function resolveReviewPanelScope({
|
||||
@@ -159,6 +159,55 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
message.meta = ['已确认归集']
|
||||
persistSessionState()
|
||||
|
||||
if (pending.mode === 'save_then_associate') {
|
||||
const inheritedReviewContext = buildReviewFormContextFromPayload(
|
||||
activeReviewPayload.value,
|
||||
reviewInlineForm.value
|
||||
)
|
||||
const savePayload = await submitComposer({
|
||||
rawText: '请先把当前已识别的报销信息保存为草稿,随后继续归集本次上传的附件。',
|
||||
userText: '',
|
||||
files: [],
|
||||
skipUserMessage: true,
|
||||
pendingText: '正在先保存未保存单据...',
|
||||
systemGenerated: true,
|
||||
extraContext: {
|
||||
...runtime.extraContext,
|
||||
...inheritedReviewContext,
|
||||
review_action: 'save_draft'
|
||||
}
|
||||
})
|
||||
const savedClaimId = String(savePayload?.result?.draft_payload?.claim_id || draftClaimId.value || '').trim()
|
||||
const savedClaimNo = String(savePayload?.result?.draft_payload?.claim_no || '').trim()
|
||||
if (!savedClaimId) {
|
||||
toast('当前单据还没有保存成功,请稍后重试。')
|
||||
return savePayload
|
||||
}
|
||||
|
||||
return submitComposer({
|
||||
rawText: `确认将本次上传的 ${runtime.fileNames.length} 份票据归集到草稿 ${savedClaimNo || '当前草稿'}`,
|
||||
userText: `保存草稿并归集 ${runtime.fileNames.length} 份票据`,
|
||||
files: runtime.files,
|
||||
uploadDisposition: 'continue_existing',
|
||||
skipDraftAssociationPrompt: true,
|
||||
skipUserMessage: true,
|
||||
appendToCurrentFlow: true,
|
||||
systemGenerated: true,
|
||||
pendingText: savedClaimNo
|
||||
? `草稿 ${savedClaimNo} 已保存,正在识别并归集附件...`
|
||||
: '草稿已保存,正在识别并归集附件...',
|
||||
associationConfirmed: true,
|
||||
extraContext: {
|
||||
...runtime.extraContext,
|
||||
review_action: 'link_to_existing_draft',
|
||||
draft_claim_id: savedClaimId,
|
||||
selected_claim_id: savedClaimId,
|
||||
selected_claim_no: savedClaimNo,
|
||||
attachment_association_confirmed: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return submitComposer({
|
||||
rawText: `确认将本次上传的 ${runtime.fileNames.length} 份票据归集到草稿 ${runtime.claimNo || '当前草稿'}`,
|
||||
userText: `确认归集到草稿 ${runtime.claimNo || '当前草稿'}`,
|
||||
@@ -231,6 +280,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
|
||||
const rawText = resolveComposerSubmitText(options.rawText).trim()
|
||||
const systemGenerated = Boolean(options.systemGenerated)
|
||||
const appendToCurrentFlow = Boolean(options.appendToCurrentFlow)
|
||||
const normalizedFiles = isKnowledgeSession.value ? [] : Array.from(options.files ?? attachedFiles.value)
|
||||
const fileMergeResult = mergeFilesWithLimit([], normalizedFiles, MAX_ATTACHMENTS)
|
||||
const files = fileMergeResult.files
|
||||
@@ -308,6 +358,47 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
? `新上传 ${fileNames.length} 份票据,请单独建立报销单。`
|
||||
: `我上传了 ${fileNames.length} 份票据,请帮我识别并整理报销建议。`)
|
||||
|
||||
const hasUnsavedReviewDraft = Boolean(
|
||||
!isKnowledgeSession.value &&
|
||||
files.length &&
|
||||
activeReviewPayload.value &&
|
||||
!String(draftClaimId.value || '').trim() &&
|
||||
!detailScopedClaimId &&
|
||||
!resolvedUploadDisposition &&
|
||||
!options.skipDraftAssociationPrompt &&
|
||||
!reviewAction
|
||||
)
|
||||
if (hasUnsavedReviewDraft) {
|
||||
const associationId = createPendingAttachmentAssociationId()
|
||||
pendingAttachmentAssociations.set(associationId, {
|
||||
files,
|
||||
fileNames,
|
||||
filePreviews: buildComposerFilePreviews(files),
|
||||
extraContext
|
||||
})
|
||||
resetFlowRun()
|
||||
if (!options.skipUserMessage) {
|
||||
messages.value.push(createMessage('user', userText, fileNames))
|
||||
}
|
||||
messages.value.push(createMessage(
|
||||
'assistant',
|
||||
buildUnsavedDraftAttachmentConfirmationMessage({ fileNames }),
|
||||
[],
|
||||
{
|
||||
meta: ['等待确认保存并归集'],
|
||||
pendingAttachmentAssociation: {
|
||||
id: associationId,
|
||||
mode: 'save_then_associate',
|
||||
status: 'pending',
|
||||
fileNames
|
||||
}
|
||||
}
|
||||
))
|
||||
nextTick(scrollToBottom)
|
||||
persistSessionState()
|
||||
return null
|
||||
}
|
||||
|
||||
if (
|
||||
!isKnowledgeSession.value &&
|
||||
files.length &&
|
||||
@@ -363,7 +454,11 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
resetFlowRun()
|
||||
if (!appendToCurrentFlow) {
|
||||
resetFlowRun()
|
||||
} else {
|
||||
clearFlowSimulationTimers()
|
||||
}
|
||||
if (rawText && !reviewAction) {
|
||||
startFlowStep('intent', '正在识别业务意图...')
|
||||
if (waitForExpenseIntentConfirmation) {
|
||||
|
||||
Reference in New Issue
Block a user