|
|
@@ -0,0 +1,750 @@
|
|
|
+<template>
|
|
|
+ <!-- 拉卡拉进件审核页:用于平台人员查看商户入网资料并执行驳回或提交审核。 -->
|
|
|
+ <div class="app-list-content lakala-page">
|
|
|
+ <div class="toolbar">
|
|
|
+ <el-select v-model="query.status" size="small" placeholder="状态" @change="load">
|
|
|
+ <el-option label="全部" value="-1"></el-option>
|
|
|
+ <el-option label="后台审核" value="PLATFORM_AUDIT"></el-option>
|
|
|
+ <el-option label="待拉卡拉审核" value="WAIT_AUDIT"></el-option>
|
|
|
+ <el-option label="已驳回" value="REJECT"></el-option>
|
|
|
+ <el-option label="认证通过" value="APPROVED"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ v-model="query.keyWord"
|
|
|
+ size="small"
|
|
|
+ clearable
|
|
|
+ placeholder="申请ID/商户名称"
|
|
|
+ class="keyword"
|
|
|
+ @keyup.enter.native="load"
|
|
|
+ ></el-input>
|
|
|
+ <el-button type="primary" size="small" @click="load">查询</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="list" border stripe v-loading="loading">
|
|
|
+ <el-table-column prop="id" label="ID" width="90" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="mainId" label="mainId" width="100" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="shopId" label="shopId" width="100" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="merchantName" label="商户经营名称" min-width="180"></el-table-column>
|
|
|
+ <el-table-column prop="legalName" label="法人/姓名" min-width="120"></el-table-column>
|
|
|
+ <el-table-column prop="accountName" label="收款人" min-width="120"></el-table-column>
|
|
|
+ <el-table-column prop="status" label="状态" width="130" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag :type="statusTag(scope.row.status)">{{ statusText(scope.row.status) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="updateTime" label="更新时间" width="170" align="center"></el-table-column>
|
|
|
+ <el-table-column label="操作" width="170" fixed="right" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button type="text" size="mini" @click="openDetail(scope.row.id)">详情</el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="scope.row.status === 'PLATFORM_AUDIT'"
|
|
|
+ type="text"
|
|
|
+ size="mini"
|
|
|
+ @click="approve(scope.row)"
|
|
|
+ >提交审核</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div class="pager">
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ layout="prev, pager, next, total"
|
|
|
+ :current-page="query.page"
|
|
|
+ :page-size="query.pageSize"
|
|
|
+ :total="total"
|
|
|
+ @current-change="pageChange"
|
|
|
+ ></el-pagination>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ title="商户入网信息"
|
|
|
+ :visible.sync="detailVisible"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ width="72%"
|
|
|
+ top="30px"
|
|
|
+ class="detail-dialog"
|
|
|
+ >
|
|
|
+ <div class="detail-body">
|
|
|
+ <section-card title="基本信息">
|
|
|
+ <info-row label="营业执照" sub-label="上传营业执照" required class="info-row--full info-row--license">
|
|
|
+ <file-box
|
|
|
+ :file="attachment('license', 'BUSINESS_LICENCE')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.BUSINESS_LICENCE"
|
|
|
+ @upload="uploadAttachment('license', 'BUSINESS_LICENCE', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="营业执照名称" required editable :value="license.licenseName" @input="setField('license.licenseName', $event)"></info-row>
|
|
|
+ <info-row label="执照起始日期" required editable type="date" :value="license.licenseStart" @input="setField('license.licenseStart', $event)"></info-row>
|
|
|
+ <info-row label="证件代码" required editable :value="license.licenseNo" @input="setField('license.licenseNo', $event)"></info-row>
|
|
|
+ <info-row label="执照有效期" required editable :value="license.licenseEnd" @input="setField('license.licenseEnd', $event)"></info-row>
|
|
|
+ <info-row label="注册地址" editable :value="license.registeredAddress[0]" @input="setField('license.registeredAddress[0]', $event)"></info-row>
|
|
|
+ </section-card>
|
|
|
+
|
|
|
+ <section-card title="法人基本信息">
|
|
|
+ <info-row label="证件类型" required value="身份证" suffix-icon="el-icon-arrow-down"></info-row>
|
|
|
+ <info-row label="证件号码" required editable :value="license.legalIdNo" @input="setField('license.legalIdNo', $event)"></info-row>
|
|
|
+ <info-row label="人像面" sub-label="上传身份证人像面" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('license', 'ID_CARD_FRONT')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ variant="id-front"
|
|
|
+ :loading="uploading.ID_CARD_FRONT"
|
|
|
+ @upload="uploadAttachment('license', 'ID_CARD_FRONT', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="国徽面" sub-label="上传身份证国徽面" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('license', 'ID_CARD_BEHIND')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ variant="id-back"
|
|
|
+ :loading="uploading.ID_CARD_BEHIND"
|
|
|
+ @upload="uploadAttachment('license', 'ID_CARD_BEHIND', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="法人姓名" required editable :value="license.legalName" @input="setField('license.legalName', $event)"></info-row>
|
|
|
+ <!-- 身份证日期沿用接口 yyyyMMdd 格式,日期控件按同一格式解析和回传。 -->
|
|
|
+ <info-row label="身份证起始日期" required editable type="date" date-value-format="yyyyMMdd" :value="license.legalIdStart" @input="setField('license.legalIdStart', $event)"></info-row>
|
|
|
+ <info-row label="身份证号" required editable :value="license.legalIdNo" @input="setField('license.legalIdNo', $event)"></info-row>
|
|
|
+ <info-row label="身份证有效期" required editable type="date" date-value-format="yyyyMMdd" :value="license.legalIdEnd" @input="setField('license.legalIdEnd', $event)"></info-row>
|
|
|
+ </section-card>
|
|
|
+
|
|
|
+ <section-card title="商户信息">
|
|
|
+ <info-row label="商户经营名称" required editable :value="merchant.businessName" @input="setField('merchant.businessName', $event)"></info-row>
|
|
|
+ <info-row label="商户所在地区" required :value="regionText(merchant)" @input="setRegionName('merchant', $event)"></info-row>
|
|
|
+ <info-row label="详细地址" required editable :value="merchant.address" @input="setField('merchant.address', $event)"></info-row>
|
|
|
+ <info-row label="联系人姓名" editable :value="merchant.contactName" @input="setField('merchant.contactName', $event)"></info-row>
|
|
|
+ <info-row label="手机号码" editable :value="merchant.contactMobile" @input="setField('merchant.contactMobile', $event)"></info-row>
|
|
|
+ <info-row label="邮箱" editable :value="merchant.email" @input="setField('merchant.email', $event)"></info-row>
|
|
|
+ </section-card>
|
|
|
+
|
|
|
+ <section-card title="结算信息">
|
|
|
+ <info-row label="账户类型" required editable type="select" :value="settlement.accountType" :options="accountTypeOptions" @input="setField('settlement.accountType', $event)"></info-row>
|
|
|
+ <info-row label="开户名" required editable :value="settlement.accountName" @input="setField('settlement.accountName', $event)"></info-row>
|
|
|
+ <info-row label="银行卡号" required editable :value="settlement.accountNo" @input="setField('settlement.accountNo', $event)"></info-row>
|
|
|
+ <info-row label="开户银行" required :value="settlement.bankName" @input="setField('settlement.bankName', $event)"></info-row>
|
|
|
+ <info-row label="开户地区" required :value="regionText(settlement)" @input="setRegionName('settlement', $event)"></info-row>
|
|
|
+ <!-- <info-row label="开户支行" required editable :value="settlement.bankNo" @input="setField('settlement.bankNo', $event)"></info-row> -->
|
|
|
+ <info-row label="银行卡照片" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('settlement', 'BANK_CARD')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.BANK_CARD"
|
|
|
+ @upload="uploadAttachment('settlement', 'BANK_CARD', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <!-- <info-row label="开户许可证">
|
|
|
+ <file-box
|
|
|
+ :file="attachment('settlement', 'OPENING_PERMIT')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.OPENING_PERMIT"
|
|
|
+ @upload="uploadAttachment('settlement', 'OPENING_PERMIT', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row> -->
|
|
|
+ </section-card>
|
|
|
+
|
|
|
+ <section-card title="门店信息">
|
|
|
+ <info-row label="门头照" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('shop', 'SHOP_OUTSIDE_IMG')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.SHOP_OUTSIDE_IMG"
|
|
|
+ @upload="uploadAttachment('shop', 'SHOP_OUTSIDE_IMG', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="内设照" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('shop', 'SHOP_INSIDE_IMG')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.SHOP_INSIDE_IMG"
|
|
|
+ @upload="uploadAttachment('shop', 'SHOP_INSIDE_IMG', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="收银台照" required>
|
|
|
+ <file-box
|
|
|
+ :file="attachment('shop', 'CHECKSTAND_IMG')"
|
|
|
+ text="点击上传或拖拽文件"
|
|
|
+ :loading="uploading.CHECKSTAND_IMG"
|
|
|
+ @upload="uploadAttachment('shop', 'CHECKSTAND_IMG', $event)"
|
|
|
+ ></file-box>
|
|
|
+ </info-row>
|
|
|
+ <info-row label="门店名称" required editable :value="shop.name" @input="setField('shop.name', $event)"></info-row>
|
|
|
+ <info-row label="门店地址" required :value="regionText(shop)" @input="setRegionName('shop', $event)"></info-row>
|
|
|
+ <info-row label="详细地址" required editable :value="shop.address" @input="setField('shop.address', $event)"></info-row>
|
|
|
+ <info-row label="门店联系人" required editable :value="shop.contactName" @input="setField('shop.contactName', $event)"></info-row>
|
|
|
+ <info-row label="联系手机号" required editable :value="shop.contactMobile" @input="setField('shop.contactMobile', $event)"></info-row>
|
|
|
+ </section-card>
|
|
|
+
|
|
|
+ <section-card title="业务信息">
|
|
|
+ <info-row label="结算类型" value="自动结算"></info-row>
|
|
|
+ <info-row label="结算周期" value="D1"></info-row>
|
|
|
+ <info-row label="批发费率" :value="business.rate || '0.33'" @input="setField('business.rate', $event)"></info-row>
|
|
|
+ <info-row label="电子合同签约手机号" required editable :value="business.signMobile" @input="setField('business.signMobile', $event)"></info-row>
|
|
|
+ <!-- <info-row label="合同状态" :value="detail.contractStatus"></info-row> -->
|
|
|
+ <info-row label="合同编号" :value="detail.contractNo"></info-row>
|
|
|
+ </section-card>
|
|
|
+ </div>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button class="footer-btn" icon="el-icon-arrow-left" @click="detailVisible = false">返回</el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="detail.status === 'PLATFORM_AUDIT'"
|
|
|
+ class="footer-btn"
|
|
|
+ icon="el-icon-document-delete"
|
|
|
+ @click="openRejectDialog(detail)"
|
|
|
+ >驳回</el-button>
|
|
|
+ <el-button
|
|
|
+ class="footer-btn"
|
|
|
+ type="primary"
|
|
|
+ plain
|
|
|
+ icon="el-icon-document-checked"
|
|
|
+ :loading="saving"
|
|
|
+ @click="saveDetail"
|
|
|
+ >保存修改</el-button>
|
|
|
+ <el-button
|
|
|
+ class="footer-btn"
|
|
|
+ type="primary"
|
|
|
+ icon="el-icon-s-promotion"
|
|
|
+ :disabled="detail.status !== 'PLATFORM_AUDIT'"
|
|
|
+ @click="approveDetail"
|
|
|
+ >提交审核</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ title="驳回原因"
|
|
|
+ :visible.sync="rejectVisible"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ width="670px"
|
|
|
+ top="10vh"
|
|
|
+ class="reject-dialog"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="rejectForm.reason"
|
|
|
+ type="textarea"
|
|
|
+ :rows="9"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ placeholder="请输入驳回原因"
|
|
|
+ class="reject-textarea"
|
|
|
+ ></el-input>
|
|
|
+ <div slot="footer" class="reject-footer">
|
|
|
+ <el-button class="reject-btn" @click="closeRejectDialog">返回</el-button>
|
|
|
+ <el-button class="reject-btn" type="primary" :loading="rejecting" @click="submitReject">驳回</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+// 分组卡片:保持弹窗资料区的标题条、分割线和内容容器一致。
|
|
|
+const SectionCard = {
|
|
|
+ props: ['title'],
|
|
|
+ render(h) {
|
|
|
+ return h('div', { class: 'section-card' }, [
|
|
|
+ h('div', { class: 'section-title' }, [
|
|
|
+ h('span'),
|
|
|
+ this.title
|
|
|
+ ]),
|
|
|
+ h('div', { class: 'section-content' }, this.$slots.default)
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 信息行:展示及编辑接口字段,日期控件可按业务字段指定解析和回传格式。
|
|
|
+const InfoRow = {
|
|
|
+ props: {
|
|
|
+ label: String,
|
|
|
+ value: [String, Number],
|
|
|
+ required: Boolean,
|
|
|
+ subLabel: String,
|
|
|
+ suffixIcon: String,
|
|
|
+ editable: Boolean,
|
|
|
+ type: String,
|
|
|
+ dateValueFormat: String,
|
|
|
+ options: {
|
|
|
+ type: Array,
|
|
|
+ default() {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render(h) {
|
|
|
+ const labelChildren = [];
|
|
|
+ if (this.required) {
|
|
|
+ labelChildren.push(h('i', '*'));
|
|
|
+ }
|
|
|
+ labelChildren.push(this.label);
|
|
|
+ if (this.subLabel) {
|
|
|
+ labelChildren.push(h('small', [
|
|
|
+ h('em', '·'),
|
|
|
+ this.subLabel
|
|
|
+ ]));
|
|
|
+ }
|
|
|
+ let content = this.$slots.default || [
|
|
|
+ h('span', { class: 'info-value-text' }, this.value || '-'),
|
|
|
+ this.suffixIcon ? h('i', { class: ['info-suffix', this.suffixIcon] }) : null
|
|
|
+ ];
|
|
|
+ if (!this.$slots.default && this.editable) {
|
|
|
+ if (this.type === 'date') {
|
|
|
+ content = [h('el-date-picker', {
|
|
|
+ class: 'info-control',
|
|
|
+ props: {
|
|
|
+ value: this.value || '',
|
|
|
+ type: 'date',
|
|
|
+ valueFormat: this.dateValueFormat || 'yyyy-MM-dd',
|
|
|
+ placeholder: '请选择'
|
|
|
+ },
|
|
|
+ on: { input: value => this.$emit('input', value) }
|
|
|
+ })];
|
|
|
+ } else if (this.type === 'select') {
|
|
|
+ content = [h('el-select', {
|
|
|
+ class: 'info-control',
|
|
|
+ props: { value: this.value || '', placeholder: '请选择' },
|
|
|
+ on: { input: value => this.$emit('input', value) }
|
|
|
+ }, this.options.map(item => h('el-option', {
|
|
|
+ props: { label: item.label, value: item.value }
|
|
|
+ })))];
|
|
|
+ } else {
|
|
|
+ content = [h('el-input', {
|
|
|
+ class: 'info-control',
|
|
|
+ props: { value: this.value || '', placeholder: '请输入' },
|
|
|
+ on: { input: value => this.$emit('input', value) }
|
|
|
+ })];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return h('div', { class: 'info-row' }, [
|
|
|
+ h('div', { class: 'info-label' }, labelChildren),
|
|
|
+ h('div', { class: [
|
|
|
+ 'info-value',
|
|
|
+ this.$slots.default ? 'info-value-file' : 'info-value-input'
|
|
|
+ ] }, content)
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 附件展示:有真实附件时可点击预览,没有附件时按入网资料上传框样式展示占位。
|
|
|
+const FileBox = {
|
|
|
+ props: ['file', 'text', 'variant', 'loading'],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ previewVisible: false
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 图片地址:附件展示优先使用后端返回的 ossPath,兼容历史字段作为兜底。
|
|
|
+ url() {
|
|
|
+ return this.file && (this.file.ossPath || this.file.ossUrl || this.file.url);
|
|
|
+ },
|
|
|
+ // 图片判断:只对常见图片类型启用弹窗预览,非图片仍按文件链接打开。
|
|
|
+ isImage() {
|
|
|
+ return /\.(png|jpe?g|webp|gif)(\?.*)?$/i.test(this.url || '');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 选择文件:触发隐藏 input,保持上传入口和原有业务流程一致。
|
|
|
+ chooseFile() {
|
|
|
+ const input = this.$refs.fileInput;
|
|
|
+ if (input) input.click();
|
|
|
+ },
|
|
|
+ // 上传变更:把浏览器选择的文件交给外层业务上传方法处理。
|
|
|
+ changeFile(event) {
|
|
|
+ const file = event.target.files && event.target.files[0];
|
|
|
+ event.target.value = '';
|
|
|
+ if (file) this.$emit('upload', file);
|
|
|
+ },
|
|
|
+ // 图片预览:已上传图片点击后打开大图弹窗,便于审核人员核对原图细节。
|
|
|
+ openPreview() {
|
|
|
+ if (this.isImage) this.previewVisible = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render(h) {
|
|
|
+ const input = h('input', {
|
|
|
+ ref: 'fileInput',
|
|
|
+ class: 'file-input',
|
|
|
+ attrs: { type: 'file', accept: 'image/jpeg,image/png,image/gif,image/webp' },
|
|
|
+ on: { change: this.changeFile }
|
|
|
+ });
|
|
|
+ if (this.url) {
|
|
|
+ return h('div', { class: 'file-box has-file' }, [
|
|
|
+ this.isImage ? h('img', {
|
|
|
+ class: 'file-preview-thumb',
|
|
|
+ attrs: { src: this.url },
|
|
|
+ on: { click: this.openPreview }
|
|
|
+ }) : h('a', {
|
|
|
+ attrs: { href: this.url, target: '_blank' }
|
|
|
+ }, '查看文件'),
|
|
|
+ h('el-button', {
|
|
|
+ class: 'file-change',
|
|
|
+ props: { type: 'text', loading: this.loading },
|
|
|
+ on: { click: this.chooseFile }
|
|
|
+ }, '更换文件'),
|
|
|
+ this.isImage ? h('el-dialog', {
|
|
|
+ class: 'file-preview-dialog',
|
|
|
+ props: {
|
|
|
+ visible: this.previewVisible,
|
|
|
+ appendToBody: true,
|
|
|
+ width: '70%',
|
|
|
+ top: '30px'
|
|
|
+ },
|
|
|
+ on: {
|
|
|
+ 'update:visible': value => {
|
|
|
+ this.previewVisible = value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [
|
|
|
+ h('img', {
|
|
|
+ class: 'file-preview-full',
|
|
|
+ attrs: { src: this.url }
|
|
|
+ })
|
|
|
+ ]) : null,
|
|
|
+ input
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ const mockCard = this.variant ? h('div', { class: ['mock-card', `mock-card--${this.variant}`] }, [
|
|
|
+ this.variant === 'id-back' ? h('span', { class: 'mock-emblem' }) : null,
|
|
|
+ h('span', { class: 'mock-lines' }),
|
|
|
+ h('span', { class: 'mock-avatar' })
|
|
|
+ ]) : null;
|
|
|
+ return h('div', {
|
|
|
+ class: ['file-box', 'empty-file', this.loading ? 'is-uploading' : ''],
|
|
|
+ on: { click: this.chooseFile }
|
|
|
+ }, [
|
|
|
+ mockCard,
|
|
|
+ h('i', { class: 'el-icon-camera-solid' }),
|
|
|
+ h('div', this.loading ? '上传中...' : (this.text || '点击上传或拖拽文件')),
|
|
|
+ h('small', '支持jpg、png格式,大小不超过10MB'),
|
|
|
+ input
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+function clone(data) {
|
|
|
+ return JSON.parse(JSON.stringify(data || {}));
|
|
|
+}
|
|
|
+
|
|
|
+function defaultForm() {
|
|
|
+ return {
|
|
|
+ license: { attachments: [] },
|
|
|
+ merchant: {},
|
|
|
+ settlement: { attachments: [] },
|
|
|
+ shop: { attachments: [] },
|
|
|
+ business: {}
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function readFileAsDataUrl(file) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = event => resolve(event.target.result);
|
|
|
+ reader.onerror = reject;
|
|
|
+ reader.readAsDataURL(file);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function mergeForm(form) {
|
|
|
+ const base = defaultForm();
|
|
|
+ Object.keys(base).forEach(key => {
|
|
|
+ base[key] = Object.assign(base[key], form[key] || {});
|
|
|
+ if (base[key].attachments && !Array.isArray(base[key].attachments)) {
|
|
|
+ base[key].attachments = [];
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return Object.assign({}, form, base);
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: { SectionCard, InfoRow, FileBox },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ loading: false,
|
|
|
+ list: [],
|
|
|
+ total: 0,
|
|
|
+ query: { page: 1, pageSize: 20, status: 'PLATFORM_AUDIT', keyWord: '' },
|
|
|
+ detailVisible: false,
|
|
|
+ detail: {},
|
|
|
+ editableForm: defaultForm(),
|
|
|
+ saving: false,
|
|
|
+ rejectVisible: false,
|
|
|
+ rejecting: false,
|
|
|
+ rejectForm: { id: '', reason: '' },
|
|
|
+ uploading: {},
|
|
|
+ idTypeOptions: [{ label: '身份证', value: '身份证' }],
|
|
|
+ accountTypeOptions: [
|
|
|
+ { label: '对公', value: '57' },
|
|
|
+ { label: '对私', value: '58' }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ form() {
|
|
|
+ return this.editableForm || {};
|
|
|
+ },
|
|
|
+ license() {
|
|
|
+ return this.form.license || {};
|
|
|
+ },
|
|
|
+ merchant() {
|
|
|
+ return this.form.merchant || {};
|
|
|
+ },
|
|
|
+ settlement() {
|
|
|
+ return this.form.settlement || {};
|
|
|
+ },
|
|
|
+ shop() {
|
|
|
+ return this.form.shop || {};
|
|
|
+ },
|
|
|
+ business() {
|
|
|
+ return this.form.business || {};
|
|
|
+ },
|
|
|
+ identityValidText() {
|
|
|
+ if (!this.license.legalIdEnd) return '-';
|
|
|
+ return this.license.legalIdEnd === '9999-12-31' ? '长期有效' : this.license.legalIdEnd;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.load();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ load() {
|
|
|
+ this.loading = true;
|
|
|
+ this.$service.saasShop.lakalaApplicationList(this.query).then(res => {
|
|
|
+ this.list = res.list || [];
|
|
|
+ this.total = Number(res.totalNum || 0);
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ pageChange(page) {
|
|
|
+ this.query.page = page;
|
|
|
+ this.load();
|
|
|
+ },
|
|
|
+ openDetail(id) {
|
|
|
+ this.$service.saasShop.lakalaApplicationDetail({ id }).then(res => {
|
|
|
+ this.detail = res;
|
|
|
+ this.editableForm = mergeForm(clone(res.formData));
|
|
|
+ this.detailVisible = true;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ setField(path, value) {
|
|
|
+ const keys = path.split('.');
|
|
|
+ let target = this.editableForm;
|
|
|
+ keys.slice(0, -1).forEach(key => {
|
|
|
+ if (!target[key]) this.$set(target, key, {});
|
|
|
+ target = target[key];
|
|
|
+ });
|
|
|
+ this.$set(target, keys[keys.length - 1], value);
|
|
|
+ },
|
|
|
+ setIdentityValid(value) {
|
|
|
+ this.setField('license.legalIdEnd', value === '长期有效' ? '9999-12-31' : value);
|
|
|
+ },
|
|
|
+ setRegionName(section, value) {
|
|
|
+ if (!this.editableForm[section]) this.$set(this.editableForm, section, {});
|
|
|
+ this.$set(this.editableForm[section], 'provinceName', value);
|
|
|
+ this.$set(this.editableForm[section], 'cityName', '');
|
|
|
+ this.$set(this.editableForm[section], 'countyName', '');
|
|
|
+ },
|
|
|
+ saveDetail(showMessage = true) {
|
|
|
+ if (!this.detail.id || this.saving) return Promise.resolve(this.detail);
|
|
|
+ this.saving = true;
|
|
|
+ return this.$service.saasShop.lakalaApplicationSave({
|
|
|
+ id: this.detail.id,
|
|
|
+ currentStep: this.detail.currentStep || 5,
|
|
|
+ formData: this.editableForm
|
|
|
+ }).then(res => {
|
|
|
+ this.detail = res;
|
|
|
+ this.editableForm = mergeForm(clone(res.formData));
|
|
|
+ if (showMessage) this.$message.success('保存成功');
|
|
|
+ this.load();
|
|
|
+ return res;
|
|
|
+ }).finally(() => {
|
|
|
+ this.saving = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ approveDetail() {
|
|
|
+ if (!this.detail || this.detail.status !== 'PLATFORM_AUDIT') return;
|
|
|
+ this.saveDetail(false).then(() => {
|
|
|
+ this.approve(this.detail);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ uploadAttachment(section, imgType, file) {
|
|
|
+ if (!this.detail.id || !file) return;
|
|
|
+ if (!/^image\/(jpeg|png|gif|webp)$/.test(file.type)) {
|
|
|
+ this.$message.error('请上传jpg、png、gif或webp图片');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (file.size > 10 * 1024 * 1024) {
|
|
|
+ this.$message.error('图片大小不能超过10MB');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.$set(this.uploading, imgType, true);
|
|
|
+ readFileAsDataUrl(file).then(content => {
|
|
|
+ return this.$service.saasShop.lakalaApplicationUploadFile({
|
|
|
+ id: this.detail.id,
|
|
|
+ content,
|
|
|
+ imgType,
|
|
|
+ isOcr: 0
|
|
|
+ });
|
|
|
+ }).then(fileInfo => {
|
|
|
+ if (!this.editableForm[section]) this.$set(this.editableForm, section, { attachments: [] });
|
|
|
+ if (!Array.isArray(this.editableForm[section].attachments)) {
|
|
|
+ this.$set(this.editableForm[section], 'attachments', []);
|
|
|
+ }
|
|
|
+ const list = this.editableForm[section].attachments;
|
|
|
+ const index = list.findIndex(item => item.imgType === imgType);
|
|
|
+ if (index >= 0) {
|
|
|
+ this.$set(list, index, fileInfo);
|
|
|
+ } else {
|
|
|
+ list.push(fileInfo);
|
|
|
+ }
|
|
|
+ this.$message.success('上传成功,请点击保存修改');
|
|
|
+ }).finally(() => {
|
|
|
+ this.$set(this.uploading, imgType, false);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ approve(row) {
|
|
|
+ if (!row || row.status !== 'PLATFORM_AUDIT') return;
|
|
|
+ this.$confirm('确认审核通过并提交到拉卡拉?', '提交审核', { type: 'warning' }).then(() => {
|
|
|
+ this.$service.saasShop.lakalaApplicationApprove({ id: row.id }).then(() => {
|
|
|
+ this.$message.success('已提交拉卡拉审核');
|
|
|
+ this.detailVisible = false;
|
|
|
+ this.load();
|
|
|
+ });
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ // 打开驳回表单:仅后台审核状态允许驳回,驳回原因会同步给客户侧列表展示。
|
|
|
+ openRejectDialog(row) {
|
|
|
+ if (!row || row.status !== 'PLATFORM_AUDIT') return;
|
|
|
+ this.rejectForm = { id: row.id, reason: '' };
|
|
|
+ this.rejectVisible = true;
|
|
|
+ },
|
|
|
+ // 关闭驳回表单:清理本次填写内容,避免切换申请时误提交上一条原因。
|
|
|
+ closeRejectDialog() {
|
|
|
+ if (this.rejecting) return;
|
|
|
+ this.rejectVisible = false;
|
|
|
+ this.rejectForm = { id: '', reason: '' };
|
|
|
+ },
|
|
|
+ // 提交驳回:校验原因后调用后台驳回接口,客户侧通过 rejectReason 字段展示该内容。
|
|
|
+ submitReject() {
|
|
|
+ const reason = (this.rejectForm.reason || '').trim();
|
|
|
+ if (!this.rejectForm.id) return;
|
|
|
+ if (!reason) {
|
|
|
+ this.$message.warning('请填写驳回原因');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.rejecting = true;
|
|
|
+ this.$service.saasShop.lakalaApplicationReject({
|
|
|
+ id: this.rejectForm.id,
|
|
|
+ reason
|
|
|
+ }).then(() => {
|
|
|
+ this.$message.success('已驳回');
|
|
|
+ this.rejectVisible = false;
|
|
|
+ this.detailVisible = false;
|
|
|
+ this.rejectForm = { id: '', reason: '' };
|
|
|
+ this.load();
|
|
|
+ }).finally(() => {
|
|
|
+ this.rejecting = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ statusText(status) {
|
|
|
+ return {
|
|
|
+ DRAFT: '草稿',
|
|
|
+ CONTRACT_PENDING: '待签约',
|
|
|
+ PLATFORM_AUDIT: '后台审核',
|
|
|
+ WAIT_AUDIT: '拉卡拉审核',
|
|
|
+ REJECT: '已驳回',
|
|
|
+ APPROVED: '认证通过'
|
|
|
+ }[status] || status || '-';
|
|
|
+ },
|
|
|
+ statusTag(status) {
|
|
|
+ return {
|
|
|
+ PLATFORM_AUDIT: 'warning',
|
|
|
+ WAIT_AUDIT: 'primary',
|
|
|
+ REJECT: 'danger',
|
|
|
+ APPROVED: 'success'
|
|
|
+ }[status] || 'info';
|
|
|
+ },
|
|
|
+ regionText(row) {
|
|
|
+ if (!row) return '-';
|
|
|
+ return `${row.provinceName || ''}${row.cityName || ''}${row.countyName || ''}` || '-';
|
|
|
+ },
|
|
|
+ attachment(section, imgType) {
|
|
|
+ const list = (this.form[section] && this.form[section].attachments) || [];
|
|
|
+ return list.find(item => item.imgType === imgType) || null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.lakala-page { padding: 16px; }
|
|
|
+.lakala-page .toolbar { display: flex; align-items: center; margin-bottom: 14px; }
|
|
|
+.lakala-page .keyword { width: 260px; margin: 0 10px; }
|
|
|
+.lakala-page .pager { margin-top: 16px; text-align: right; }
|
|
|
+.detail-dialog .el-dialog { display: flex; flex-direction: column; height: calc(100vh - 4px); max-height: 1086px; margin-top: 2px !important; margin-bottom: 0; border-radius: 8px; overflow: hidden; }
|
|
|
+.detail-dialog .el-dialog__header { flex-shrink: 0; padding: 24px 36px 18px; border-bottom: 0; }
|
|
|
+.detail-dialog .el-dialog__title { font-size: 28px; line-height: 36px; font-weight: 700; color: #111827; }
|
|
|
+.detail-dialog .el-dialog__headerbtn { top: 28px; right: 30px; font-size: 28px; }
|
|
|
+.detail-dialog .el-dialog__body { flex: 1; min-height: 0; padding: 0 30px 10px; overflow-y: auto; background: #fff; }
|
|
|
+.detail-dialog .el-dialog__body::-webkit-scrollbar { width: 10px; }
|
|
|
+.detail-dialog .el-dialog__body::-webkit-scrollbar-track { background: #f6f8fb; border-radius: 8px; }
|
|
|
+.detail-dialog .el-dialog__body::-webkit-scrollbar-thumb { background: #9aa4b5; border-radius: 8px; }
|
|
|
+.detail-dialog .el-dialog__footer { flex-shrink: 0; padding: 24px 36px 28px; border-top: 1px solid #e5e7eb; background: #fff; box-shadow: 0 -4px 14px rgba(15, 23, 42, .03); }
|
|
|
+.detail-dialog .detail-body { padding-bottom: 2px; }
|
|
|
+.detail-dialog .section-card { border: 1px solid #e3e8f0; border-radius: 8px; margin-bottom: 8px; padding: 18px 20px 16px; background: #fff; box-shadow: 0 4px 18px rgba(15, 23, 42, .08); }
|
|
|
+.detail-dialog .section-title { display: flex; align-items: center; font-size: 18px; font-weight: 700; color: #111827; padding: 0 0 15px; border-bottom: 1px solid #e5e7eb; }
|
|
|
+.detail-dialog .section-title span { width: 8px; height: 22px; background: #237bff; border-radius: 3px; margin-right: 12px; }
|
|
|
+.detail-dialog .section-content { display: flex; flex-wrap: wrap; padding-top: 12px; }
|
|
|
+.detail-dialog .info-row { width: 50%; display: flex; align-items: flex-start; min-height: 58px; padding: 8px 12px; box-sizing: border-box; }
|
|
|
+.detail-dialog .info-row--full { width: 100%; }
|
|
|
+.detail-dialog .info-row--license { padding-bottom: 12px; margin-bottom: 8px; border-bottom: 1px solid #edf0f5; }
|
|
|
+.detail-dialog .info-label { width: 220px; flex-shrink: 0; min-height: 40px; line-height: 40px; font-size: 16px; font-weight: 700; color: #111827; }
|
|
|
+.detail-dialog .info-label i { color: #ff1616; font-style: normal; margin-right: 8px; }
|
|
|
+.detail-dialog .info-label small { display: block; padding-left: 15px; margin-top: -7px; line-height: 20px; font-size: 13px; font-weight: 400; color: #6b7280; }
|
|
|
+.detail-dialog .info-label small em { color: #ff1616; font-style: normal; margin-right: 6px; }
|
|
|
+.detail-dialog .info-value { flex: 1; min-width: 0; color: #374151; font-size: 15px; }
|
|
|
+.detail-dialog .info-value-input { display: flex; align-items: center; justify-content: space-between; min-height: 42px; line-height: 40px; padding: 0 14px; border: 1px solid #d8dee9; border-radius: 5px; background: #fff; box-sizing: border-box; color: #374151; overflow: hidden; }
|
|
|
+.detail-dialog .info-control { width: 100%; }
|
|
|
+.detail-dialog .info-control .el-input__inner { height: 40px; line-height: 40px; padding: 0; border: 0; color: #374151; background: transparent; }
|
|
|
+.detail-dialog .info-control .el-input__prefix { display: none; }
|
|
|
+.detail-dialog .info-control .el-input__suffix { right: 0; }
|
|
|
+.detail-dialog .info-control.el-date-editor.el-input { width: 100%; }
|
|
|
+.detail-dialog .info-value-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
|
+.detail-dialog .info-suffix { flex-shrink: 0; margin-left: 10px; color: #6b7280; font-size: 16px; }
|
|
|
+.detail-dialog .info-value-file { min-height: 120px; line-height: normal; }
|
|
|
+.detail-dialog .file-box { position: relative; width: 100%; max-width: 480px; min-height: 126px; border: 1px dashed #2f7df6; border-radius: 5px; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #111827; text-decoration: none; box-sizing: border-box; background: #fff; }
|
|
|
+.detail-dialog .file-box.is-uploading { cursor: wait; opacity: .72; }
|
|
|
+.detail-dialog .file-input { display: none; }
|
|
|
+.detail-dialog .file-preview-thumb { width: auto; height: auto; max-width: 100%; max-height: 220px; display: block; border-radius: 4px; object-fit: contain; cursor: zoom-in; }
|
|
|
+.file-preview-dialog .el-dialog__body { padding: 0 24px 24px; text-align: center; }
|
|
|
+.file-preview-dialog .file-preview-full { width: auto; height: auto; max-width: 100%; max-height: calc(100vh - 150px); display: inline-block; object-fit: contain; }
|
|
|
+.detail-dialog .has-file .file-change { margin-top: 8px; }
|
|
|
+.detail-dialog .empty-file i { width: 64px; height: 64px; line-height: 64px; text-align: center; border-radius: 50%; color: #fff; background: #237bff; font-size: 27px; margin-bottom: 12px; box-shadow: 0 8px 18px rgba(35, 123, 255, .24); z-index: 1; }
|
|
|
+.detail-dialog .empty-file div { font-size: 16px; font-weight: 600; color: #111827; z-index: 1; }
|
|
|
+.detail-dialog .empty-file small { color: #6b7280; margin-top: 10px; font-size: 14px; z-index: 1; }
|
|
|
+.detail-dialog .mock-card { width: 170px; height: 82px; margin-bottom: 10px; border: 1px solid #b7d2ff; border-radius: 4px; background: linear-gradient(135deg, #eef6ff 0%, #dcecff 100%); position: relative; overflow: hidden; }
|
|
|
+.detail-dialog .mock-card--id-front .mock-lines { position: absolute; left: 16px; top: 20px; width: 70px; height: 9px; border-radius: 10px; background: #8bb7fb; box-shadow: 0 22px 0 #a7c7fb; }
|
|
|
+.detail-dialog .mock-card--id-front .mock-avatar { position: absolute; right: 22px; bottom: 13px; width: 48px; height: 50px; border-radius: 22px 22px 6px 6px; background: #8db8fb; }
|
|
|
+.detail-dialog .mock-card--id-back .mock-emblem { position: absolute; left: 18px; top: 12px; width: 42px; height: 42px; border-radius: 50%; background: #ee1d23; border: 4px solid #ffd34d; box-sizing: border-box; }
|
|
|
+.detail-dialog .mock-card--id-back .mock-lines { position: absolute; right: 20px; top: 20px; width: 58px; height: 8px; border-radius: 10px; background: #8bb7fb; box-shadow: 0 20px 0 #8bb7fb, -12px 40px 0 #a7c7fb; }
|
|
|
+.detail-dialog .mock-card--id-back .mock-avatar { display: none; }
|
|
|
+.detail-dialog .mock-card + i { position: absolute; top: 42px; width: 54px; height: 54px; line-height: 54px; font-size: 23px; }
|
|
|
+.detail-dialog .dialog-footer { display: flex; justify-content: center; }
|
|
|
+.detail-dialog .footer-btn { width: 280px; height: 60px; margin: 0 14px; font-size: 22px; border-radius: 5px; }
|
|
|
+.reject-dialog .el-dialog { border: 1px solid #8b8b8b; border-radius: 0; box-shadow: none; }
|
|
|
+.reject-dialog .el-dialog__header { padding: 36px 34px 8px; }
|
|
|
+.reject-dialog .el-dialog__title { font-size: 28px; line-height: 36px; font-weight: 700; color: #333; }
|
|
|
+.reject-dialog .el-dialog__headerbtn { top: 25px; right: 34px; font-size: 28px; }
|
|
|
+.reject-dialog .el-dialog__headerbtn .el-dialog__close { font-weight: 700; color: #333; }
|
|
|
+.reject-dialog .el-dialog__body { padding: 0 34px 20px; }
|
|
|
+.reject-dialog .reject-textarea .el-textarea__inner { height: 272px; min-height: 272px !important; padding: 12px 14px; border: 1px solid #8f8f8f; border-radius: 0; resize: none; font-size: 18px; line-height: 26px; color: #333; }
|
|
|
+.reject-dialog .el-dialog__footer { padding: 0 39px 49px; }
|
|
|
+.reject-dialog .reject-footer { display: flex; justify-content: space-between; }
|
|
|
+.reject-dialog .reject-btn { width: 264px; height: 64px; margin: 0; border: 0; border-radius: 6px; background: #18a8df; color: #fff; font-size: 22px; font-weight: 700; }
|
|
|
+.reject-dialog .reject-btn:hover,
|
|
|
+.reject-dialog .reject-btn:focus { background: #129ed4; color: #fff; }
|
|
|
+.reject-dialog .reject-btn.is-loading { background: #18a8df; }
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .detail-dialog .info-row { width: 100%; }
|
|
|
+ .detail-dialog .info-label { width: 190px; }
|
|
|
+ .detail-dialog .footer-btn { width: 23%; min-width: 150px; margin: 0 6px; }
|
|
|
+}
|
|
|
+</style>
|