import { nextTick, onBeforeUnmount, onMounted, watch } from 'vue' import { buildLocalApplicationPreviewMessage, normalizeApplicationPreview } from '../../utils/expenseApplicationPreview.js' import { MAX_ATTACHMENTS, VISIBLE_ATTACHMENT_CHIPS, buildReviewFilePreviewsFromReviewPayload } from './travelReimbursementAttachmentModel.js' import { SESSION_TYPE_EXPENSE, createMessage, buildWelcomeInsight } from './travelReimbursementConversationModel.js' export function useTravelReimbursementCreateViewLifecycle({ activeFlowSteps, activeReviewPanelScope, activeReviewPayload, activeSessionType, adjustComposerTextareaHeight, attachedFiles, clearExpenseSessionForDeletedClaim, clearStewardThinkingTimers, closeAfterBusy, composerDraft, composerFilesExpanded, composerUploadIntent, conversationId, currentInsight, currentUser, draftClaimId, guidedFlowState, handleComposerDatePickerOutside, hasInsightPanelContent, insightPanelCollapsed, linkedRequest, maybeFinalizeDeferredClose, mergeFilesWithLimit, messages, persistSessionState, props, rememberFilePreviews, resetReviewDrawerFromPayload, resolveActiveClaimId, restorePersistedDraftAttachmentPreviews, reviewActionBusy, reviewDocumentDrawerAvailable, reviewDrawerMode, reviewFilePreviews, reviewFlowDrawerAvailable, reviewRiskDrawerAvailable, scrollToBottom, startFlowTick, stewardState, stopAttachmentRuntime, stopFlowRuntime, submitComposer, submitting, sessionSwitchBusy, toast, workbenchVisible, REVIEW_DRAWER_MODE_DOCUMENTS, REVIEW_DRAWER_MODE_FLOW, REVIEW_DRAWER_MODE_REVIEW, REVIEW_DRAWER_MODE_RISK, SESSION_TYPE_EXPENSE: sessionTypeExpense = SESSION_TYPE_EXPENSE }) { watch( () => [activeReviewPayload.value, activeReviewPanelScope.value], ([payload]) => { rememberFilePreviews(buildReviewFilePreviewsFromReviewPayload(payload)) const shouldKeepFlowDrawer = reviewDrawerMode.value === REVIEW_DRAWER_MODE_FLOW && activeFlowSteps.value.length > 0 resetReviewDrawerFromPayload(payload) if (shouldKeepFlowDrawer) { reviewDrawerMode.value = REVIEW_DRAWER_MODE_FLOW } }, { immediate: true } ) watch( () => hasInsightPanelContent.value, (available) => { if (!available) { insightPanelCollapsed.value = false } } ) watch( () => reviewDocumentDrawerAvailable.value, (available) => { if (!available && reviewDrawerMode.value === REVIEW_DRAWER_MODE_DOCUMENTS) { reviewDrawerMode.value = REVIEW_DRAWER_MODE_REVIEW } } ) watch( () => reviewRiskDrawerAvailable.value, (available) => { if (!available && reviewDrawerMode.value === REVIEW_DRAWER_MODE_RISK) { reviewDrawerMode.value = REVIEW_DRAWER_MODE_REVIEW } } ) watch( () => reviewFlowDrawerAvailable.value, (available) => { if (!available && reviewDrawerMode.value === REVIEW_DRAWER_MODE_FLOW) { reviewDrawerMode.value = REVIEW_DRAWER_MODE_REVIEW } } ) watch( () => [activeSessionType.value, activeFlowSteps.value.length], ([, activeCount], [, previousActiveCount] = []) => { if (activeCount <= 0 || previousActiveCount > 0) { return } reviewDrawerMode.value = REVIEW_DRAWER_MODE_FLOW insightPanelCollapsed.value = false } ) watch( () => composerDraft.value, () => { nextTick(adjustComposerTextareaHeight) } ) watch( () => ({ sessionType: activeSessionType.value, conversationId: conversationId.value, stewardState: stewardState.value, draftClaimId: draftClaimId.value, messages: messages.value, currentInsight: currentInsight.value, reviewFilePreviews: reviewFilePreviews.value, composerDraft: composerDraft.value, composerUploadIntent: composerUploadIntent.value, guidedFlowState: guidedFlowState.value, insightPanelCollapsed: insightPanelCollapsed.value }), () => { persistSessionState() }, { deep: true } ) watch( () => [activeSessionType.value, resolveActiveClaimId()], ([sessionType, claimId]) => { if (sessionType !== sessionTypeExpense || !claimId) { return } void restorePersistedDraftAttachmentPreviews(claimId) }, { immediate: true } ) watch( () => props.invalidatedDraftClaimId, (claimId) => { clearExpenseSessionForDeletedClaim(claimId) }, { immediate: true } ) watch( () => workbenchVisible.value, (visible) => { if (visible) { scrollToBottom() } else { maybeFinalizeDeferredClose() } } ) watch( () => [submitting.value, reviewActionBusy.value, sessionSwitchBusy.value, workbenchVisible.value], () => { maybeFinalizeDeferredClose() } ) watch( () => props.reopenToken, (token, previousToken) => { if (token === previousToken) { return } closeAfterBusy.value = false workbenchVisible.value = true nextTick(() => { adjustComposerTextareaHeight() scrollToBottom() }) } ) onMounted(() => { document.addEventListener('click', handleComposerDatePickerOutside) startFlowTick() nextTick(() => { workbenchVisible.value = true nextTick(() => { adjustComposerTextareaHeight() scrollToBottom() }) }) currentInsight.value = currentInsight.value || buildWelcomeInsight(props.entrySource, linkedRequest.value, activeSessionType.value, currentUser.value) if (props.initialApplicationPreview && typeof props.initialApplicationPreview === 'object') { const applicationPreview = normalizeApplicationPreview(props.initialApplicationPreview) const draftPayload = props.initialDraftPayload && typeof props.initialDraftPayload === 'object' ? props.initialDraftPayload : null messages.value.push(createMessage('assistant', buildLocalApplicationPreviewMessage(applicationPreview), [], { meta: ['修改申请'], applicationPreview, draftPayload })) persistSessionState() } if (props.initialPrompt?.trim() || props.initialFiles.length) { const initialMerge = mergeFilesWithLimit([], Array.from(props.initialFiles), MAX_ATTACHMENTS) composerDraft.value = props.initialPrompt.trim() attachedFiles.value = initialMerge.files composerFilesExpanded.value = initialMerge.files.length > VISIBLE_ATTACHMENT_CHIPS if (initialMerge.overflowCount > 0) { toast(`一次最多上传 ${MAX_ATTACHMENTS} 份附件,已保留前 ${MAX_ATTACHMENTS} 份。`) } nextTick(() => { adjustComposerTextareaHeight() }) if (props.initialPromptAutoSubmit !== false) { submitComposer() } } }) onBeforeUnmount(() => { document.removeEventListener('click', handleComposerDatePickerOutside) clearStewardThinkingTimers() stopFlowRuntime() stopAttachmentRuntime() }) }