| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- <template>
- <view class="page" v-if="loaded">
- <view v-if="mode !== 'settlement-change'" class="steps">
- <view v-for="(name, index) in stepNames" :key="name" class="step" :class="{ active: currentStep >= index + 1 }" @click="goStep(index + 1)">
- <view class="circle">{{ index + 1 }}</view>
- <text>{{ name }}</text>
- </view>
- </view>
- <view v-if="currentStep === 1 && mode !== 'settlement-change'">
- <SectionTitle title="商家基本情况" />
- <view class="box choice-row">
- <text class="label required" style="width: 280upx;">商户类别</text>
- <radio-group @change="setValue('license.merchantType', $event.detail.value)">
- <label><radio value="TP_MERCHANT" :checked="form.license.merchantType === 'TP_MERCHANT'" />企业</label>
- <label><radio value="TP_PERSONAL" :checked="form.license.merchantType === 'TP_PERSONAL'" />小微</label>
- </radio-group>
- </view>
- <AttachmentCard v-if="form.license.merchantType === 'TP_MERCHANT'" title="营业执照" imgType="BUSINESS_LICENCE" :items="form.license.attachments" @upload="uploadAttachment('license', 'BUSINESS_LICENCE', true)" />
- <view class="box">
- <FormInput v-if="form.license.merchantType === 'TP_MERCHANT'" label="营业执照名称" v-model="form.license.licenseName" required />
- <FormInput v-if="form.license.merchantType === 'TP_MERCHANT'" label="证件代码" v-model="form.license.licenseNo" required />
- <DateInput v-if="form.license.merchantType === 'TP_MERCHANT'" label="执照起始日期" v-model="form.license.licenseStart" />
- <DateInput v-if="form.license.merchantType === 'TP_MERCHANT'" label="执照有效期" v-model="form.license.licenseEnd" />
- <FormInput v-if="form.license.merchantType === 'TP_MERCHANT'" label="注册地址" v-model="form.license.registeredAddress" />
- </view>
- <AttachmentCard title="身份证人像面" imgType="ID_CARD_FRONT" :items="form.license.attachments" @upload="uploadAttachment('license', 'ID_CARD_FRONT', true)" />
- <AttachmentCard title="身份证国徽面" imgType="ID_CARD_BEHIND" :items="form.license.attachments" @upload="uploadAttachment('license', 'ID_CARD_BEHIND', true)" />
- <view class="box">
- <!-- <FormInput label="经营范围" v-model="form.license.businessContent" required /> -->
- <view v-if="form.license.merchantType === 'TP_PERSONAL'">
- <FormInput label="姓名" v-model="form.license.legalName" required />
- </view>
- <view v-if="form.license.merchantType === 'TP_MERCHANT'">
- <FormInput label="法人姓名" v-model="form.license.legalName" required />
- </view>
- <FormInput label="身份证号" v-model="form.license.legalIdNo" required />
- <DateInput label="身份证起始日期" v-model="form.license.legalIdStart" />
- <DateInput label="身份证有效期" v-model="form.license.legalIdEnd" />
- </view>
- </view>
- <view v-if="currentStep === 2 && mode !== 'settlement-change'">
- <SectionTitle title="商户信息" />
- <view class="box">
- <FormInput label="商户经营名称" v-model="form.merchant.businessName" required />
- <view class="form-row">
- <text class="form-label required">商户所在地区</text>
- <button class="mini-btn" @click="chooseRegion('merchant', 'region')">{{ merchantRegionText }}</button>
- </view>
- <FormInput label="详细地址" v-model="form.merchant.address" required />
- </view>
- <view class="tip">商户类型固定为花店(5992);联系人、手机号和邮箱按系统默认值提交。</view>
- </view>
- <view v-if="currentStep === 3">
- <SectionTitle title="结算信息" />
- <view class="box choice-row">
- <text class="label required" style="width: 290upx;">账户类型</text>
- <radio-group @change="setValue('settlement.accountType', $event.detail.value)">
- <label><radio value="58" :checked="form.settlement.accountType === '58'" />对私</label>
- <label><radio value="57" :checked="form.settlement.accountType === '57'" />对公</label>
- </radio-group>
- </view>
- <view v-if="form.settlement.accountType === '58'" class="box switch-row">
- <text>是否法人进件</text>
- <switch :checked="form.settlement.isLegalPerson" @change="setValue('settlement.isLegalPerson', $event.detail.value)" color="#288bf5" />
- </view>
- <AttachmentCard v-if="form.settlement.accountType === '58'" title="银行卡照片" imgType="BANK_CARD" :items="form.settlement.attachments" @upload="uploadAttachment('settlement', 'BANK_CARD', true)" />
- <template v-if="form.settlement.accountType === '58' && !form.settlement.isLegalPerson">
- <AttachmentCard title="结算人身份证人像面" imgType="ID_CARD_FRONT" :items="form.settlement.attachments" @upload="uploadAttachment('settlement', 'ID_CARD_FRONT', true)" />
- <AttachmentCard title="结算人身份证国徽面" imgType="ID_CARD_BEHIND" :items="form.settlement.attachments" @upload="uploadAttachment('settlement', 'ID_CARD_BEHIND', true)" />
- <AttachmentCard title="法人授权函" imgType="LETTER_OF_AUTHORIZATION" :items="form.settlement.attachments" @upload="uploadAttachment('settlement', 'LETTER_OF_AUTHORIZATION', false)" />
- </template>
- <AttachmentCard v-if="form.settlement.accountType === '57'" title="开户许可证" imgType="OPENING_PERMIT" :items="form.settlement.attachments" @upload="uploadAttachment('settlement', 'OPENING_PERMIT', false)" />
- <view class="box">
- <FormInput label="开户名" v-model="form.settlement.accountName" required />
- <FormInput label="银行卡号" v-model="form.settlement.accountNo" required />
- <FormInput label="开户银行" v-model="form.settlement.bankName" required />
- <view class="form-row">
- <text class="form-label required">开户地区</text>
- <button class="mini-btn" @click="chooseRegion('settlement', 'bank-region')">{{ settlementRegionText }}</button>
- </view>
- <view class="form-row">
- <text class="form-label required">开户支行</text>
- <button class="mini-btn" @click="chooseBank">{{ settlementBranchText }}</button>
- </view>
- <FormInput v-if="!form.settlement.isLegalPerson" label="结算人身份证号" v-model="form.settlement.accountIdNo" />
- <DateInput v-if="!form.settlement.isLegalPerson" label="结算人证件起始日" v-model="form.settlement.accountIdStart" />
- <DateInput v-if="!form.settlement.isLegalPerson" label="结算人证件有效期" v-model="form.settlement.accountIdEnd" />
- </view>
- </view>
- <view v-if="currentStep === 4 && mode !== 'settlement-change'">
- <SectionTitle title="门店信息" />
- <AttachmentCard title="门头照" imgType="SHOP_OUTSIDE_IMG" :items="form.shop.attachments" @upload="uploadAttachment('shop', 'SHOP_OUTSIDE_IMG', false)" />
- <AttachmentCard title="内设照" imgType="SHOP_INSIDE_IMG" :items="form.shop.attachments" @upload="uploadAttachment('shop', 'SHOP_INSIDE_IMG', false)" />
- <AttachmentCard title="收银台照" imgType="CHECKSTAND_IMG" :items="form.shop.attachments" @upload="uploadAttachment('shop', 'CHECKSTAND_IMG', false)" />
- <view class="box">
- <FormInput label="门店名称" v-model="form.shop.name" required />
- <FormInput label="详细地址" v-model="form.shop.address" required />
- <FormInput label="门店联系人" v-model="form.shop.contactName" required />
- <FormInput label="联系手机号" v-model="form.shop.contactMobile" required />
- <!-- <FormInput label="经度" v-model="form.shop.longitude" required />
- <FormInput label="纬度" v-model="form.shop.latitude" required /> -->
- </view>
- </view>
- <view v-if="currentStep === 5 && mode !== 'settlement-change'">
- <SectionTitle title="业务信息" />
- <view class="box summary">
- <view><text>结算类型</text><text>自动结算</text></view>
- <view><text>结算周期</text><text>D1</text></view>
- <view><text>商户类型</text><text>花店(5992)</text></view>
- <view><text>批发费率</text><text>{{ form.business.rate }}%</text></view>
- </view>
- <view class="box">
- <FormInput label="电子合同签约手机号" v-model="form.business.signMobile" required />
- </view>
- <view class="contract">
- <button class="outline" @click="createContract">生成并签署电子合同</button>
- <button class="outline" @click="checkContract">刷新签约状态</button>
- <text :class="{ signed: contractStatus === 'COMPLETED' }">签约状态:{{ contractStatusText }}</text>
- </view>
- </view>
- <view class="bottom-space"></view>
- <view class="bottom">
- <button v-if="currentStep > 1 && mode !== 'settlement-change'" class="back" @click="previous">上一步</button>
- <button v-if="currentStep < 5 && mode !== 'settlement-change'" class="next" @click="next">下一步</button>
- <button v-else class="next" @click="submit">{{ mode === 'settlement-change' ? '提交申请' : '提交审核' }}</button>
- </view>
- <!-- 省市区/支行等超长列表选择,小程序 showActionSheet 最多 6 项不够用 -->
- <OptionPicker
- :visible="optionPicker.visible"
- :title="optionPicker.title"
- :options="optionPicker.options"
- @select="onOptionPickerSelect"
- @cancel="onOptionPickerCancel"
- />
- </view>
- </template>
- <script>
- import {
- applicationDetail, saveDraft, uploadFile, ocrResult, aliyunOcr, applyContract,
- contractStatus, submitApplication, getOption
- } from "@/api/lakala-account";
- import SectionTitle from "./lakala-components/SectionTitle.vue";
- import FormInput from "./lakala-components/FormInput.vue";
- import DateInput from "./lakala-components/DateInput.vue";
- import AttachmentCard from "./lakala-components/AttachmentCard.vue";
- import OptionPicker from "./lakala-components/OptionPicker.vue";
- export default {
- components: { SectionTitle, FormInput, DateInput, AttachmentCard, OptionPicker },
- data() {
- return {
- id: 0, mode: 'create', loaded: false, currentStep: 1, form: null,
- stepNames: ['执照信息', '商户信息', '结算信息', '门店信息', '业务信息'],
- contractStatus: '', saveTimer: null, saving: false,
- // 通用选项弹层状态,resolve 用于 chooseOption / chooseBank 的 Promise
- optionPicker: { visible: false, title: '', options: [], resolve: null }
- };
- },
- computed: {
- contractStatusText() {
- return { COMPLETED: '已完成', UNDONE: '待签署' }[this.contractStatus] || '未生成';
- },
- merchantRegionText() {
- const m = this.form && this.form.merchant;
- return m && m.countyCode ? `${m.provinceName || ''}${m.cityName || ''}${m.countyName || ''}` : '请选择地区';
- },
- settlementRegionText() {
- const s = this.form && this.form.settlement;
- return s && s.cityCode ? `${s.provinceName || ''}${s.cityName || ''}` : '请选择开户地区';
- },
- /** 已选支行展示名称,未选时提示查询 */
- settlementBranchText() {
- const s = this.form && this.form.settlement;
- if (!s || !s.bankNo) return '查询并选择支行';
- return s.bankName || s.bankNo;
- }
- },
- watch: {
- form: {
- deep: true,
- handler() {
- if (!this.loaded || this.saving) return;
- clearTimeout(this.saveTimer);
- this.saveTimer = setTimeout(() => this.persist(), 800);
- }
- }
- },
- onLoad(option) {
- this.id = Number(option.id || 0);
- this.mode = option.mode || 'create';
- this.load();
- },
- onShow() {
- if (this.loaded && this.contractStatus === 'UNDONE') this.checkContract(false);
- },
- onUnload() {
- clearTimeout(this.saveTimer);
- this.persist();
- },
- methods: {
- init() {
- },
- async load() {
- const res = await applicationDetail({ id: this.id });
- this.form = res.data.formData;
- this.applyDefaultMerchantType();
- this.normalizeFormAttachments();
- this.applyDefaultExpiryDates();
- this.currentStep = this.mode === 'settlement-change' ? 3 : Number(res.data.currentStep || 1);
- this.contractStatus = res.data.contractStatus || '';
- this.loaded = true;
- },
- /** 新建进件默认按企业商户处理;已有草稿或详情值不覆盖 */
- applyDefaultMerchantType() {
- if (!this.form.license.merchantType) {
- this.$set(this.form.license, 'merchantType', 'TP_MERCHANT');
- }
- },
- /** 返回当天日期 yyyy-MM-dd,供 date picker 默认值使用 */
- getTodayDateStr() {
- const d = new Date();
- const pad = n => (n < 10 ? '0' : '') + n;
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
- },
- /** 执照/身份证有效期未填时默认当天,减少用户重复选择 */
- applyDefaultExpiryDates() {
- const today = this.getTodayDateStr();
- if (!this.form.license.legalIdEnd || this.form.license.legalIdEnd == '9999-12-31') {
- this.$set(this.form.license, 'legalIdEnd', today);
- }
- if (!this.form.license.licenseEnd || this.form.license.licenseEnd == '9999-12-31') {
- this.$set(this.form.license, 'licenseEnd', today);
- }
- },
- async persist() {
- if (!this.form || this.saving) return;
- this.saving = true;
- try {
- await saveDraft({ id: this.id, currentStep: this.currentStep, formData: JSON.stringify(this.form) });
- } catch (e) {
- // Submitted applications are intentionally no longer editable.
- } finally {
- this.saving = false;
- }
- },
- setValue(path, value) {
- const parts = path.split('.');
- this.$set(this.form[parts[0]], parts[1], value);
- },
- async chooseRegion(section, type) {
- const province = await this.chooseOption(type, '1', '选择省份');
- if (!province) return;
- const city = await this.chooseOption(type, province.code, '选择城市');
- if (!city) return;
- this.$set(this.form[section], 'provinceCode', province.code);
- this.$set(this.form[section], 'provinceName', province.name);
- this.$set(this.form[section], 'cityCode', city.code);
- this.$set(this.form[section], 'cityName', city.name);
- if (section === 'merchant') {
- const county = await this.chooseOption(type, city.code, '选择区县');
- if (county) {
- this.$set(this.form.merchant, 'countyCode', county.code);
- this.$set(this.form.merchant, 'countyName', county.name);
- }
- }
- },
- async chooseOption(type, parentCode, title) {
- const res = await getOption({ type, parentCode });
- const list = this.normalizeOptions(res.data);
- if (!list.length) {
- uni.showToast({ title: '没有可选数据', icon: 'none' });
- return null;
- }
- return this.openOptionPicker(title, list);
- },
- /** 打开可滚动选项弹层,返回选中项或 null */
- openOptionPicker(title, options) {
- return new Promise(resolve => {
- this.optionPicker = { visible: true, title, options, resolve };
- });
- },
- onOptionPickerSelect(item) {
- const { resolve } = this.optionPicker;
- this.optionPicker.visible = false;
- this.optionPicker.resolve = null;
- if (resolve) resolve(item);
- },
- onOptionPickerCancel() {
- const { resolve } = this.optionPicker;
- this.optionPicker.visible = false;
- this.optionPicker.resolve = null;
- if (resolve) resolve(null);
- },
- /** OCR/接口日期统一为 yyyy-MM-dd,供 date picker 使用 */
- normalizeDateStr(value) {
- if (!value) return value;
- const str = String(value).trim();
- if (/^\d{4}-\d{2}-\d{2}$/.test(str)) return str;
- const cn = str.match(/^(\d{4})年(\d{1,2})月(\d{1,2})日$/);
- if (cn) {
- const pad = n => (n < 10 ? '0' : '') + Number(n);
- return `${cn[1]}-${pad(cn[2])}-${pad(cn[3])}`;
- }
- const dot = str.match(/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/);
- if (dot) {
- const pad = n => (n < 10 ? '0' : '') + Number(n);
- return `${dot[1]}-${pad(dot[2])}-${pad(dot[3])}`;
- }
- return str;
- },
- /** 统一省市区、支行等选项结构;兼容 camelCase 与 snake_case 字段 */
- normalizeOptions(data) {
- const source = Array.isArray(data) ? data : ((data && data.data) || []);
- return source.map(v => ({
- code: String(
- v.code
- || v.branch_bank_no
- || v.area_code || v.bank_no || v.id || ''
- ),
- name: v.name || v.area_name
- || v.branch_bank_name
- || v.bank_name || '',
- raw: v
- })).filter(v => v.code && v.name);
- },
- async chooseBank() {
- if (!this.form.settlement.cityCode) { //|| !this.form.settlement.bankName
- uni.showToast({ title: '请先选择开户地区', icon: 'none' }); //并填写银行名称
- return;
- }
- const res = await getOption({ type: 'bank', parentCode: this.form.settlement.cityCode, keyword: this.form.settlement.bankName });
- const list = this.normalizeOptions(res.data);
- if (!list.length) {
- uni.showToast({ title: '没有查询到支行', icon: 'none' });
- return;
- }
- const selected = await this.openOptionPicker('选择开户支行', list);
- if (!selected) return;
- const row = selected.raw || selected;
- this.$set(this.form.settlement, 'bankName', row.branch_bank_name);
- // bankNo 取支行联行号,不能用 bank_no(仅为银行类别码,如 102)
- this.$set(this.form.settlement, 'bankNo', String(row.branch_bank_no || ''));
- this.$set(this.form.settlement, 'clearingBankNo', String(row.clear_no || ''));
- },
- goStep(step) {
- if (step < this.currentStep) {
- this.currentStep = step;
- this.persist();
- }
- },
- previous() { this.currentStep--; this.persist(); },
- next() {
- if (!this.validateStep(this.currentStep)) return;
- if (this.currentStep === 3) {
- this.form.shop.name = this.form.merchant.businessName;
- this.form.shop.address = this.form.merchant.address;
- this.form.shop.provinceCode = this.form.merchant.provinceCode;
- this.form.shop.cityCode = this.form.merchant.cityCode;
- this.form.shop.countyCode = this.form.merchant.countyCode;
- this.form.shop.provinceName = this.form.merchant.provinceName;
- this.form.shop.cityName = this.form.merchant.cityName;
- this.form.shop.countyName = this.form.merchant.countyName;
- }
- this.currentStep++;
- this.persist();
- },
- validateStep(step) {
- const required = {
- 1: ['license.legalName', 'license.legalIdNo', 'license.legalIdStart', 'license.legalIdEnd'],
- 2: ['merchant.businessName', 'merchant.provinceCode', 'merchant.cityCode', 'merchant.countyCode', 'merchant.address'],
- 3: ['settlement.accountName', 'settlement.accountNo', 'settlement.bankName', 'settlement.bankNo', 'settlement.clearingBankNo', 'settlement.provinceCode', 'settlement.cityCode'],
- 4: ['shop.name', 'shop.address', 'shop.contactName', 'shop.contactMobile', 'shop.longitude', 'shop.latitude'],
- 5: ['business.signMobile']
- }[step] || [];
- // 经营范围仅企业商户必填(小微无营业执照,无此字段)
- if (step === 1 && this.form.license.merchantType === 'TP_MERCHANT') {
- required.push('license.businessContent');
- }
- const missing = required.some(path => {
- const [section, field] = path.split('.');
- return !this.form[section][field];
- });
- if (missing) uni.showToast({ title: '请填写完整必填信息', icon: 'none' });
- return !missing;
- },
- async uploadAttachment(section, imgType, isOcr) {
- const path = await this.chooseImage();
- if (!path) return;
- uni.showLoading({ title: '上传识别中', mask: true });
- try {
- const content = await this.toBase64(path);
- const useLakalaOcr = isOcr && imgType === 'BUSINESS_LICENCE';
- const res = await uploadFile({ id: this.id, content, imgType, isOcr: useLakalaOcr ? 1 : 0 });
- const list = this.form[section].attachments || [];
- const attachment = this.normalizeAttachment(res.data);
- const oldIndex = list.findIndex(v => v.imgType === imgType);
- if (oldIndex >= 0) list.splice(oldIndex, 1, attachment); else list.push(attachment);
- this.$set(this.form[section], 'attachments', list);
- if (isOcr && (attachment.batchNo || attachment.ossPath || attachment.lakalaUrl || attachment.url)) {
- await this.pollOcr(section, attachment, 0);
- }
- await this.persist();
- } finally {
- uni.hideLoading();
- }
- },
- normalizeAttachment(attachment) {
- return Object.assign({}, attachment, {
- lakalaUrl: attachment.lakalaUrl || attachment.url || '',
- batchNo: attachment.batchNo || '',
- imgType: attachment.imgType || '',
- ocrStatus: attachment.ocrStatus || attachment.status || '',
- ocrResult: attachment.ocrResult || attachment.ocr || null
- });
- },
- normalizeFormAttachments() {
- ['license', 'settlement', 'shop'].forEach(section => {
- const list = (this.form[section] && this.form[section].attachments) || [];
- this.$set(this.form[section], 'attachments', list.map(item => this.normalizeAttachment(item)));
- });
- },
- chooseImage() {
- return new Promise(resolve => {
- uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: res => resolve(res.tempFilePaths[0]), fail: () => resolve('') });
- });
- },
- toBase64(path) {
- // #ifdef MP-WEIXIN
- return new Promise((resolve, reject) => uni.getFileSystemManager().readFile({ filePath: path, encoding: 'base64', success: res => resolve('data:image/png;base64,' + res.data), fail: reject }));
- // #endif
- // #ifdef H5
- return fetch(path).then(r => r.blob()).then(blob => new Promise(resolve => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }));
- // #endif
- // #ifdef APP-PLUS
- return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL(path, entry => { entry.file(file => { const reader = new plus.io.FileReader(); reader.onloadend = e => resolve(e.target.result); reader.onerror = reject; reader.readAsDataURL(file); }); }, reject); });
- // #endif
- },
- async pollOcr(section, attachment, count) {
- if (count > 8) return;
- const type = attachment.imgType;
- if (type === 'BUSINESS_LICENCE') {
- const res = await ocrResult({ id: this.id, batchNo: attachment.batchNo, imgType: attachment.imgType });
- this.updateAttachment(section, attachment.imgType, {
- ocrStatus: res.data.status || '',
- ocrResult: res.data.result || null
- });
- if (res.data.status === '01') {
- await new Promise(resolve => setTimeout(resolve, 1200));
- return this.pollOcr(section, attachment, count + 1);
- }
- if (res.data.status === '00' && res.data.result) this.applyOcr(section, attachment.imgType, res.data.result);
- } else {
- const imageUrl = attachment.ossPath || attachment.lakalaUrl || attachment.url || '';
- if (!imageUrl) return;
- const res = await aliyunOcr({ id: this.id, imgType: attachment.imgType, imageUrl });
- this.updateAttachment(section, attachment.imgType, {
- ocrStatus: res.data.status || '',
- ocrResult: res.data.result || null
- });
- if (res.data.status === '00' && res.data.result) this.applyOcr(section, attachment.imgType, res.data.result);
- }
- },
- updateAttachment(section, imgType, patch) {
- const list = this.form[section].attachments || [];
- const index = list.findIndex(v => v.imgType === imgType);
- if (index < 0) return;
- this.$set(list, index, Object.assign({}, list[index], patch));
- this.$set(this.form[section], 'attachments', list);
- },
- applyOcr(section, type, result) {
- if (type === 'BUSINESS_LICENCE') {
- Object.assign(this.form.license, {
- licenseName: result.biz_license_address[1] || '',
- licenseNo: result.biz_license_credit_code || result.biz_license_registration_code || this.form.license.licenseNo,
- registeredAddress: result.biz_license_address || this.form.license.registeredAddress,
- businessContent: result.biz_license_scope || this.form.license.businessContent,
- legalName: result.biz_license_owner_name || this.form.license.legalName,
- licenseStart: this.normalizeDateStr(result.biz_license_start_time) || this.form.license.licenseStart
- });
- if (!this.form.merchant.address) this.$set(this.form.merchant, 'address', result.biz_license_address || '');
- } else if (type === 'ID_CARD_FRONT') {
- const target = section === 'license' ? this.form.license : this.form.settlement;
- this.$set(target, section === 'license' ? 'legalName' : 'accountName', result.name || target.accountName || '');
- this.$set(target, section === 'license' ? 'legalIdNo' : 'accountIdNo', result.id_number || '');
- } else if (type === 'ID_CARD_BEHIND') {
- const validity = String(result.validity || '').split('-');
- const target = section === 'license' ? this.form.license : this.form.settlement;
- if (validity.length >= 2) {
- this.$set(target, section === 'license' ? 'legalIdStart' : 'accountIdStart', this.normalizeDateStr(validity[0]));
- this.$set(target, section === 'license' ? 'legalIdEnd' : 'accountIdEnd', this.normalizeDateStr(validity.slice(1).join('-')));
- }
- } else if (type === 'BANK_CARD') {
- this.$set(this.form.settlement, 'accountNo', result.card_number || result.bank_card_number || this.form.settlement.accountNo);
- this.$set(this.form.settlement, 'bankName', result.bank_name || this.form.settlement.bankName);
- }
- },
- async createContract() {
- if (!this.validateStep(5)) return;
- await this.persist();
- const res = await applyContract({ id: this.id });
- this.contractStatus = res.data.status;
- uni.navigateTo({ url: `/common/webview?url=${encodeURIComponent(res.data.resultUrl)}` });
- },
- async checkContract(show = true) {
- if (!this.contractStatus) {
- if (show) uni.showToast({ title: '请先生成电子合同', icon: 'none' });
- return;
- }
- const res = await contractStatus({ id: this.id });
- this.contractStatus = res.data.status;
- if (show) uni.showToast({ title: this.contractStatusText, icon: 'none' });
- },
- async submit() {
- if (!this.validateStep(this.currentStep)) return;
- await this.persist();
- const res = await submitApplication({ id: this.id, formData: JSON.stringify(this.form) });
- uni.showToast({ title: this.mode === 'settlement-change' ? '申请已提交' : '已提交后台审核', icon: 'none' });
- setTimeout(() => uni.navigateBack(), 1000);
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .page { min-height: 100vh; background: #f5f7fa; padding-bottom: 30upx; font-size: 28upx; }
- .steps { display: flex; background: #fff; padding: 30upx 12upx; border-radius: 0 0 28upx 28upx; }
- .step { flex: 1; text-align: center; color: #999; font-size: 27.5upx; position: relative; }
- .step:not(:last-child):before { content: ''; position: absolute; height: 4upx; background: #d8e8fa; top: 25upx; left: 60%; right: -40%; }
- .step.active:not(:last-child):before { background: #288bf5; }
- .circle { width: 52upx; height: 52upx; line-height: 52upx; border-radius: 50%; background: #d8e8fa; color: #fff; margin: 0 auto 12upx; position: relative; z-index: 1; }
- .active { color: #222; }.active .circle { background: #288bf5; }
- .box { margin: 0 24upx 24upx; padding: 24upx; background: #fff; border-radius: 18upx; }
- .choice-row, .switch-row { display: flex; justify-content: space-between; align-items: center; }
- .choice-row label { margin-left: 26upx; font-size: 28upx; }
- .label, .form-label { color: #34445c; }
- .required:before { content: '*'; color: #f33; margin-right: 6upx; }
- .form-row { min-height: 88upx; display: flex; align-items: center; border-bottom: 1upx solid #eee; }
- .form-label { width: 270upx; flex-shrink: 0; }
- .mini-btn { flex: 1; margin: 0; padding: 0 12upx; background: #fff; color: #288bf5; font-size: 32.5upx; line-height: 64upx; text-align: right; }
- .tip { margin: 20upx 30upx; color: #999; font-size: 35upx; line-height: 52.5upx; }
- .summary view { display: flex; justify-content: space-between; font-size: 35upx; line-height: 87.5upx; border-bottom: 1upx solid #eee; }
- .contract { margin: 24upx; display: flex; flex-direction: column; gap: 18upx; text-align: center; color: #999; font-size: 35upx; }
- .signed { color: #079b52; }
- .bottom-space { height: 150upx; }
- .bottom { position: fixed; left: 0; right: 0; bottom: 0; display: flex; gap: 18upx; padding: 20upx 28upx calc(20upx + env(safe-area-inset-bottom)); background: #fff; }
- .bottom button { flex: 1; border-radius: 50upx; font-size: 35upx; }
- .next { color: #fff; background: #288bf5; }.back, .outline { color: #288bf5; background: #fff; border: 1upx solid #288bf5; }
- </style>
|