- aiConversationHtmlRenderer 识别单据记录类表格并渲染为卡片列表,新增删除申请单详情的禁用占位链接 - aiWorkbenchConversationStore 增加草稿删除后会话链接失效处理,避免点击已删除单据跳转 - aiApplicationPreviewActions 调整提交/草稿调用路径,PersonalWorkbenchAiMode 接入新的会话存储与渲染 - ConfirmDialog/TravelRequestDeleteDialog/useAppShell/AppShellRouteView 配套适配,同步更新相关前端测试
139 lines
4.8 KiB
JavaScript
139 lines
4.8 KiB
JavaScript
import { apiRequest } from './api.js'
|
||
import {
|
||
buildApplicationPreviewRows,
|
||
buildApplicationPreviewSubmitText,
|
||
normalizeApplicationPreview
|
||
} from '../utils/expenseApplicationPreview.js'
|
||
|
||
export const AI_APPLICATION_ACTION_SAVE_DRAFT = 'ai_application_save_draft'
|
||
export const AI_APPLICATION_ACTION_SUBMIT = 'ai_application_submit'
|
||
|
||
function normalizeText(value) {
|
||
return String(value || '').trim()
|
||
}
|
||
|
||
function resolveUserValue(user = {}, ...keys) {
|
||
for (const key of keys) {
|
||
const value = normalizeText(user?.[key])
|
||
if (value) return value
|
||
}
|
||
return ''
|
||
}
|
||
|
||
function buildClientTimeContext() {
|
||
const now = new Date()
|
||
const locale =
|
||
typeof navigator !== 'undefined' && typeof navigator.language === 'string'
|
||
? navigator.language
|
||
: 'zh-CN'
|
||
|
||
return {
|
||
client_now_iso: now.toISOString(),
|
||
client_timezone_offset_minutes: now.getTimezoneOffset(),
|
||
client_locale: locale
|
||
}
|
||
}
|
||
|
||
function buildApplicationPreviewSaveText(preview = {}) {
|
||
const rows = buildApplicationPreviewRows(preview)
|
||
return [
|
||
'费用申请保存草稿',
|
||
...rows.map((row) => `${row.label}:${row.value}`),
|
||
'',
|
||
'保存草稿'
|
||
].join('\n')
|
||
}
|
||
|
||
export function buildAiApplicationPreviewActionText(actionType, preview = {}) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
return actionType === AI_APPLICATION_ACTION_SUBMIT
|
||
? buildApplicationPreviewSubmitText(normalized)
|
||
: buildApplicationPreviewSaveText(normalized)
|
||
}
|
||
|
||
export function buildAiApplicationPreviewActionPayload({
|
||
actionType,
|
||
applicationPreview,
|
||
currentUser = {},
|
||
conversationId = '',
|
||
draftPayload = null
|
||
} = {}) {
|
||
const normalizedPreview = normalizeApplicationPreview(applicationPreview || {})
|
||
const message = buildAiApplicationPreviewActionText(actionType, normalizedPreview)
|
||
const username = resolveUserValue(currentUser, 'username', 'account', 'email', 'name') || 'anonymous'
|
||
const name = resolveUserValue(currentUser, 'name', 'username')
|
||
const employeeNo = resolveUserValue(currentUser, 'employeeNo', 'employee_no')
|
||
const managerName = resolveUserValue(currentUser, 'managerName', 'manager_name', 'directManagerName', 'direct_manager_name')
|
||
const departmentName = resolveUserValue(currentUser, 'departmentName', 'department_name', 'department')
|
||
const position = resolveUserValue(currentUser, 'position', 'employeePosition', 'employee_position')
|
||
const grade = resolveUserValue(currentUser, 'grade', 'employeeGrade', 'employee_grade')
|
||
const roleCodes = Array.isArray(currentUser.roleCodes)
|
||
? currentUser.roleCodes.map((item) => normalizeText(item)).filter(Boolean)
|
||
: []
|
||
const draftClaimId = normalizeText(draftPayload?.claim_id || draftPayload?.claimId)
|
||
const isSubmit = actionType === AI_APPLICATION_ACTION_SUBMIT
|
||
|
||
return {
|
||
source: 'user_message',
|
||
user_id: username,
|
||
conversation_id: normalizeText(conversationId) || null,
|
||
message,
|
||
context_json: {
|
||
role_codes: roleCodes,
|
||
is_admin: Boolean(currentUser.isAdmin),
|
||
name,
|
||
role: resolveUserValue(currentUser, 'role'),
|
||
department: departmentName,
|
||
department_name: departmentName,
|
||
position,
|
||
employee_position: position,
|
||
employeePosition: position,
|
||
grade,
|
||
employee_grade: grade,
|
||
employeeGrade: grade,
|
||
employee_no: employeeNo,
|
||
employeeNo,
|
||
manager_name: managerName,
|
||
managerName,
|
||
direct_manager_name: managerName,
|
||
directManagerName: managerName,
|
||
cost_center: resolveUserValue(currentUser, 'costCenter', 'cost_center'),
|
||
finance_owner_name: resolveUserValue(currentUser, 'financeOwnerName', 'finance_owner_name'),
|
||
...buildClientTimeContext(),
|
||
session_type: 'application',
|
||
entry_source: 'workbench_ai_inline',
|
||
source: 'workbench',
|
||
document_type: 'expense_application',
|
||
application_stage: 'expense_application',
|
||
user_input_text: message,
|
||
application_preview: normalizedPreview,
|
||
...(isSubmit
|
||
? {}
|
||
: {
|
||
application_action: 'save_draft',
|
||
application_save_mode: true
|
||
}),
|
||
...(draftClaimId
|
||
? {
|
||
application_edit_claim_id: draftClaimId,
|
||
draft_claim_id: draftClaimId,
|
||
selected_claim_id: draftClaimId,
|
||
application_edit_mode: true
|
||
}
|
||
: {})
|
||
}
|
||
}
|
||
}
|
||
|
||
export function runAiApplicationPreviewAction(params = {}, options = {}) {
|
||
const payload = buildAiApplicationPreviewActionPayload(params)
|
||
const isSubmit = params.actionType === AI_APPLICATION_ACTION_SUBMIT
|
||
return apiRequest('/reimbursements/application-preview-action', {
|
||
method: 'POST',
|
||
body: JSON.stringify(payload),
|
||
timeoutMs: isSubmit ? 45000 : 30000,
|
||
timeoutMessage: isSubmit ? '申请提交处理超时,请稍后重试。' : '申请草稿保存超时,请稍后重试。',
|
||
...options
|
||
})
|
||
}
|