feat: 优化账户切换时的页面状态一致性,增加登录回跳校验和课程阅读新逻辑
- 增加账户状态监听定时器,页面切换时自动校验账户归属,避免跨账户操作 - 新增登录回跳路径校验函数,限制仅允许指定页面回跳,防止非法跳转 - 课程页改为整篇连续阅读,底部仅一次标记已读,兼容历史记录 - 完善助手、对比页、资料填写页等多处的账户状态校验逻辑,防止错版数据提交 - 优化账户资料请求逻辑,增加版本校验,避免旧请求覆盖新数据
This commit is contained in:
@@ -14,6 +14,7 @@ export type ArchiveCompleteness = { percent: number | null, description: string
|
||||
export async function fetchArchiveCompleteness(id: string, revisionId: string = ''): Promise<ArchiveCompleteness> {
|
||||
const report = await requestJson('/assessments/' + encodeURIComponent(id) + '/report', 'GET', revisionParams(revisionId))
|
||||
if (report.getString('assessmentId') != id) throw new Error('报告与当前档案不一致')
|
||||
if (revisionId.length > 0 && report.getString('revisionId') != revisionId) throw new Error('报告版本不一致,请重新选择。')
|
||||
if (report.getNumber('resultVersion') == 1) return { percent: null, description: '这份旧版报告未计算完整度,已提交资料仍可查看。' }
|
||||
if (report.getNumber('resultVersion') != 2) throw new Error('报告格式暂不支持')
|
||||
const completeness = report['completeness'] as UTSJSONObject | null
|
||||
@@ -23,7 +24,14 @@ export async function fetchArchiveCompleteness(id: string, revisionId: string =
|
||||
return { percent, description: '反映本次评估时的资料填写情况,不代表信用评分或审批结果。' }
|
||||
}
|
||||
|
||||
function recordFrom(item: UTSJSONObject): AssessmentRecord {
|
||||
function validAssessmentId(value: string): boolean { return /^[1-9][0-9]{0,9}$/.test(value) }
|
||||
function recordFrom(item: UTSJSONObject, id: string = '', revisionId: string = ''): AssessmentRecord {
|
||||
const recordId = draftText(item, 'assessmentId'); const revision = draftText(item, 'revisionId')
|
||||
const revisionNo = item.getNumber('revisionNo')
|
||||
if (!validAssessmentId(recordId) || !validAssessmentId(revision) || (id.length > 0 && recordId != id) || (revisionId.length > 0 && revision != revisionId)
|
||||
|| !['personal', 'enterprise'].includes(draftText(item, 'type')) || !['processing', 'failed', 'succeeded'].includes(draftText(item, 'status'))
|
||||
|| revisionNo == null || !Number.isInteger(revisionNo) || revisionNo < 1
|
||||
|| (item.getBoolean('hasReport') == true && !validAssessmentId(draftText(item, 'publishedRevisionId')))) throw new Error('评估记录或版本不一致,请重新加载。')
|
||||
const submitted = draftText(item, 'submittedAt')
|
||||
const date = new Date(submitted)
|
||||
const pad = (value: number): string => value < 10 ? '0' + value.toString() : value.toString()
|
||||
@@ -126,6 +134,9 @@ export async function createAssessment(payload: UTSJSONObject): Promise<string>
|
||||
const documents = payload['documents'] as UTSJSONObject[] | null
|
||||
const grants = payload['authorizations'] as string[] | null
|
||||
if ((documents != null && documents.length > 0) || (grants != null && grants.length > 0)) throw new Error('资料上传与外部查询授权尚未开放,请移除资料及授权选择后提交')
|
||||
const editId = draftText(payload, 'editAssessmentId'); const baseRevision = draftText(payload, 'baseRevisionId')
|
||||
if (editId.length > 0 && (!validAssessmentId(editId) || !validAssessmentId(baseRevision))) throw new Error('修改版本无效,请返回档案重新读取。')
|
||||
if (!['personal', 'enterprise'].includes(draftText(payload, 'type'))) throw new Error('评估类型无效,请重新填写。')
|
||||
const values = assessmentApiPayload(payload)
|
||||
const form = new UTSJSONObject()
|
||||
const textKeys = ['name', 'idCard', 'phone', 'city', 'occupation', 'company', 'enterpriseName', 'businessCode']
|
||||
@@ -150,14 +161,15 @@ export async function createAssessment(payload: UTSJSONObject): Promise<string>
|
||||
form['cityCode'] = cityIndex < 0 ? null : cityCodes[cityIndex]
|
||||
// 输入v3恢复原资料表单,不提交已取消的资金需求字段;报告仍使用v2展示结构。
|
||||
const body: UTSJSONObject = { inputVersion: 3, type: values['type'], moneyUnit: 'yuan', form, documents: [] as UTSJSONObject[], consentIds: [] as string[] }
|
||||
const editId = draftText(payload, 'editAssessmentId')
|
||||
if (editId.length > 0) body['baseRevisionId'] = draftText(payload, 'baseRevisionId')
|
||||
if (editId.length > 0) body['baseRevisionId'] = baseRevision
|
||||
// 新建和修改使用不同幂等作用域,回执丢失时安全重放原提交。
|
||||
body['requestId'] = assessmentRequestKey(session['token'] as string, editId + ':' + JSON.stringify(body))
|
||||
const path = editId.length > 0 ? '/assessments/' + encodeURIComponent(editId) + '/revisions' : '/assessments'
|
||||
const result = await requestJson(path, 'POST', body)
|
||||
const id = draftText(result, 'assessmentId')
|
||||
if (id.length == 0) throw new Error('提交回执不完整,请重试')
|
||||
const revision = draftText(result, 'revisionId')
|
||||
if (!validAssessmentId(id) || !validAssessmentId(revision) || result.getString('submissionStatus') != 'accepted'
|
||||
|| (editId.length > 0 && (id != editId || revision == baseRevision))) throw new Error('提交回执不一致,请使用原提交重试。')
|
||||
return id
|
||||
}
|
||||
|
||||
@@ -166,16 +178,34 @@ export async function fetchAssessments(cursor: string, type: string = ''): Promi
|
||||
// 按主体在服务端过滤后分页,不能只过滤当前页而漏掉更早的企业/个人档案。
|
||||
if (type.length > 0) params['type'] = type
|
||||
const result = await requestJson('/assessments', 'GET', params)
|
||||
const items = result['items'] as UTSJSONObject[] | null
|
||||
return { items: items == null ? [] : items.map((item: UTSJSONObject): AssessmentRecord => recordFrom(item)), hasMore: result['hasMore'] == true, nextCursor: draftText(result, 'nextCursor') }
|
||||
return assessmentPageFrom(result, cursor, type)
|
||||
}
|
||||
|
||||
// 记录和版本分页必须属于当前选择,坏页不能推进游标或拼入另一评估。
|
||||
function assessmentPageFrom(result: UTSJSONObject, cursor: string, type: string = '', id: string = ''): AssessmentPage {
|
||||
const rawItems = result['items'] as UTSJSONObject[] | null
|
||||
const more = result.getBoolean('hasMore'); const next = draftText(result, 'nextCursor')
|
||||
if (rawItems == null || !Array.isArray(rawItems) || more == null) throw new Error('历史分页格式不完整,请重试。')
|
||||
const items: AssessmentRecord[] = []; let previous = cursor
|
||||
rawItems.forEach((item: UTSJSONObject) => {
|
||||
const record = recordFrom(item, id)
|
||||
const key = id.length > 0 ? record.revisionId : record.id
|
||||
if ((type.length > 0 && record.type != type) || (previous.length > 0 && parseInt(key) >= parseInt(previous))) throw new Error('历史分页记录不一致,请重试。')
|
||||
previous = key; items.push(record)
|
||||
})
|
||||
if ((more && (items.length == 0 || !validAssessmentId(next) || next != previous)) || (!more && next.length > 0)) throw new Error('历史分页游标不一致,请重试。')
|
||||
return { items, hasMore: more, nextCursor: next }
|
||||
}
|
||||
|
||||
export async function fetchAssessmentStatus(id: string): Promise<AssessmentRecord> {
|
||||
return recordFrom(await requestJson('/assessments/' + encodeURIComponent(id) + '/status', 'GET', {}))
|
||||
return recordFrom(await requestJson('/assessments/' + encodeURIComponent(id) + '/status', 'GET', {}), id)
|
||||
}
|
||||
|
||||
export async function fetchAssessmentDetail(id: string, revisionId: string = ''): Promise<AssessmentDetail> {
|
||||
const result = await requestJson('/assessments/' + encodeURIComponent(id), 'GET', revisionParams(revisionId))
|
||||
if (result.getString('assessmentId') != id) throw new Error('评估详情与当前档案不一致')
|
||||
if (revisionId.length > 0 && result.getString('revisionId') != revisionId) throw new Error('评估详情版本不一致,请重新选择。')
|
||||
const record = recordFrom(result, id, revisionId)
|
||||
const form = result['form'] as UTSJSONObject | null
|
||||
if (form == null) throw new Error('评估详情不完整')
|
||||
const fields: AssessmentField[] = []
|
||||
@@ -209,19 +239,21 @@ export async function fetchAssessmentDetail(id: string, revisionId: string = '')
|
||||
// “无”及数值0都是已填写,不能用真值判断遗漏零负债、零经营月数。
|
||||
addField(incomeKeys.includes(key) ? 1 : (assetKeys.includes(key) ? 2 : 0), labels[index], value, raw != null && value.length > 0)
|
||||
})
|
||||
return { record: recordFrom(result), fields, sections }
|
||||
return { record, fields, sections }
|
||||
}
|
||||
|
||||
// 版本编号显式随请求传递,避免不同页面共享“当前版本”造成报告串版。
|
||||
export function revisionParams(revisionId: string): UTSJSONObject { return revisionId.length > 0 ? { revisionId } : new UTSJSONObject() }
|
||||
export async function fetchAssessmentRevisions(id: string, cursor: string): Promise<AssessmentPage> {
|
||||
const result = await requestJson('/assessments/' + encodeURIComponent(id) + '/revisions', 'GET', { cursor })
|
||||
return { items: (result['items'] as UTSJSONObject[]).map((item: UTSJSONObject): AssessmentRecord => recordFrom(item)), hasMore: result.getBoolean('hasMore') ?? false, nextCursor: draftText(result, 'nextCursor') }
|
||||
return assessmentPageFrom(result, cursor, '', id)
|
||||
}
|
||||
export async function fetchAssessmentEdit(id: string): Promise<UTSJSONObject> {
|
||||
const result = await requestJson('/assessments/' + encodeURIComponent(id) + '/edit', 'GET', {})
|
||||
if (draftText(result, 'assessmentId') != id || result.getString('status') == 'processing') throw new Error('评估正在处理中,请完成后再修改。')
|
||||
const form = result['form'] as UTSJSONObject
|
||||
const record = recordFrom(result, id)
|
||||
if (record.status == 'processing') throw new Error('评估正在处理中,请完成后再修改。')
|
||||
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 labels: UTSJSONObject = { married: '已婚', single: '未婚', divorced: '离异', widowed: '丧偶', yes: '有', no: '无', six_months_plus: '连续缴纳 6 个月以上', under_six_months: '缴纳不足 6 个月', none: '未缴纳' }
|
||||
|
||||
Reference in New Issue
Block a user