2026-09-10 10:57:40 +08:00
|
|
|
<template>
|
2026-09-15 16:16:55 +08:00
|
|
|
<view class="page page-white" :style="pageStyle()">
|
2026-09-18 12:59:43 +08:00
|
|
|
<AppHeader :title="titles[step]" :customBack="true" @back="back" />
|
|
|
|
|
<scroll-view scroll-y :style="contentStyle(96, false)">
|
|
|
|
|
<view class="assessment-content">
|
2026-09-30 19:11:44 +08:00
|
|
|
<!-- 离页清空表单时仅切换提示可见性,避免卸载期间创建原生文本节点。 -->
|
|
|
|
|
<text v-if="editId.length > 0" class="section-hint">修改本次评估 · 提交后保留此前版本</text><text v-show="editLoading" class="local-note">正在读取已提交资料…</text><text v-show="editError.length > 0" class="local-note">{{ editError }}</text><text class="local-note">未提交内容不会保存,离开或刷新后需重新填写。</text><view class="progress-row"><view class="step-line"><view v-for="i in 5" :key="i" :class="i <= step + 1 ? 'step-segment done' : 'step-segment'"></view></view><text class="step-count">{{ step + 1 }}/5</text></view>
|
2026-09-18 12:59:43 +08:00
|
|
|
<view v-if="step == 0" class="type-row"><text class="type-label">融资类型</text><view class="type-switch"><text :class="assessmentType == 'personal' ? 'type-item type-active' : 'type-item'" @click="switchType('personal')">个人</text><text :class="assessmentType == 'enterprise' ? 'type-item type-active' : 'type-item'" @click="switchType('enterprise')">企业</text></view></view>
|
|
|
|
|
<text v-else class="section-hint">{{ assessmentType == 'enterprise' ? '企业信用融资' : '个人信用融资' }} · {{ step == 3 ? '资料与授权均为选填' : '请按实际情况填写' }}</text>
|
|
|
|
|
<view v-if="step == 0" class="form-list">
|
|
|
|
|
<view v-if="assessmentType == 'enterprise'" class="form-row"><text class="field-label">企业名称</text><input v-model="form.enterpriseName" class="field-input" placeholder="请输入企业名称" /></view>
|
|
|
|
|
<view v-if="assessmentType == 'enterprise'" class="form-row"><text class="field-label">信用代码</text><input v-model="form.businessCode" class="field-input" maxlength="18" placeholder="统一社会信用代码" /></view>
|
|
|
|
|
<view class="form-row"><text class="field-label">{{ assessmentType == 'enterprise' ? '联系人' : '姓名' }}</text><input v-model="form.name" class="field-input" placeholder="请输入姓名" /></view>
|
|
|
|
|
<view v-if="assessmentType == 'personal'" class="form-row"><text class="field-label">身份证号</text><input v-model="form.idCard" class="field-input" maxlength="18" placeholder="请输入身份证号" /></view>
|
|
|
|
|
<view class="form-row"><text class="field-label">手机号</text><input v-model="form.phone" class="field-input" type="number" maxlength="11" placeholder="请输入手机号" /></view>
|
|
|
|
|
<AssessmentSelect label="所在城市" :modelValue="form.city" @update:modelValue="cityChanged" :options="['深圳市', '广州市', '北京市', '上海市', '杭州市', '其他城市']" />
|
|
|
|
|
<view v-if="form.city == '其他城市' || customCity.length > 0" class="form-row"><text class="field-label">城市名称</text><input v-model="customCity" class="field-input" placeholder="请输入所在城市" /></view>
|
|
|
|
|
<AssessmentSelect v-if="assessmentType == 'personal'" label="婚姻状况" v-model="form.maritalStatus" :options="['未婚', '已婚', '离异', '丧偶']" />
|
|
|
|
|
</view>
|
|
|
|
|
<view v-else-if="step == 1" class="form-list">
|
|
|
|
|
<template v-if="assessmentType == 'enterprise'">
|
|
|
|
|
<AssessmentSelect label="经营行业" v-model="form.occupation" :options="['商贸零售', '制造业', '科技服务', '餐饮住宿', '专业服务', '其他行业']" />
|
2026-09-24 11:50:07 +08:00
|
|
|
<view class="form-row"><text class="field-label">经营月数</text><input v-model="form.operatingMonths" class="field-input" type="number" maxlength="4" placeholder="请输入实际经营月数" /></view>
|
2026-09-18 12:59:43 +08:00
|
|
|
<view class="form-row"><text class="field-label">年营收(万元)</text><input v-model="form.annualRevenue" class="field-input" type="digit" placeholder="请输入年营业收入" /></view>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
<AssessmentSelect label="职业类型" v-model="form.occupation" :options="['企业职员', '事业单位', '公务员', '个体经营', '自由职业', '其他']" />
|
|
|
|
|
<view class="form-row"><text class="field-label">工作单位</text><input v-model="form.company" class="field-input" placeholder="请输入工作单位" /></view>
|
2026-09-22 17:25:52 +08:00
|
|
|
<view class="form-row"><text class="field-label">月收入(万元)</text><input v-model="form.monthlyIncome" class="field-input" type="digit" placeholder="请输入月收入" /></view>
|
2026-09-18 12:59:43 +08:00
|
|
|
<AssessmentSelect label="社保缴纳" v-model="form.socialSecurity" :options="['连续缴纳 6 个月以上', '缴纳不足 6 个月', '未缴纳']" />
|
|
|
|
|
<AssessmentSelect label="公积金缴纳" v-model="form.housingFund" :options="['连续缴纳 6 个月以上', '缴纳不足 6 个月', '未缴纳']" />
|
|
|
|
|
</template>
|
2026-09-30 19:11:44 +08:00
|
|
|
|
2026-09-18 12:59:43 +08:00
|
|
|
</view>
|
|
|
|
|
<view v-else-if="step == 2" class="form-list">
|
2026-09-21 15:04:59 +08:00
|
|
|
<text class="asset-section-title">贷款信息</text>
|
|
|
|
|
<view class="form-row"><text class="field-label">信用贷款笔数</text><input v-model="form.creditLoanCount" class="field-input" type="number" maxlength="4" placeholder="无则填 0" /><text class="field-unit">笔</text></view>
|
2026-09-22 17:25:52 +08:00
|
|
|
<view class="form-row"><text class="field-label">欠款总余额</text><input v-model="form.totalDebtBalance" class="field-input" type="digit" maxlength="15" placeholder="请输入金额" /><text class="field-unit">万元</text></view>
|
|
|
|
|
<view class="form-row"><text class="field-label">贷款月还款金额</text><input v-model="form.monthlyLoanPayment" class="field-input" type="digit" maxlength="15" placeholder="请输入金额" /><text class="field-unit">万元</text></view>
|
2026-09-21 15:04:59 +08:00
|
|
|
<text class="asset-section-title">信用卡信息</text>
|
|
|
|
|
<view class="form-row"><text class="field-label">银行信用卡张数</text><input v-model="form.creditCardCount" class="field-input" type="number" maxlength="4" placeholder="无则填 0" /><text class="field-unit">张</text></view>
|
2026-09-22 17:25:52 +08:00
|
|
|
<view class="form-row"><text class="field-label">总额度</text><input v-model="form.creditCardTotalLimit" class="field-input" type="digit" maxlength="15" placeholder="请输入金额" /><text class="field-unit">万元</text></view>
|
|
|
|
|
<view class="form-row"><text class="field-label">已使用总额度</text><input v-model="form.creditCardUsedLimit" class="field-input" type="digit" maxlength="15" placeholder="请输入金额" /><text class="field-unit">万元</text></view>
|
2026-09-21 15:04:59 +08:00
|
|
|
<text class="asset-section-title">房车信息</text>
|
|
|
|
|
<AssessmentSelect label="是否有房" v-model="form.house" :options="['有', '无']" />
|
|
|
|
|
<AssessmentSelect label="是否有车" v-model="form.car" :options="['有', '无']" />
|
2026-09-18 12:59:43 +08:00
|
|
|
</view>
|
|
|
|
|
<view v-else class="upload-area">
|
|
|
|
|
<text class="upload-title">资料选择 <text class="optional">(选填)</text></text>
|
|
|
|
|
<text class="upload-desc">支持照片,仅在本机预览,尚未上传。</text>
|
|
|
|
|
<view class="upload-grid"><view class="upload-card" v-for="(item, index) in uploadNames" :key="item" :class="index == 2 ? 'upload-last' : ''" @click="documentAction(item)"><image v-if="documentPath(item).length > 0" class="document-thumb" :src="documentPath(item)" mode="aspectFill" @error="documentExpired(item)" /><AppIcon v-else name="upload" :size="52" /><text class="upload-name">{{ item }}</text><text :class="documentPath(item).length > 0 ? 'upload-state selected-state' : 'upload-state'">{{ documentPath(item).length > 0 ? '已选择 · 管理' : '点击选择' }}</text></view></view>
|
|
|
|
|
<view class="consent"><view class="check-hit" @click="documentConsent = !documentConsent"><view :class="documentConsent ? 'checkbox checked' : 'checkbox'"><text v-if="documentConsent" class="check-mark">✓</text></view></view><text class="consent-copy">我已阅读并同意<text class="consent-link" @click="showAgreement('资料使用协议')">《资料使用协议》</text></text></view>
|
|
|
|
|
<view class="data-section"><text class="upload-title">数据授权 <text class="optional">(可选)</text></text><text class="upload-desc">自主选择授权项目,可随时取消选择。</text><view class="grant-list"><view v-for="grant in authorizations" :key="grant.key" :class="grant.selected ? 'grant-card grant-selected' : 'grant-card'" @click="grant.selected = !grant.selected"><text :class="grant.selected ? 'grant-name grant-name-active' : 'grant-name'">{{ grant.name }}</text><view :class="grant.selected ? 'checkbox checked' : 'checkbox'"><text v-if="grant.selected" class="check-mark">✓</text></view></view></view><view class="consent"><view class="check-hit" @click="dataConsent = !dataConsent"><view :class="dataConsent ? 'checkbox checked' : 'checkbox'"><text v-if="dataConsent" class="check-mark">✓</text></view></view><text class="consent-copy">我已阅读并同意<text class="consent-link" @click="showAgreement('数据授权协议')">《数据授权协议》</text></text></view><text class="local-note">当前仅保存选择意向,不查询外部数据。</text></view>
|
|
|
|
|
</view>
|
|
|
|
|
<view class="scroll-spacer" :style="bottomStyle(24)"></view>
|
2026-09-11 20:23:10 +08:00
|
|
|
</view>
|
2026-09-18 12:59:43 +08:00
|
|
|
</scroll-view>
|
2026-09-30 19:11:44 +08:00
|
|
|
<view class="bottom-action" :style="bottomStyle(20)"><button v-if="step > 0" class="back-button" @click="previous">上一步</button><button class="primary-button next-button" :disabled="editLoading || editError.length > 0" @click="next">{{ step == 3 ? '确认信息' : '下一步' }}</button></view>
|
2026-09-10 10:57:40 +08:00
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="uts">
|
2026-09-24 11:50:07 +08:00
|
|
|
import { getSession } from '@/services/api.uts'
|
2026-09-22 17:25:52 +08:00
|
|
|
|
2026-09-30 19:11:44 +08:00
|
|
|
import { fetchAssessmentEdit } from '@/packages/finance/services/records.uts'
|
|
|
|
|
import { writeAssessmentFlow } from '@/services/assessment-flow.uts'
|
2026-09-22 17:25:52 +08:00
|
|
|
import { wanAmountValid } from '@/services/money.uts'
|
2026-09-15 16:16:55 +08:00
|
|
|
import { usePageLayout } from '@/services/layout.uts'
|
2026-09-10 10:57:40 +08:00
|
|
|
import AppHeader from '@/components/AppHeader.uvue'
|
|
|
|
|
import AppIcon from '@/components/AppIcon.uvue'
|
2026-09-20 10:52:10 +08:00
|
|
|
import AssessmentSelect from '@/packages/finance/components/AssessmentSelect.uvue'
|
2026-09-24 11:50:07 +08:00
|
|
|
import { AssessmentForm, SelectedDocument, DataAuthorization, emptyAssessmentForm, activeAssessmentType, getAssessmentInput, formFromInput, documentsFromInput, setAssessmentInput, showAgreementNotice, assetValidationMessage, clearAssessmentFlow } from '@/services/assessment.uts'
|
2026-09-18 12:59:43 +08:00
|
|
|
const { bottomStyle, contentStyle, pageStyle } = usePageLayout()
|
|
|
|
|
const showAgreement = (title: string) => { showAgreementNotice(title) }
|
2026-09-30 19:11:44 +08:00
|
|
|
const editId = ref(''); const editError = ref(''); const editLoading = ref(false)
|
|
|
|
|
let baseRevisionId = ''; let editGeneration = 0
|
2026-09-10 10:57:40 +08:00
|
|
|
const step = ref(0)
|
2026-09-11 20:23:10 +08:00
|
|
|
const assessmentType = ref('personal')
|
2026-09-18 12:59:43 +08:00
|
|
|
const form = ref<AssessmentForm>(emptyAssessmentForm())
|
2026-10-07 10:01:05 +08:00
|
|
|
let ownerToken = ''; let goingToConfirm = false; let visible = false; let accountTimer = 0
|
2026-09-24 11:50:07 +08:00
|
|
|
const sameOwner = (): boolean => { const session = getSession(); return session != null && session['token'] == ownerToken }
|
2026-09-18 12:59:43 +08:00
|
|
|
const customCity = ref('')
|
|
|
|
|
const cityChanged = (city: string) => { form.value.city = city; if (city != '其他城市') customCity.value = '' }
|
|
|
|
|
const documentConsent = ref(false)
|
|
|
|
|
const dataConsent = ref(false)
|
|
|
|
|
const documents = ref<SelectedDocument[]>([])
|
|
|
|
|
const authorizations = ref<DataAuthorization[]>([{ key: 'credit', name: '征信查询', selected: false }, { key: 'business', name: '经营数据', selected: false }, { key: 'fund', name: '公积金数据', selected: false }])
|
2026-09-30 19:11:44 +08:00
|
|
|
const titles = ['基本信息', '经营 / 收入信息', '资产 / 负债信息', '资料上传 / 授权']
|
2026-09-22 17:25:52 +08:00
|
|
|
const uploadNames = computed((): string[] => assessmentType.value == 'enterprise' ? ['营业执照', '银行流水', '经营证明'] : ['身份证正面', '身份证反面', '银行卡', '收入证明'])
|
2026-09-18 12:59:43 +08:00
|
|
|
let initialized = false
|
2026-10-07 10:01:05 +08:00
|
|
|
const stopAccountTimer = () => { if (accountTimer != 0) clearInterval(accountTimer); accountTimer = 0 }
|
|
|
|
|
const ensureOwner = (): boolean => {
|
|
|
|
|
if (!visible) return false
|
|
|
|
|
if (sameOwner()) return true
|
|
|
|
|
const session = getSession()
|
|
|
|
|
ownerToken = session?.getString('token') ?? ''
|
|
|
|
|
editGeneration++; initialized = false; stopAccountTimer(); clearAssessmentFlow()
|
|
|
|
|
form.value = emptyAssessmentForm(); documents.value = []; customCity.value = ''; step.value = 0
|
|
|
|
|
documentConsent.value = false; dataConsent.value = false; authorizations.value.forEach((item) => { item.selected = false })
|
|
|
|
|
baseRevisionId = ''; editLoading.value = false; editError.value = '账户已变化,请返回重新填写。'
|
|
|
|
|
if (session == null) uni.redirectTo({ url: '/packages/account/login/login' })
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
const startAccountTimer = () => {
|
|
|
|
|
stopAccountTimer()
|
|
|
|
|
if (ownerToken.length == 0) return
|
|
|
|
|
accountTimer = setInterval(() => { if (visible && !sameOwner()) ensureOwner() }, 1000)
|
|
|
|
|
}
|
2026-09-24 11:50:07 +08:00
|
|
|
const rememberInput = () => {
|
|
|
|
|
if (!initialized || !sameOwner()) return
|
2026-09-18 12:59:43 +08:00
|
|
|
const source = form.value
|
2026-09-30 19:11:44 +08:00
|
|
|
const currentForm: AssessmentForm = { name: source.name, idCard: source.idCard, phone: source.phone, city: source.city, maritalStatus: source.maritalStatus, occupation: source.occupation, company: source.company, monthlyIncome: source.monthlyIncome, socialSecurity: source.socialSecurity, housingFund: source.housingFund, house: source.house, car: source.car, savings: source.savings, creditCard: source.creditCard, otherAssets: source.otherAssets, creditLoanCount: source.creditLoanCount, totalDebtBalance: source.totalDebtBalance, monthlyLoanPayment: source.monthlyLoanPayment, creditCardCount: source.creditCardCount, creditCardTotalLimit: source.creditCardTotalLimit, creditCardUsedLimit: source.creditCardUsedLimit, enterpriseName: source.enterpriseName, businessCode: source.businessCode, annualRevenue: source.annualRevenue, operatingYears: source.operatingYears, operatingMonths: source.operatingMonths }
|
2026-09-24 11:50:07 +08:00
|
|
|
if (currentForm.city == '其他城市' && customCity.value.trim().length > 0) currentForm.city = customCity.value.trim()
|
2026-09-30 19:11:44 +08:00
|
|
|
setAssessmentInput(assessmentType.value, step.value, currentForm, documents.value, authorizations.value, documentConsent.value, dataConsent.value, editId.value, baseRevisionId)
|
2026-09-10 10:57:40 +08:00
|
|
|
}
|
2026-09-18 12:59:43 +08:00
|
|
|
const restore = (type: string) => {
|
|
|
|
|
assessmentType.value = type; step.value = 0; form.value = emptyAssessmentForm(); customCity.value = ''; documents.value = []; documentConsent.value = false; dataConsent.value = false
|
|
|
|
|
authorizations.value.forEach((item) => { item.selected = false })
|
2026-09-24 11:50:07 +08:00
|
|
|
const saved = getAssessmentInput(type)
|
2026-09-18 12:59:43 +08:00
|
|
|
if (saved != null) {
|
2026-09-24 11:50:07 +08:00
|
|
|
form.value = formFromInput(saved); documents.value = documentsFromInput(saved)
|
2026-09-18 12:59:43 +08:00
|
|
|
const savedStep = saved['step']; if (typeof savedStep == 'number') step.value = Math.max(0, Math.min(3, savedStep as number))
|
|
|
|
|
documentConsent.value = saved['documentConsent'] == true; dataConsent.value = saved['dataConsent'] == true
|
|
|
|
|
const grants = saved['authorizations'] as string[] | null
|
|
|
|
|
if (grants != null) authorizations.value.forEach((item) => { item.selected = grants.includes(item.key) })
|
|
|
|
|
if (form.value.city.length > 0 && !['深圳市', '广州市', '北京市', '上海市', '杭州市', '其他城市'].includes(form.value.city)) { customCity.value = form.value.city; form.value.city = '其他城市' }
|
2026-09-11 20:23:10 +08:00
|
|
|
}
|
2026-09-18 12:59:43 +08:00
|
|
|
initialized = true
|
2026-09-24 11:50:07 +08:00
|
|
|
rememberInput()
|
2026-09-18 12:59:43 +08:00
|
|
|
}
|
2026-10-07 10:01:05 +08:00
|
|
|
const switchType = (type: string) => { if (!ensureOwner() || editId.value.length > 0 || assessmentType.value == type) return; rememberInput(); restore(type); step.value = 0; rememberInput() }
|
2026-09-30 19:11:44 +08:00
|
|
|
const loadEdit = async (type: string) => {
|
|
|
|
|
const ticket = ++editGeneration; editLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const saved = await fetchAssessmentEdit(editId.value)
|
2026-10-07 10:01:05 +08:00
|
|
|
if (ticket != editGeneration || !ensureOwner()) return
|
2026-09-30 19:11:44 +08:00
|
|
|
baseRevisionId = saved.getString('baseRevisionId') ?? ''
|
|
|
|
|
writeAssessmentFlow(ownerToken, saved); restore(saved.getString('type') ?? type)
|
2026-10-07 10:01:05 +08:00
|
|
|
} catch (err) { if (ticket == editGeneration && ensureOwner()) editError.value = err instanceof Error ? err.message : '资料读取失败,请返回重试。' }
|
2026-09-30 19:11:44 +08:00
|
|
|
finally { if (ticket == editGeneration) editLoading.value = false }
|
|
|
|
|
}
|
2026-09-18 12:59:43 +08:00
|
|
|
onLoad((options) => {
|
2026-09-24 11:50:07 +08:00
|
|
|
const session = getSession()
|
|
|
|
|
if (session == null) { uni.redirectTo({ url: '/packages/account/login/login' }); return }
|
|
|
|
|
ownerToken = session['token'] as string
|
|
|
|
|
clearAssessmentFlow()
|
2026-09-18 12:59:43 +08:00
|
|
|
let type = activeAssessmentType()
|
|
|
|
|
if (options != null && (options['type'] == 'enterprise' || options['type'] == 'personal')) type = options['type'] as string
|
2026-09-30 19:11:44 +08:00
|
|
|
editId.value = options?.['editId'] ?? ''
|
|
|
|
|
if (editId.value.length == 0) { restore(type); return }
|
|
|
|
|
if (!/^[1-9][0-9]{0,9}$/.test(editId.value)) { editError.value = '评估编号无效,请返回档案重新选择。'; return }
|
|
|
|
|
loadEdit(type)
|
2026-09-11 20:23:10 +08:00
|
|
|
})
|
2026-09-24 11:50:07 +08:00
|
|
|
onShow(() => {
|
2026-10-07 10:01:05 +08:00
|
|
|
visible = true; stopAccountTimer()
|
|
|
|
|
goingToConfirm = false
|
|
|
|
|
if (initialized && !sameOwner()) ensureOwner()
|
2026-09-24 11:50:07 +08:00
|
|
|
const input = getAssessmentInput(assessmentType.value)
|
|
|
|
|
if (initialized && input != null && typeof input['step'] == 'number') step.value = Math.max(0, Math.min(3, input['step'] as number))
|
2026-10-07 10:01:05 +08:00
|
|
|
startAccountTimer()
|
2026-09-24 11:50:07 +08:00
|
|
|
})
|
|
|
|
|
// 离开填写流程即丢弃未提交内容;进入确认页时只在内存传递。
|
|
|
|
|
onHide(() => {
|
2026-10-07 10:01:05 +08:00
|
|
|
visible = false; stopAccountTimer()
|
2026-09-24 11:50:07 +08:00
|
|
|
if (!goingToConfirm) {
|
2026-09-30 19:11:44 +08:00
|
|
|
editGeneration++; if (editId.value.length > 0) editError.value = '已离开修改流程,请返回档案重新进入。'
|
|
|
|
|
// 离页清空资料但不切换步骤,避免卸载时又挂载另一组原生输入组件。
|
|
|
|
|
clearAssessmentFlow(); form.value = emptyAssessmentForm(); documents.value = []
|
2026-09-24 11:50:07 +08:00
|
|
|
customCity.value = ''; documentConsent.value = false; dataConsent.value = false
|
|
|
|
|
authorizations.value.forEach((item) => { item.selected = false })
|
|
|
|
|
}
|
|
|
|
|
})
|
2026-10-07 10:01:05 +08:00
|
|
|
onUnload(() => { visible = false; stopAccountTimer(); editGeneration++; initialized = false; clearAssessmentFlow() })
|
2026-09-24 11:50:07 +08:00
|
|
|
// 页内前后步骤只维护当前内存状态,返回入口后不保留填写内容。
|
|
|
|
|
onBackPress((): boolean => { rememberInput(); if (step.value > 0) { step.value--; rememberInput(); return true }; return false })
|
|
|
|
|
const previous = () => { rememberInput(); if (step.value > 0) step.value--; rememberInput() }
|
|
|
|
|
const back = () => { if (step.value > 0) { previous(); return }; rememberInput(); if (getCurrentPages().length > 1) uni.navigateBack(); else uni.redirectTo({ url: '/packages/finance/entry/entry?type=' + assessmentType.value }) }
|
2026-09-18 12:59:43 +08:00
|
|
|
const documentPath = (name: string): string => { const item = documents.value.find((file) => file.name == name); return item == null ? '' : item.path }
|
|
|
|
|
const documentExpired = (name: string) => {
|
2026-09-24 11:50:07 +08:00
|
|
|
documents.value = documents.value.filter((file) => file.name != name); rememberInput()
|
2026-09-18 12:59:43 +08:00
|
|
|
uni.showToast({ title: name + '已失效,请重新选择', icon: 'none' })
|
2026-09-11 20:23:10 +08:00
|
|
|
}
|
2026-09-18 12:59:43 +08:00
|
|
|
const chooseDocument = (name: string) => {
|
2026-10-07 10:01:05 +08:00
|
|
|
if (!ensureOwner()) return
|
|
|
|
|
const ticket = editGeneration
|
2026-09-18 12:59:43 +08:00
|
|
|
uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: (result) => {
|
2026-10-07 10:01:05 +08:00
|
|
|
if (ticket != editGeneration || !ensureOwner() || result.tempFilePaths.length == 0) return
|
2026-09-18 12:59:43 +08:00
|
|
|
documents.value = documents.value.filter((file) => file.name != name)
|
|
|
|
|
const document: SelectedDocument = { name, path: result.tempFilePaths[0] }
|
2026-09-24 11:50:07 +08:00
|
|
|
documents.value.push(document); rememberInput()
|
2026-10-07 10:01:05 +08:00
|
|
|
}, fail: (error) => { if (ticket == editGeneration && ensureOwner() && !error.errMsg.includes('cancel')) uni.showToast({ title: '选择失败,请重试或检查相册权限', icon: 'none' }) } })
|
2026-09-18 12:59:43 +08:00
|
|
|
}
|
|
|
|
|
const documentAction = (name: string) => {
|
2026-10-07 10:01:05 +08:00
|
|
|
if (!ensureOwner()) return
|
|
|
|
|
const ticket = editGeneration
|
2026-09-18 12:59:43 +08:00
|
|
|
const path = documentPath(name)
|
|
|
|
|
if (path.length == 0) { chooseDocument(name); return }
|
|
|
|
|
uni.showActionSheet({ itemList: ['预览图片', '重新选择', '移除资料'], success: (result) => {
|
2026-10-07 10:01:05 +08:00
|
|
|
if (ticket != editGeneration || !ensureOwner()) return
|
2026-09-18 12:59:43 +08:00
|
|
|
if (result.tapIndex == 0) uni.previewImage({ urls: [path], fail: () => { uni.showToast({ title: '本地图片已失效,请重新选择', icon: 'none' }) } })
|
|
|
|
|
else if (result.tapIndex == 1) chooseDocument(name)
|
2026-09-24 11:50:07 +08:00
|
|
|
else if (result.tapIndex == 2) { documents.value = documents.value.filter((file) => file.name != name); rememberInput() }
|
2026-09-18 12:59:43 +08:00
|
|
|
} })
|
|
|
|
|
}
|
|
|
|
|
const validateStep = (): boolean => {
|
|
|
|
|
let message = ''
|
|
|
|
|
if (step.value == 0) {
|
|
|
|
|
if (assessmentType.value == 'enterprise' && form.value.enterpriseName.trim().length < 2) message = '请输入企业名称'
|
|
|
|
|
else if (assessmentType.value == 'enterprise' && !/^[0-9A-Z]{18}$/.test(form.value.businessCode.trim().toUpperCase())) message = '请输入 18 位统一社会信用代码'
|
|
|
|
|
else if (form.value.name.trim().length < 2) message = '请输入正确姓名'
|
|
|
|
|
else if (assessmentType.value == 'personal' && !/(^[0-9]{15}$)|(^[0-9]{17}[0-9Xx]$)/.test(form.value.idCard.trim())) message = '请输入正确身份证号'
|
|
|
|
|
else if (!/^1[3-9][0-9]{9}$/.test(form.value.phone)) message = '请输入正确手机号'
|
|
|
|
|
else if (form.value.city.length == 0 || (form.value.city == '其他城市' && customCity.value.trim().length == 0)) message = '请选择或填写所在城市'
|
|
|
|
|
}
|
|
|
|
|
if (step.value == 1) {
|
|
|
|
|
const amount = assessmentType.value == 'enterprise' ? form.value.annualRevenue : form.value.monthlyIncome
|
2026-09-22 17:25:52 +08:00
|
|
|
if (!wanAmountValid(amount) || parseFloat(amount) <= 0) message = assessmentType.value == 'enterprise' ? '请输入有效年营收(万元,最多六位小数)' : '请输入有效月收入(万元,最多六位小数)'
|
2026-09-18 12:59:43 +08:00
|
|
|
}
|
2026-09-21 15:04:59 +08:00
|
|
|
if (step.value == 2) message = assetValidationMessage(form.value)
|
2026-09-18 12:59:43 +08:00
|
|
|
if (step.value == 3 && documents.value.length > 0 && !documentConsent.value) message = '请阅读并同意资料使用协议,或移除资料'
|
|
|
|
|
if (step.value == 3 && authorizations.value.some((item) => item.selected) && !dataConsent.value) message = '请阅读并同意数据授权协议,或取消授权选择'
|
|
|
|
|
if (message.length == 0) return true
|
|
|
|
|
uni.showToast({ title: message, icon: 'none' }); return false
|
|
|
|
|
}
|
2026-10-07 10:01:05 +08:00
|
|
|
const next = () => { if (!ensureOwner() || editLoading.value || editError.value.length > 0) return; if (!validateStep()) return; if (step.value < 3) { step.value++; rememberInput() } else { rememberInput(); goingToConfirm = true; uni.navigateTo({ url: '/packages/finance/confirm/confirm', fail: () => { goingToConfirm = false } }) } }
|
2026-09-10 10:57:40 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
2026-09-18 12:59:43 +08:00
|
|
|
.assessment-content { padding: 26rpx 30rpx 0; }
|
|
|
|
|
.progress-row { flex-direction: row; align-items: center; }
|
|
|
|
|
.step-line { height: 8rpx; flex: 1; flex-direction: row; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.step-segment { flex: 1; height: 8rpx; border-radius: 8rpx; background-color: #e8edf4; margin-right: 8rpx; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.done { background-color: #0868f7; }
|
|
|
|
|
.step-count { color: #758297; font-size: 24rpx; margin-left: 20rpx; }
|
|
|
|
|
.type-row { margin-top: 30rpx; flex-direction: row; align-items: center; justify-content: space-between; }
|
|
|
|
|
.type-label { font-size: 28rpx; color: #29374e; }
|
|
|
|
|
.type-switch { flex-direction: row; padding: 5rpx; border-radius: 14rpx; background-color: #eef4fd; }
|
|
|
|
|
.type-item { width: 130rpx; padding: 13rpx 0; border-radius: 10rpx; text-align: center; color: #68809f; font-size: 26rpx; }
|
|
|
|
|
.type-active { color: #0868f7; font-weight: 600; background-color: #fff; }
|
|
|
|
|
.section-hint { color: #738198; font-size: 24rpx; line-height: 36rpx; margin-top: 30rpx; }
|
|
|
|
|
.form-list { margin-top: 14rpx; }
|
2026-09-21 15:04:59 +08:00
|
|
|
.asset-section-title { margin-top: 28rpx; font-size: 26rpx; line-height: 38rpx; color: #738198; font-weight: 600; }
|
|
|
|
|
.field-unit { margin-left: 12rpx; font-size: 25rpx; color: #738198; flex-shrink: 0; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.form-row { min-height: 106rpx; flex-direction: row; align-items: center; border-bottom: 1rpx solid #edf1f6; }
|
|
|
|
|
.field-label { font-size: 28rpx; color: #29374e; margin-right: 18rpx; flex-shrink: 0; }
|
|
|
|
|
.field-input { flex: 1; min-width: 0; text-align: right; font-size: 27rpx; color: #22324a; }
|
|
|
|
|
.upload-title { font-size: 30rpx; font-weight: 600; color: #20304a; margin-top: 28rpx; }
|
|
|
|
|
.optional { font-size: 24rpx; color: #748198; font-weight: 400; }
|
|
|
|
|
.upload-desc { font-size: 24rpx; line-height: 36rpx; color: #748198; margin-top: 10rpx; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.upload-grid { flex-direction: row; margin-top: 22rpx; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.upload-card { flex: 1; min-width: 0; height: 200rpx; margin-right: 14rpx; border-radius: 16rpx; background-color: #f1f6fd; align-items: center; justify-content: center; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.upload-last { margin-right: 0; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.document-thumb { width: 74rpx; height: 62rpx; border-radius: 8rpx; }
|
|
|
|
|
.upload-name { font-size: 25rpx; color: #304260; margin-top: 16rpx; }
|
|
|
|
|
.upload-state { color: #7a889e; font-size: 22rpx; margin-top: 9rpx; }
|
|
|
|
|
.selected-state { color: #0868f7; }
|
|
|
|
|
.consent { margin-top: 24rpx; flex-direction: row; align-items: flex-start; }
|
|
|
|
|
.check-hit { width: 44rpx; height: 42rpx; flex-shrink: 0; justify-content: center; }
|
|
|
|
|
.checkbox { width: 30rpx; height: 30rpx; border-radius: 8rpx; border: 2rpx solid #9aa8ba; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
|
|
|
.checked { background-color: #0868f7; border-color: #0868f7; }
|
|
|
|
|
.check-mark { color: #fff; font-size: 22rpx; }
|
|
|
|
|
.consent-copy { flex: 1; min-width: 0; color: #687991; font-size: 24rpx; line-height: 40rpx; }
|
|
|
|
|
.consent-link { color: #0868f7; font-size: 24rpx; line-height: 40rpx; }
|
|
|
|
|
.data-section { margin-top: 24rpx; padding-top: 4rpx; border-top: 1rpx solid #e9eef6; }
|
|
|
|
|
.grant-list { margin-top: 18rpx; }
|
|
|
|
|
.grant-card { min-height: 78rpx; padding: 0 22rpx; border: 1rpx solid #e3eaf4; border-radius: 14rpx; margin-top: 12rpx; flex-direction: row; align-items: center; justify-content: space-between; }
|
|
|
|
|
.grant-selected { border-color: #c3d9ff; background-color: #f1f6ff; }
|
|
|
|
|
.grant-name { font-size: 27rpx; color: #344761; }
|
|
|
|
|
.grant-name-active { color: #0868f7; }
|
|
|
|
|
.local-note { color: #8290a4; font-size: 22rpx; line-height: 34rpx; margin-top: 14rpx; }
|
|
|
|
|
.scroll-spacer { min-height: 160rpx; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.bottom-action { position: fixed; left: 0; right: 0; bottom: 0; padding: 20rpx 30rpx; background-color: #fff; border-top: 1rpx solid #edf1f6; flex-direction: row; }
|
2026-09-18 12:59:43 +08:00
|
|
|
.back-button { width: 180rpx; height: 92rpx; line-height: 92rpx; margin-right: 18rpx; border-radius: 16rpx; background-color: #eef3f9; color: #526075; font-size: 28rpx; }
|
2026-09-15 16:16:55 +08:00
|
|
|
.next-button { flex: 1; margin: 0; }
|
2026-09-10 10:57:40 +08:00
|
|
|
</style>
|