feat(web): AI 文档查询卡片重构与单号判定统一
- documentClassification 抽出 isApplicationDocumentNo,统一兼容 AP-/APP- 旧格式与 A+8 新格式,aiDocumentQueryModel 复用 - aiDocumentQueryModel 文档卡片改为结构化字段布局(单据类型/金额/申请人/编号/操作),新增查询范围摘要区,渲染走 HTML 信任块 - AppShellRouteView/useAppShell/useRequests/detailAlerts/riskVisibility 等差旅详情模型适配单号判定 - 同步更新 ai-document-query-model/workbench-ai-mode-switch 测试,新增 document-classification 测试
This commit is contained in:
@@ -273,7 +273,27 @@ const sidebarCollapsed = ref(false)
|
||||
const sidebarCollapsedBeforeAiMode = ref(false)
|
||||
const mobileSidebarOpen = ref(false)
|
||||
const overviewDashboard = ref('finance')
|
||||
const workbenchMode = ref('traditional')
|
||||
const { companyProfile, currentUser, logout } = useSystemState()
|
||||
|
||||
function resolveDefaultWorkbenchMode(user) {
|
||||
return isPlatformAdminUser(user) ? 'traditional' : 'ai'
|
||||
}
|
||||
|
||||
function resolveWorkbenchUserKey(user = {}) {
|
||||
const roleCodes = Array.isArray(user?.roleCodes) ? user.roleCodes.join(',') : ''
|
||||
return [
|
||||
user?.id,
|
||||
user?.userId,
|
||||
user?.username,
|
||||
user?.account,
|
||||
user?.name,
|
||||
user?.role,
|
||||
roleCodes,
|
||||
user?.isAdmin ? 'admin' : 'user'
|
||||
].map((item) => String(item || '').trim()).join('|')
|
||||
}
|
||||
|
||||
const workbenchMode = ref(resolveDefaultWorkbenchMode(currentUser.value))
|
||||
const aiSidebarCommandSeq = ref(0)
|
||||
const aiSidebarCommand = ref({ seq: 0, type: '', payload: null })
|
||||
const aiActiveConversationId = ref('')
|
||||
@@ -343,7 +363,6 @@ const {
|
||||
topBarView
|
||||
} = useAppShell()
|
||||
|
||||
const { companyProfile, currentUser, logout } = useSystemState()
|
||||
const PRODUCT_DISPLAY_NAME = '易财费控'
|
||||
const ENTERPRISE_DISPLAY_NAME = '远光软件股份有限公司'
|
||||
const filteredNavItems = computed(() => filterNavItemsByAccess(navItems, currentUser.value))
|
||||
@@ -496,7 +515,14 @@ function handleLogout() {
|
||||
|
||||
watch(
|
||||
() => currentUser.value,
|
||||
(user) => {
|
||||
(user, previousUser) => {
|
||||
if (resolveWorkbenchUserKey(user) !== resolveWorkbenchUserKey(previousUser)) {
|
||||
const nextMode = resolveDefaultWorkbenchMode(user)
|
||||
workbenchMode.value = nextMode
|
||||
if (nextMode === 'ai') {
|
||||
sidebarCollapsed.value = false
|
||||
}
|
||||
}
|
||||
aiConversationHistory.value = loadAiWorkbenchConversationHistory(user || {})
|
||||
},
|
||||
{ immediate: true }
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
|
||||
const REQUIRED_APPLICATION_EXPENSE_TYPES = new Set(['travel', 'meal'])
|
||||
|
||||
const APPLICATION_TYPE_ALIASES = {
|
||||
@@ -302,8 +304,7 @@ export function isExpenseApplicationClaim(claim) {
|
||||
|
||||
return documentType === 'application'
|
||||
|| documentType === 'expense_application'
|
||||
|| claimNo.startsWith('AP-')
|
||||
|| claimNo.startsWith('APP-')
|
||||
|| isApplicationDocumentNo(claimNo)
|
||||
|| expenseType === 'application'
|
||||
|| expenseType.endsWith('_application')
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
|
||||
function normalizeText(value) {
|
||||
return String(value || '').trim()
|
||||
}
|
||||
@@ -22,7 +24,7 @@ function isApplicationDocumentRequest(requestModel) {
|
||||
|| requestModel?.document_type
|
||||
).toLowerCase()
|
||||
const claimNo = normalizeText(requestModel?.claimNo || requestModel?.claim_no || requestModel?.documentNo).toUpperCase()
|
||||
return documentType === 'application' || claimNo.startsWith('AP-') || claimNo.startsWith('APP-')
|
||||
return documentType === 'application' || isApplicationDocumentNo(claimNo)
|
||||
}
|
||||
|
||||
function isHotelExpenseItem(item) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
|
||||
function normalizeText(value) {
|
||||
return String(value || '').trim()
|
||||
}
|
||||
@@ -112,7 +114,7 @@ export function resolveRequestBusinessStage(request = {}) {
|
||||
|| request?.document_no
|
||||
|| request?.id
|
||||
).toUpperCase()
|
||||
if (claimNo.startsWith('AP-') || claimNo.startsWith('APP-')) {
|
||||
if (isApplicationDocumentNo(claimNo)) {
|
||||
return 'expense_application'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
|
||||
export const EXPENSE_TYPE_OPTIONS = [
|
||||
{ value: 'travel', label: '差旅费' },
|
||||
{ value: 'train_ticket', label: '火车票' },
|
||||
@@ -83,8 +85,7 @@ export function isApplicationDocumentRequest(request) {
|
||||
return (
|
||||
documentType === 'application'
|
||||
|| documentType === 'expense_application'
|
||||
|| claimNo.startsWith('AP-')
|
||||
|| claimNo.startsWith('APP-')
|
||||
|| isApplicationDocumentNo(claimNo)
|
||||
|| typeCode === 'application'
|
||||
|| typeCode.endsWith('_application')
|
||||
)
|
||||
|
||||
@@ -718,7 +718,7 @@ export function useTravelReimbursementFlow({
|
||||
function buildApplicationDuplicateDetail(payload) {
|
||||
const result = payload?.result && typeof payload.result === 'object' ? payload.result : {}
|
||||
const answer = String(result.answer || result.message || '').trim()
|
||||
const claimNo = answer.match(/AP-\d{14}-[A-HJ-NP-Z2-9]{8}/)?.[0] || ''
|
||||
const claimNo = answer.match(/A[A-HJ-NP-Z2-9]{8}|AP-\d{14}-[A-HJ-NP-Z2-9]{8}|APP-\d{8}-[A-Z0-9]{6}/)?.[0] || ''
|
||||
return claimNo
|
||||
? `已拦截重复申请,已有申请单:${claimNo}`
|
||||
: '已拦截重复申请,未创建新申请单'
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
collectReceiptFiles
|
||||
} from './travelReimbursementAttachmentModel.js'
|
||||
import { resolveAssistantScopeGuard } from '../../utils/assistantSessionScope.js'
|
||||
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
|
||||
import {
|
||||
APPLICATION_TRANSPORT_MODE_OPTIONS,
|
||||
applyApplicationBusinessTimeContext,
|
||||
@@ -148,8 +149,7 @@ function isApplicationClaimRecord(claim) {
|
||||
expenseType === 'application' ||
|
||||
expenseType === 'expense_application' ||
|
||||
expenseType.endsWith('_application') ||
|
||||
claimNo.startsWith('AP-') ||
|
||||
claimNo.startsWith('APP-') ||
|
||||
isApplicationDocumentNo(claimNo) ||
|
||||
Boolean(extractApplicationDetailFromClaim(claim))
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user