refactor(login): move match-route logic to dedicated service and fix import
- 提取登录回跳、产品对比的路由匹配逻辑至独立的 match-route.uts 服务 - 修复登录页面导入对比服务的错误,改为导入新的 match-route 模块 - 保持原有的路由参数校验和跳转逻辑不变,仅重构代码结构
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { getSession, requestJson } from '@/services/api.uts'
|
||||
import { assessmentApiPayload, draftText } from '@/services/assessment.uts'
|
||||
import { assessmentRequestKey } from '@/services/assessment-flow.uts'
|
||||
import { contributionLabels, contributionCodes, contributionLabel } from '@/services/contribution.uts'
|
||||
import { yuanToWan } from '@/services/money.uts'
|
||||
import { FinancingGradeView, financingGradeFrom } from '@/packages/finance/services/financing-grade.uts'
|
||||
|
||||
export type AssessmentRecord = { id: string, type: string, status: string, statusLabel: string, message: string, city: string, submittedAt: string, taskId: string, stage: string, canRetry: boolean, revisionId: string, revisionNo: number, hasReport: boolean, publishedRevisionId: string }
|
||||
export type AssessmentPage = { items: AssessmentRecord[], hasMore: boolean, nextCursor: string }
|
||||
@@ -44,10 +46,48 @@ export async function retryAssessment(id: string, requestId: string): Promise<vo
|
||||
}
|
||||
|
||||
export type ReportMatching = { status: string, snapshotId: string, ruleVersion: string, orderingVersion: string, eligible: string, ineligible: string, unknown: string }
|
||||
export type AnalysisReport = { revisionId: string, revisionNo: number, isPreviousResult: boolean, currentStatus: string, version: number, generatedAt: string, completenessPercent: number | null, matching: ReportMatching, summary: string, facts: AssessmentField[], observations: string[], suggestions: string[], suggestionSummaries: string[], dataGaps: string[], disclaimer: string, matchingMessage: string, modelCode: string, demand: AssessmentField[], completenessText: string, completenessItems: AssessmentField[], readinessLabel: string, readinessBasis: string[], warnings: string[] }
|
||||
export type AnalysisReport = { revisionId: string, revisionNo: number, isPreviousResult: boolean, currentStatus: string, version: number, generatedAt: string, completenessPercent: number | null, matching: ReportMatching, summary: string, facts: AssessmentField[], observations: string[], suggestions: string[], priorityItems: string[], dataGaps: string[], disclaimer: string, matchingMessage: string, modelCode: string, demand: AssessmentField[], completenessText: string, completenessItems: AssessmentField[], readinessLabel: string, readinessBasis: string[], warnings: string[], financingGrade: FinancingGradeView }
|
||||
|
||||
function reportPriorityItems(improvements: UTSJSONObject[], fields: UTSJSONObject[], basis: UTSJSONObject[]): string[] {
|
||||
const items: string[] = []; const covered: string[] = []
|
||||
// 仅用冻结证据中的明确问题标识合并;普通事实引用不表示同一个问题。
|
||||
improvements.forEach((item: UTSJSONObject) => {
|
||||
const text = draftText(item, 'text').trim()
|
||||
if (text.length == 0) return
|
||||
const keys: string[] = []
|
||||
const refs = item['evidenceRefs'] as string[]
|
||||
refs.forEach((ref: string) => {
|
||||
let related: string[] = []
|
||||
if (ref.startsWith('fact:')) {
|
||||
const field = fields.find((entry: UTSJSONObject): boolean => draftText(entry, 'fieldKey') == ref.slice(5))
|
||||
if (field != null && ['missing', 'invalid'].includes(draftText(field, 'state'))) related = [draftText(field, 'state') + ':' + ref.slice(5)]
|
||||
} else if (ref.startsWith('readiness:')) {
|
||||
const entry = basis.find((value: UTSJSONObject): boolean => draftText(value, 'basisId') == ref.slice(10))
|
||||
if (entry != null && ['MISSING_FIELD', 'INVALID_FIELD'].includes(draftText(entry, 'code'))) {
|
||||
const kind = draftText(entry, 'code') == 'MISSING_FIELD' ? 'missing' : 'invalid'
|
||||
related = (entry['fieldRefs'] as string[]).map((key: string): string => kind + ':' + key)
|
||||
} else if (entry != null && (entry['issueRefs'] as string[]).length > 0) related = [ref]
|
||||
}
|
||||
related.forEach((key: string) => { if (!keys.includes(key)) keys.push(key) })
|
||||
})
|
||||
if (!items.includes(text) && (keys.length == 0 || keys.some((key: string): boolean => !covered.includes(key)))) items.push(text)
|
||||
keys.forEach((key: string) => { if (!covered.includes(key)) covered.push(key) })
|
||||
})
|
||||
fields.forEach((field: UTSJSONObject) => {
|
||||
const state = draftText(field, 'state'); const key = state + ':' + draftText(field, 'fieldKey')
|
||||
const label = draftText(field, 'label').trim()
|
||||
if (!['missing', 'invalid'].includes(state) || covered.includes(key) || label.length == 0) return
|
||||
const text = (state == 'missing' ? '补充' : '核实') + label
|
||||
if (!items.includes(text)) items.push(text)
|
||||
covered.push(key)
|
||||
})
|
||||
return items
|
||||
}
|
||||
|
||||
export async function fetchAnalysisReport(id: string, revisionId: string = ''): Promise<AnalysisReport> {
|
||||
const result = await requestJson('/assessments/' + encodeURIComponent(id) + '/report', 'GET', revisionParams(revisionId))
|
||||
const version = result['resultVersion'] as number
|
||||
const financingGrade = financingGradeFrom(version == 2 ? result['financingGrade'] as UTSJSONObject | null : null)
|
||||
if (revisionId.length > 0 && result.getString('revisionId') != revisionId) throw new Error('报告版本不一致,请重新选择。')
|
||||
if (result['assessmentId'] != id || (version != 1 && version != 2) || (version == 1 && result['reportType'] != 'self_reported_analysis') || (version == 2 && result['reportType'] != 'financing_needs_analysis')) throw new Error('报告格式不支持')
|
||||
const date = new Date(draftText(result, 'generatedAt'))
|
||||
@@ -74,6 +114,7 @@ export async function fetchAnalysisReport(id: string, revisionId: string = ''):
|
||||
if (fact['value'] != null && fact['unit'] == 'month') value += ' 个月'
|
||||
if (fact['state'] == 'invalid') value = '格式需核实'
|
||||
const enumLabels: UTSJSONObject = { six_months_plus: '连续缴纳6个月以上', under_six_months: '缴纳不足6个月', none: '无' }
|
||||
if (['socialSecurity', 'housingFund'].includes(draftText(fact, 'fieldKey'))) value = contributionLabel(value)
|
||||
if (enumLabels[value] != null) value = enumLabels[value] as string
|
||||
// v2的需求在独立区块展示,避免用途代码和同一金额重复出现。
|
||||
if (version == 2 && ['requestedAmountYuan', 'requestedTermMonths', 'purposeCode'].includes(draftText(fact, 'fieldKey'))) return
|
||||
@@ -108,17 +149,18 @@ export async function fetchAnalysisReport(id: string, revisionId: string = ''):
|
||||
}).filter((label: string): boolean => label.length > 0)
|
||||
return draftText(item, 'text') + (labels.length > 0 ? '(依据:' + labels.join(';') + ')' : '')
|
||||
})
|
||||
return { revisionId: draftText(result, 'revisionId'), revisionNo: result.getNumber('revisionNo') ?? 1, isPreviousResult: result.getBoolean('isPreviousResult') ?? false, currentStatus: draftText(result, 'currentStatus'), version, generatedAt, completenessPercent, matching, summary: draftText(result, 'summary'), facts, observations: explain('strengths'), suggestions: explain('improvements'), suggestionSummaries: (result['improvements'] as UTSJSONObject[]).map((item: UTSJSONObject): string => draftText(item, 'text')), dataGaps: explain('riskWarnings'),
|
||||
return { revisionId: draftText(result, 'revisionId'), revisionNo: result.getNumber('revisionNo') ?? 1, isPreviousResult: result.getBoolean('isPreviousResult') ?? false, currentStatus: draftText(result, 'currentStatus'), version, generatedAt, completenessPercent, matching, summary: draftText(result, 'summary'), facts, observations: explain('strengths'), suggestions: explain('improvements'), priorityItems: reportPriorityItems(result['improvements'] as UTSJSONObject[], items, basis), dataGaps: explain('riskWarnings'),
|
||||
// 新报告展示服务端冻结结果的统计;旧报告无此字段时保留原提示,不重算历史。
|
||||
disclaimer: draftText(result, 'disclaimer'), matchingMessage: draftText(result, 'matchingMessage').length > 0 ? draftText(result, 'matchingMessage') : '产品资料及匹配规则尚未就绪,本报告未执行产品匹配。', modelCode: draftText(result, 'modelCode'),
|
||||
demand, completenessText, completenessItems, readinessLabel: readiness['status'] == 'evaluated' ? draftText(readiness, 'label') : '未评定',
|
||||
demand, completenessText, completenessItems, financingGrade, readinessLabel: readiness['status'] == 'evaluated' ? draftText(readiness, 'label') : '未评定',
|
||||
readinessBasis: basis.map((item: UTSJSONObject): string => draftText(item, 'message')), warnings: result['systemWarnings'] as string[] }
|
||||
}
|
||||
const observations = (result['observations'] as UTSJSONObject[]).map((item: UTSJSONObject): string => {
|
||||
const fact = rawFacts.find((entry: UTSJSONObject): boolean => entry['id'] == item['factId'])
|
||||
return (fact == null ? '' : draftText(fact, 'label') + ':') + draftText(item, 'text')
|
||||
})
|
||||
return { revisionId: draftText(result, 'revisionId'), revisionNo: result.getNumber('revisionNo') ?? 1, isPreviousResult: result.getBoolean('isPreviousResult') ?? false, currentStatus: draftText(result, 'currentStatus'), version, generatedAt, completenessPercent: null, matching, summary: draftText(result, 'summary'), facts, observations, suggestions: result['suggestions'] as string[], suggestionSummaries: result['suggestions'] as string[], dataGaps: result['dataGaps'] as string[], disclaimer: draftText(result, 'disclaimer'), matchingMessage: draftText(result, 'matchingMessage'), modelCode: draftText(result, 'modelCode'), demand: [], completenessText: '旧版报告未计算资料完整度', completenessItems: [], readinessLabel: '未评定', readinessBasis: [], warnings: [] }
|
||||
const legacySuggestions = (result['suggestions'] as string[]).map((text: string): string => text.trim())
|
||||
return { revisionId: draftText(result, 'revisionId'), revisionNo: result.getNumber('revisionNo') ?? 1, isPreviousResult: result.getBoolean('isPreviousResult') ?? false, currentStatus: draftText(result, 'currentStatus'), version, generatedAt, completenessPercent: null, matching, summary: draftText(result, 'summary'), facts, observations, suggestions: result['suggestions'] as string[], priorityItems: legacySuggestions.filter((text: string, index: number): boolean => text.length > 0 && legacySuggestions.indexOf(text) == index), dataGaps: result['dataGaps'] as string[], disclaimer: draftText(result, 'disclaimer'), matchingMessage: draftText(result, 'matchingMessage'), modelCode: draftText(result, 'modelCode'), demand: [], completenessText: '旧版报告未计算资料完整度', completenessItems: [], readinessLabel: '未评定', readinessBasis: [], warnings: [], financingGrade }
|
||||
}
|
||||
|
||||
function enumValue(value: string, labels: string[], codes: string[]): string | null {
|
||||
@@ -140,7 +182,7 @@ export async function createAssessment(payload: UTSJSONObject): Promise<string>
|
||||
const values = assessmentApiPayload(payload)
|
||||
const form = new UTSJSONObject()
|
||||
const textKeys = ['name', 'idCard', 'phone', 'city', 'occupation', 'company', 'enterpriseName', 'businessCode']
|
||||
const moneyKeys = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit']
|
||||
const moneyKeys = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit', 'socialSecurityBase', 'housingFundBase']
|
||||
textKeys.concat(moneyKeys).forEach((key: string) => { const value = draftText(values, key).trim(); form[key] = value.length == 0 ? null : value })
|
||||
if (form['idCard'] != null) form['idCard'] = (form['idCard'] as string).toUpperCase()
|
||||
if (form['businessCode'] != null) form['businessCode'] = (form['businessCode'] as string).toUpperCase()
|
||||
@@ -152,7 +194,7 @@ export async function createAssessment(payload: UTSJSONObject): Promise<string>
|
||||
})
|
||||
form['maritalStatus'] = enumValue(draftText(values, 'maritalStatus'), ['已婚', '未婚', '离异', '丧偶'], ['married', 'single', 'divorced', 'widowed'])
|
||||
const socialKeys = ['socialSecurity', 'housingFund']
|
||||
socialKeys.forEach((key: string) => { form[key] = enumValue(draftText(values, key), ['连续缴纳 6 个月以上', '缴纳不足 6 个月', '未缴纳'], ['six_months_plus', 'under_six_months', 'none']) })
|
||||
socialKeys.forEach((key: string) => { form[key] = enumValue(draftText(values, key), contributionLabels, contributionCodes) })
|
||||
const ownershipKeys = ['house', 'car']
|
||||
ownershipKeys.forEach((key: string) => { form[key] = enumValue(draftText(values, key), ['有', '无'], ['yes', 'no']) })
|
||||
const cityNames = ['深圳市', '广州市', '北京市', '上海市', '杭州市']
|
||||
@@ -221,20 +263,21 @@ export async function fetchAssessmentDetail(id: string, revisionId: string = '')
|
||||
fields.push(field); sections[section].fields.push(field)
|
||||
if (provided) sections[section].provided++
|
||||
}
|
||||
const keys = ['name', 'phone', 'city', 'idCard', 'enterpriseName', 'businessCode', 'occupation', 'company', 'operatingMonths', 'monthlyIncome', 'annualRevenue', 'creditLoanCount', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardCount', 'creditCardTotalLimit', 'creditCardUsedLimit', 'maritalStatus', 'socialSecurity', 'housingFund', 'house', 'car']
|
||||
const labels = ['姓名 / 联系人', '手机号', '城市', '身份证号', '企业名称', '信用代码', '职业 / 行业', '工作单位', '经营月数', '月收入', '年营收', '信用贷款笔数', '欠款总余额', '贷款月还款金额', '信用卡张数', '信用卡总额度', '信用卡已用额度', '婚姻状况', '社保缴纳', '公积金缴纳', '是否有房', '是否有车']
|
||||
const moneyKeys = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit']
|
||||
const keys = ['name', 'phone', 'city', 'idCard', 'enterpriseName', 'businessCode', 'occupation', 'company', 'operatingMonths', 'monthlyIncome', 'annualRevenue', 'creditLoanCount', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardCount', 'creditCardTotalLimit', 'creditCardUsedLimit', 'maritalStatus', 'socialSecurity', 'housingFund', 'house', 'car', 'socialSecurityBase', 'housingFundBase']
|
||||
const labels = ['姓名 / 联系人', '手机号', '城市', '身份证号', '企业名称', '信用代码', '职业 / 行业', '工作单位', '经营月数', '月收入', '年营收', '信用贷款笔数', '欠款总余额', '贷款月还款金额', '信用卡张数', '信用卡总额度', '信用卡已用额度', '婚姻状况', '社保缴纳', '公积金缴纳', '是否有房', '是否有车', '社保月缴存基数', '公积金月缴存基数']
|
||||
const moneyKeys = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit', 'socialSecurityBase', 'housingFundBase']
|
||||
const enumLabels: UTSJSONObject = { married: '已婚', single: '未婚', divorced: '离异', widowed: '丧偶', yes: '有', no: '无', six_months_plus: '连续缴纳6个月以上', under_six_months: '缴纳不足6个月', none: '未缴纳' }
|
||||
keys.forEach((key: string, index: number) => {
|
||||
const raw = form[key]
|
||||
let value = raw == null ? '未填写' : (typeof raw == 'number' ? (raw as number).toString() : raw as string)
|
||||
if (raw != null && moneyKeys.includes(key)) value = yuanToWan(value) + ' 万元'
|
||||
if (raw != null && key == 'operatingMonths') value += ' 个月'
|
||||
if (['socialSecurity', 'housingFund'].includes(key)) value = contributionLabel(value)
|
||||
if (['maritalStatus', 'socialSecurity', 'housingFund', 'house', 'car'].includes(key) && enumLabels[value] != null) value = enumLabels[value] as string
|
||||
const personalOnly = ['idCard', 'company', 'monthlyIncome', 'maritalStatus', 'socialSecurity', 'housingFund']
|
||||
const personalOnly = ['idCard', 'company', 'monthlyIncome', 'maritalStatus', 'socialSecurity', 'housingFund', 'socialSecurityBase', 'housingFundBase']
|
||||
const enterpriseOnly = ['enterpriseName', 'businessCode', 'operatingMonths', 'annualRevenue']
|
||||
if ((result['type'] == 'enterprise' && personalOnly.includes(key)) || (result['type'] == 'personal' && enterpriseOnly.includes(key))) return
|
||||
const incomeKeys = ['occupation', 'company', 'operatingMonths', 'monthlyIncome', 'annualRevenue', 'socialSecurity', 'housingFund']
|
||||
const incomeKeys = ['occupation', 'company', 'operatingMonths', 'monthlyIncome', 'annualRevenue', 'socialSecurity', 'housingFund', 'socialSecurityBase', 'housingFundBase']
|
||||
const assetKeys = ['creditLoanCount', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardCount', 'creditCardTotalLimit', 'creditCardUsedLimit', 'house', 'car']
|
||||
// “无”及数值0都是已填写,不能用真值判断遗漏零负债、零经营月数。
|
||||
addField(incomeKeys.includes(key) ? 1 : (assetKeys.includes(key) ? 2 : 0), labels[index], value, raw != null && value.length > 0)
|
||||
@@ -255,14 +298,15 @@ export async function fetchAssessmentEdit(id: string): Promise<UTSJSONObject> {
|
||||
const form = result['form'] as UTSJSONObject | null
|
||||
if (form == null || Array.isArray(form) || typeof form != 'object' || result.getString('moneyUnit') != 'yuan') throw new Error('修改资料不完整,请返回档案重新读取。')
|
||||
const payload: UTSJSONObject = { type: result['type'], editAssessmentId: id, baseRevisionId: result['revisionId'], step: 0 }
|
||||
const money = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit']
|
||||
const money = ['monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit', 'socialSecurityBase', 'housingFundBase']
|
||||
const labels: UTSJSONObject = { married: '已婚', single: '未婚', divorced: '离异', widowed: '丧偶', yes: '有', no: '无', six_months_plus: '连续缴纳 6 个月以上', under_six_months: '缴纳不足 6 个月', none: '未缴纳' }
|
||||
const enums = ['maritalStatus', 'house', 'car', 'socialSecurity', 'housingFund']
|
||||
const keys = ['name', 'idCard', 'phone', 'city', 'occupation', 'company', 'enterpriseName', 'businessCode', 'monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit', 'creditLoanCount', 'creditCardCount', 'operatingMonths', 'maritalStatus', 'house', 'car', 'socialSecurity', 'housingFund']
|
||||
const keys = ['name', 'idCard', 'phone', 'city', 'occupation', 'company', 'enterpriseName', 'businessCode', 'monthlyIncome', 'annualRevenue', 'totalDebtBalance', 'monthlyLoanPayment', 'creditCardTotalLimit', 'creditCardUsedLimit', 'creditLoanCount', 'creditCardCount', 'operatingMonths', 'maritalStatus', 'house', 'car', 'socialSecurity', 'housingFund', 'socialSecurityBase', 'housingFundBase']
|
||||
keys.forEach((key: string) => {
|
||||
const raw = form[key]
|
||||
let value = raw == null ? '' : (typeof raw == 'number' ? (raw as number).toString() : raw as string)
|
||||
if (value.length > 0 && money.includes(key)) value = yuanToWan(value)
|
||||
if (['socialSecurity', 'housingFund'].includes(key)) value = contributionLabel(value)
|
||||
if (enums.includes(key) && labels[value] != null) value = labels[value] as string
|
||||
payload[key] = value
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user