| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774 |
- <template>
- <div class="form-container">
- <div>
- <!-- 返回按钮 -->
- <el-button class="back-btn" @click="handleBack"> 返回 </el-button>
- <!-- 进度条 -->
- <div class="progress-container">
- <el-steps :active="currentStep" style="max-width: 1500px" align-center>
- <el-step v-for="(item, index) in entryList" :key="index">
- <template #title>
- <div class="step-title-wrapper">
- <span class="step-title">{{ item.title }}</span>
- </div>
- </template>
- </el-step>
- </el-steps>
- </div>
- </div>
- <!-- 第一步:个人实名 - 身份证正反面上传 -->
- <div v-if="currentStep === 1" class="step1-content">
- <div class="form-content">
- <h3 class="section-title">身份证正反面</h3>
- <div class="id-card-upload-container">
- <!-- 正面 -->
- <div class="upload-item">
- <div class="upload-label">正面</div>
- <el-upload
- v-model:file-list="idCardFrontList"
- :http-request="handleHttpUpload"
- list-type="picture-card"
- :limit="1"
- :on-exceed="handleExceed"
- :on-success="(response, file) => handleUploadSuccess(response, file, 'ID_CARD', '身份证')"
- :on-preview="handlePictureCardPreview"
- :on-remove="handleRemove"
- accept="image/*"
- class="id-card-upload"
- :class="{ 'upload-complete': idCardFrontList.length > 0 }"
- >
- <template v-if="idCardFrontList.length === 0">
- <div class="upload-placeholder">
- <!-- <el-image src="/src/assets/images/idCard1.png" /> -->
- <span class="placeholder-text">身份证正面示例-带有国徽一面</span>
- </div>
- </template>
- </el-upload>
- </div>
- <!-- 反面 -->
- <div class="upload-item">
- <div class="upload-label">反面</div>
- <el-upload
- v-model:file-list="idCardBackList"
- :http-request="handleHttpUpload"
- list-type="picture-card"
- :limit="1"
- :on-exceed="handleExceed"
- :on-success="(response, file) => handleUploadSuccess(response, file, 'ID_CARD', '身份证')"
- :on-preview="handlePictureCardPreview"
- :on-remove="handleRemove"
- accept="image/*"
- class="id-card-upload"
- :class="{ 'upload-complete': idCardBackList.length > 0 }"
- >
- <template v-if="idCardBackList.length === 0">
- <div class="upload-placeholder">
- <span class="placeholder-text">
- <span>身份证反面示例-带有人像一面</span>
- </span>
- </div>
- </template>
- </el-upload>
- </div>
- </div>
- <!-- OCR 识别结果展示 -->
- <div class="ocr-result-container" v-if="isIdCardUploadComplete">
- <div class="ocr-result-item" v-if="isOcrProcessing">
- <span class="label">识别中:</span>
- <span class="value">正在识别身份证信息,请稍候...</span>
- </div>
- <template v-else>
- <div class="ocr-result-item" v-if="ocrResult.name">
- <span class="label">姓名:</span>
- <span class="value">{{ ocrResult.name }}</span>
- </div>
- <div class="ocr-result-item" v-if="ocrResult.idCard">
- <span class="label">身份证号:</span>
- <span class="value">{{ ocrResult.idCard }}</span>
- </div>
- <div class="ocr-result-tip" v-if="!ocrResult.name && !ocrResult.idCard">请等待身份证识别完成</div>
- </template>
- </div>
- </div>
- <!-- 按钮 -->
- <div class="form-actions">
- <el-button type="primary" size="large" @click="handleNextStep"> 下一步 </el-button>
- </div>
- </div>
- <!-- 第二步:填写信息 -->
- <div v-if="currentStep === 2">
- <!-- 表单内容 -->
- <div class="form-content step2-form">
- <el-form :model="step2Form" :rules="step2Rules" ref="step2FormRef" label-width="125px">
- <div class="form-row">
- <!-- 左列 -->
- <div class="form-col">
- <el-form-item label="店铺名称" prop="storeName">
- <el-input v-model="step2Form.storeName" placeholder="请输入店铺名称" maxlength="30" />
- </el-form-item>
- <el-form-item label="容纳人数" prop="storeCapacity">
- <el-input-number v-model="step2Form.storeCapacity" :min="1" :max="9999" />
- </el-form-item>
- <el-form-item label="门店面积" prop="storeArea">
- <el-radio-group v-model="step2Form.storeArea">
- <el-radio label="小于20平米" value="1"> 小于20平米 </el-radio>
- <el-radio label="20-50平米" value="2"> 20-50平米 </el-radio>
- <el-radio label="50-100平米" value="3"> 50-100平米 </el-radio>
- <el-radio label="100-300平米" value="4"> 100-300平米 </el-radio>
- <el-radio label="500-1000平米" value="5"> 500-1000平米 </el-radio>
- <el-radio label="大于1000平米" value="6"> 大于1000平米 </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="所在地区" prop="region">
- <el-cascader :props="areaProps" v-model="step2Form.region" style="width: 100%" />
- </el-form-item>
- <el-form-item label="详细地址" prop="storeDetailAddress">
- <el-input v-model="step2Form.storeDetailAddress" type="textarea" :rows="3" placeholder="请输入" maxlength="255" />
- </el-form-item>
- <el-form-item label="门店简介" prop="storeBlurb">
- <el-input v-model="step2Form.storeBlurb" type="textarea" :rows="3" placeholder="请输入" maxlength="300" />
- </el-form-item>
- <el-form-item label="经营板块" prop="businessSection">
- <el-radio-group v-model="step2Form.businessSection" @change="changeBusinessSection">
- <el-radio
- v-for="businessSection in businessSectionList"
- :value="businessSection.dictId"
- :key="businessSection.dictId"
- >
- {{ businessSection.dictDetail }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="标签" prop="storeTickets" v-if="showDisportLicence">
- <el-radio-group v-model="step2Form.storeTickets">
- <el-radio
- v-for="businessSection in businessLabelList"
- :value="businessSection.dictId"
- :key="businessSection.dictId"
- >
- {{ businessSection.dictDetail }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <!-- 经营种类 -->
- <el-form-item label="经营种类" prop="businessTypeName">
- <el-input v-model="step2Form.businessTypeName" type="textarea" :rows="3" placeholder="请输入" maxlength="255" />
- </el-form-item>
- <!-- 经营类目 -->
- <el-form-item label="经营类目" prop="businessCategoryName">
- <el-input
- v-model="step2Form.businessCategoryName"
- type="textarea"
- :rows="3"
- placeholder="请输入"
- maxlength="255"
- />
- </el-form-item>
- </div>
- <!-- 右列 -->
- <div class="form-col">
- <el-form-item label="门店营业状态" prop="businessType">
- <el-radio-group v-model="step2Form.businessType">
- <el-radio label="正常营业"> 正常营业 </el-radio>
- <el-radio label="暂停营业"> 暂停营业 </el-radio>
- <el-radio label="筹建中"> 筹建中 </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="经度" prop="storePositionLongitude" v-show="latShow">
- <el-input disabled v-model="step2Form.storePositionLongitude" placeholder="请填写经度" clearable />
- </el-form-item>
- <el-form-item label="纬度" prop="storePositionLatitude" v-show="latShow">
- <el-input disabled v-model="step2Form.storePositionLatitude" placeholder="请填写纬度" clearable />
- </el-form-item>
- <el-form-item label="经纬度查询" prop="address">
- <el-select
- v-model="step2Form.address"
- filterable
- placeholder="请输入地址进行查询"
- remote
- reserve-keyword
- :remote-method="getLonAndLat"
- @change="selectAddress"
- >
- <el-option v-for="item in addressList" :key="item.id" :label="item.name" :value="item.location">
- <span style="float: left">{{ item.name }}</span>
- <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">{{ item.district }}</span>
- </el-option>
- </el-select>
- </el-form-item>
- <!-- 店铺评价(三项绑定 storePj 数组,校验才能通过) -->
- <el-form-item label="店铺评价" prop="storePj" required>
- <div class="store-pj-inputs">
- <el-input v-model="step2Form.storePj[0]" placeholder="请输入" maxlength="2" clearable class="store-pj-input" />
- <el-input v-model="step2Form.storePj[1]" maxlength="2" placeholder="请输入" clearable class="store-pj-input" />
- <el-input v-model="step2Form.storePj[2]" placeholder="请输入" maxlength="2" clearable class="store-pj-input" />
- </div>
- </el-form-item>
- <el-form-item label="预订服务">
- <el-radio-group v-model="step2Form.appointment">
- <el-radio label="提供"> 提供 </el-radio>
- <el-radio label="不提供"> 不提供 </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="营业时间">
- <div style="color: #6c8ff8; cursor: pointer" @click="openBusinessHours">
- {{ hasBusinessHoursConfig ? "已添加" : "添加" }}
- </div>
- </el-form-item>
- <el-form-item label="营业执照" prop="businessLicenseAddress">
- <el-upload
- v-model:file-list="step2Form.businessLicenseAddress"
- :http-request="handleHttpUpload"
- list-type="picture-card"
- :limit="1"
- :on-exceed="handleExceed"
- :on-success="(response, file) => handleUploadSuccess(response, file, 'BUSINESS_LICENSE', '营业执照')"
- :on-preview="handlePictureCardPreview"
- >
- <el-icon><Plus /></el-icon>
- <template #tip>
- <div class="el-upload__tip">({{ step2Form.businessLicenseAddress.length }}/1)</div>
- </template>
- </el-upload>
- </el-form-item>
- <el-form-item label="其他资质证明" prop="disportLicenceImgList">
- <el-upload
- v-model:file-list="step2Form.disportLicenceImgList"
- :http-request="handleHttpUpload"
- :limit="20"
- list-type="picture-card"
- :on-exceed="handleExceed"
- :on-success="(response, file) => handleUploadSuccess(response, file, 'BUSINESS_LICENSE', '其他资质证明')"
- :on-preview="handlePictureCardPreview"
- >
- <el-icon><Plus /></el-icon>
- <template #tip>
- <div class="el-upload__tip">已上传 {{ step2Form.disportLicenceImgList.length }} 张(最多20张)</div>
- </template>
- </el-upload>
- </el-form-item>
- <el-form-item label="设置收款账号" @click="handleSetPayAccount" style="cursor: pointer">
- <div class="pay-account-trigger">
- <el-icon color="#666" class="pay-account-trigger__arrow">
- <ArrowRightBold />
- </el-icon>
- </div>
- </el-form-item>
- </div>
- </div>
- </el-form>
- </div>
- <!-- 按钮 -->
- <div class="form-actions">
- <el-button type="primary" size="large" @click="handleSubmit"> 提交 </el-button>
- </div>
- </div>
- </div>
- <!-- 营业时间弹窗(入驻:仅缓存,关闭按钮) -->
- <GoBusinessHours
- v-model="businessHoursDialogVisible"
- :cache-only="true"
- @success="hasBusinessHoursConfig = true"
- @has-config="(v: boolean) => (hasBusinessHoursConfig = v)"
- />
- <el-dialog
- v-model="payAccountDialogVisible"
- width="420px"
- align-center
- append-to-body
- destroy-on-close
- class="pay-account-setup-dialog"
- :show-close="true"
- @open="onPayAccountDialogOpen"
- >
- <template #header>
- <div class="pay-account-setup-dialog__title">设置收款账号</div>
- </template>
- <div class="pay-account-option-list">
- <button
- v-for="opt in payAccountOptions"
- :key="opt.value"
- type="button"
- class="pay-account-option"
- :class="{ 'is-active': payAccountTemp === opt.value }"
- @click="payAccountTemp = opt.value"
- >
- <span class="pay-account-option__icon" :class="`pay-account-option__icon--${opt.value}`" aria-hidden="true" />
- <span class="pay-account-option__label">{{ opt.label }}</span>
- <span class="pay-account-option__radio" :class="{ 'is-checked': payAccountTemp === opt.value }">
- <el-icon v-if="payAccountTemp === opt.value" class="pay-account-option__check"><Check /></el-icon>
- </span>
- </button>
- </div>
- <template #footer>
- <el-button type="primary" class="pay-account-setup-dialog__confirm" @click="confirmPayAccount"> 确定 </el-button>
- </template>
- </el-dialog>
- <!-- 图片预览 -->
- <el-image-viewer
- v-if="imageViewerVisible"
- :url-list="imageViewerUrlList"
- :initial-index="imageViewerInitialIndex"
- @close="imageViewerVisible = false"
- />
- </template>
- <script setup lang="ts">
- import { ref, reactive, watch, onMounted, computed, toRaw } from "vue";
- import { ElMessage, ElMessageBox, type FormInstance, type FormRules, UploadUserFile, UploadRequestOptions } from "element-plus";
- import { Plus, ArrowRightBold, Check } from "@element-plus/icons-vue";
- import { applyStore, getMerchantByPhone, getThirdLevelList, verifyIdInfo } from "@/api/modules/homeEntry";
- import { getInputPrompt, getDistrict, uploadImg, ocrRequestUrl, getAiapprovestoreInfo } from "@/api/modules/newLoginApi";
- import GoBusinessHours from "./go-businessHours.vue";
- import { localGet, localSet } from "@/utils/index";
- import { useAuthStore } from "@/stores/modules/auth";
- import { useRouter } from "vue-router";
- const authStore = useAuthStore();
- const router = useRouter();
- const userInfo = localGet("geeker-user")?.userInfo || {};
- const latShow = ref(false);
- const showDisportLicence = ref(false);
- // 图片预览相关
- const imageViewerVisible = ref(false);
- const imageViewerUrlList = ref<string[]>([]);
- const imageViewerInitialIndex = ref(0);
- // 营业时间
- const businessHoursDialogVisible = ref(false);
- const hasBusinessHoursConfig = ref(false);
- const openBusinessHours = () => {
- businessHoursDialogVisible.value = true;
- };
- /** 收款方式:与弹窗选项一致,默认支付宝(与设计稿一致) */
- type ReceivePayType = "alipay" | "wechat" | "bank";
- const payAccountOptions: { value: ReceivePayType; label: string }[] = [
- { value: "alipay", label: "支付宝支付" },
- { value: "wechat", label: "微信支付" }
- ];
- const payAccountDialogVisible = ref(false);
- const payAccountTemp = ref<ReceivePayType>("alipay");
- const entryList = ref([
- {
- title: "个人实名"
- },
- {
- title: "填写信息"
- },
- {
- title: "等待审核"
- },
- {
- title: "入驻成功"
- }
- ]);
- const businessLabelList = ref<any[]>([
- {
- dictId: 1,
- dictDetail: "装修公司"
- },
- {
- dictId: 0,
- dictDetail: "其他类型"
- }
- ]);
- const businessSectionList = ref<any[]>([
- {
- dictId: 1,
- dictDetail: "特色美食"
- },
- {
- dictId: 2,
- dictDetail: "休闲娱乐"
- },
- {
- dictId: 3,
- dictDetail: "生活服务"
- }
- ]);
- // 身份证正反面上传列表
- const idCardFrontList = ref<UploadUserFile[]>([]);
- const idCardBackList = ref<UploadUserFile[]>([]);
- // OCR 识别结果
- const ocrResult = ref<{
- name?: string;
- idCard?: string;
- }>({});
- // 食品经营许可证到期时间(从 OCR 结果中提取)
- const foodLicenceExpirationTime = ref<string>("");
- // 其他资质证明到期时间(从 OCR 结果中提取)
- const entertainmentLicenceExpirationTime = ref<string>("");
- // 是否正在识别中
- const isOcrProcessing = ref(false);
- // OCR识别状态:'success' | 'failed' | 'none'(未识别)
- const businessLicenseOcrStatus = ref<"success" | "failed" | "none">("none"); // 营业执照OCR状态
- const foodLicenseOcrStatus = ref<"success" | "failed" | "none">("none"); // 食品经营许可证OCR状态
- const entertainmentLicenseOcrStatus = ref<"success" | "failed" | "none">("none"); // 其他资质证明OCR状态
- // 日期格式转换函数:支持两种格式
- // 1. "20220508" -> "2022-05-08"
- // 2. "2024年01月14日" -> "2024-01-14"
- const formatDate = (dateStr: string): string => {
- if (!dateStr) {
- return "";
- }
- // 处理中文日期格式:2024年01月14日
- if (dateStr.includes("年") && dateStr.includes("月") && dateStr.includes("日")) {
- const match = dateStr.match(/(\d{4})年(\d{1,2})月(\d{1,2})日/);
- if (match) {
- const year = match[1];
- const month = match[2].padStart(2, "0"); // 补零,确保是两位数
- const day = match[3].padStart(2, "0"); // 补零,确保是两位数
- return `${year}-${month}-${day}`;
- }
- }
- // 处理8位数字格式:20220508
- if (dateStr.length === 8 && /^\d{8}$/.test(dateStr)) {
- const year = dateStr.substring(0, 4);
- const month = dateStr.substring(4, 6);
- const day = dateStr.substring(6, 8);
- return `${year}-${month}-${day}`;
- }
- return "";
- };
- // 计算是否已上传完成(正反面都上传完成)
- const isIdCardUploadComplete = computed(() => {
- return idCardFrontList.value.length > 0 && idCardBackList.value.length > 0;
- });
- // 下一步 - 验证身份证正反面是否已上传
- const handleNextStep = async () => {
- // 识别成功,进入下一步
- // try {
- // const res: any = await verifyIdInfo({
- // idCard: ocrResult.value.idCard,
- // name: ocrResult.value.name,
- // appType: 1
- // });
- // if (res.code === 200) {
- // ElMessage.success("身份证识别成功");
- // setStep(2);
- // } else {
- // ElMessage.error(res?.msg || "身份证识别失败");
- // idCardFrontList.value = [];
- // }
- // } catch (error: any) {
- // console.log(error);
- // }
- ElMessage.success("身份证识别成功");
- setStep(2);
- };
- const step2Rules: FormRules = {
- storeName: [{ required: true, message: "请输入店铺名称", trigger: "blur" }],
- storeCapacity: [{ required: true, message: "请输入容纳人数", trigger: "blur" }],
- storeArea: [{ required: true, message: "请选择门店面积", trigger: "change" }],
- storeBlurb: [{ required: true, message: "请输入门店简介", trigger: "change" }],
- storeDetailAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
- businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
- storeTickets: [
- {
- required: true,
- message: "请选择标签",
- trigger: "change",
- validator: (_rule: any, value: any, callback: (err?: Error) => void) => {
- // 仅当经营板块为「生活服务」时校验标签必选
- if (step2Form.businessSection != 3) {
- callback();
- return;
- }
- if (value !== "" && value !== undefined && value !== null) {
- callback();
- } else {
- callback(new Error("请选择标签"));
- }
- }
- }
- ],
- businessTypeName: [{ required: true, message: "请输入经营种类", trigger: "change" }],
- businessCategoryName: [{ required: true, message: "请选择经营类目", trigger: "change" }],
- address: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
- businessLicenseAddress: [{ required: true, message: "请上传营业执照", trigger: "change" }],
- storePj: [
- {
- required: true,
- message: "请完整填写三项店铺评价",
- trigger: "blur",
- validator: (_rule: any, value: any, callback: (err?: Error) => void) => {
- const list = Array.isArray(value) ? value : [];
- const filled = list.length >= 3 && list.every(v => v != null && String(v).trim() !== "");
- if (filled) callback();
- else callback(new Error("请完整填写三项店铺评价"));
- }
- }
- ]
- // disportLicenceImgList: [{ required: true, message: "请上传其他资质证明", trigger: "change" }]
- };
- //地址集合
- const addressList = ref<any[]>([]);
- //查询地址名称
- const queryAddress = ref<string>("");
- const props = defineProps({
- currentStep: {
- type: Number,
- default: 1
- },
- storeApplicationStatus: {
- type: Number,
- default: 0
- }
- });
- const emit = defineEmits(["update:currentStep", "update:get-user-info"]);
- // 调用父组件的 getUserInfo 方法
- const callGetUserInfo = () => {
- emit("update:get-user-info");
- };
- // 内部步骤状态,和父组件同步
- const currentStep = ref<number>(props.currentStep || 1);
- const storeApplicationStatus = ref<number>(props.storeApplicationStatus || 0);
- watch(
- () => props.currentStep,
- val => {
- if (typeof val === "number") currentStep.value = val;
- }
- );
- watch(
- () => props.storeApplicationStatus,
- val => {
- if (typeof val === "number") storeApplicationStatus.value = val;
- }
- );
- const changeBusinessSection = () => {
- if (step2Form.businessSection == 3) {
- // 生活服务:显示标签,默认选「其他类型」(dictId=0)
- showDisportLicence.value = true;
- (step2Form as { storeTickets: string | number }).storeTickets = 0;
- } else {
- // 非生活服务:隐藏标签,不选任何类型
- showDisportLicence.value = false;
- step2Form.storeTickets = "";
- }
- };
- // 隐藏财务管理菜单的函数
- const hideFinancialManagementMenu = () => {
- const hideMenus = (menuList: any[]) => {
- menuList.forEach(menu => {
- if (menu.name && menu.name === "financialManagement") {
- menu.meta.isHide = true;
- }
- if (menu.children && menu.children.length > 0) {
- hideMenus(menu.children);
- }
- });
- };
- if (authStore.authMenuList && authStore.authMenuList.length > 0) {
- hideMenus(authStore.authMenuList);
- }
- };
- // 显示财务管理菜单的函数
- const showFinancialManagementMenu = () => {
- const showMenus = (menuList: any[]) => {
- menuList.forEach(menu => {
- if (menu.name && menu.name === "financialManagement") {
- menu.meta.isHide = false;
- }
- if (menu.children && menu.children.length > 0) {
- showMenus(menu.children);
- }
- });
- };
- if (authStore.authMenuList && authStore.authMenuList.length > 0) {
- showMenus(authStore.authMenuList);
- }
- };
- // 更新缓存中的 storeId
- const updateStoreIdInCache = async () => {
- try {
- const geekerUser = localGet("geeker-user");
- if (!geekerUser || !geekerUser.userInfo || !geekerUser.userInfo.phone) {
- console.error("用户信息不存在");
- return;
- }
- const phone = geekerUser.userInfo.phone;
- const res: any = await getMerchantByPhone({ phone });
- if (res && res.code == 200 && res.data && res.data.storeId) {
- geekerUser.userInfo.storeId = res.data.storeId;
- localSet("geeker-user", geekerUser);
- if (res.data.storeId) {
- localSet("createdId", res.data.storeId);
- }
- }
- } catch (error) {
- console.error("更新 storeId 缓存失败:", error);
- }
- };
- // 监听步骤和审核状态
- watch([() => currentStep.value, () => storeApplicationStatus.value], ([step, status]) => {
- if (step === 3 && (status === 0 || status === 2)) {
- updateStoreIdInCache();
- }
- if (status === 2) {
- hideFinancialManagementMenu();
- }
- if (status === 1) {
- showFinancialManagementMenu();
- }
- });
- // 监听菜单列表变化
- watch(
- () => authStore.authMenuList.length,
- newLength => {
- if (newLength > 0) {
- if (storeApplicationStatus.value === 2) {
- hideFinancialManagementMenu();
- }
- if (storeApplicationStatus.value === 1) {
- showFinancialManagementMenu();
- }
- }
- }
- );
- onMounted(() => {
- callGetUserInfo();
- if (currentStep.value === 3 && (storeApplicationStatus.value === 0 || storeApplicationStatus.value === 2)) {
- updateStoreIdInCache();
- }
- if (storeApplicationStatus.value === 2) {
- hideFinancialManagementMenu();
- } else if (storeApplicationStatus.value === 1) {
- showFinancialManagementMenu();
- }
- });
- const setStep = (val: number) => {
- currentStep.value = val;
- emit("update:currentStep", val);
- };
- // 第二步表单
- const step2FormRef = ref<FormInstance>();
- const step2Form = reactive({
- appointment: "",
- businessSecondMeal: 1,
- storeName: "",
- storeCapacity: 1,
- storeArea: "1",
- isChain: 0,
- storeDetailAddress: "",
- region: [],
- administrativeRegionProvinceAdcode: "",
- administrativeRegionCityAdcode: "",
- administrativeRegionDistrictAdcode: "",
- storeAddress: "",
- storeBlurb: "",
- businessSection: 1,
- storeTickets: "",
- businessSecondLevel: [] as string[],
- businessTypes: "" as string,
- businessTypesList: [] as string[],
- businessStatus: 0,
- storeStatus: 1,
- businessType: "正常营业",
- storePositionLongitude: "",
- storePositionLatitude: "",
- businessLicenseAddress: [] as UploadUserFile[],
- contractImageList: [] as UploadUserFile[],
- foodLicenceImgList: [] as UploadUserFile[],
- disportLicenceImgList: [] as UploadUserFile[],
- address: "",
- // 经营种类
- businessTypeName: "",
- // 经营类目
- businessCategoryName: "",
- // 店铺评价(三项,与 prop="storePj" 对应,校验规则会检查此数组)
- storePj: ["", "", ""] as string[],
- /** 设置收款账号(弹窗选择,提交时带给 saveStoreInfo,后端可按需接收) */
- receivePayType: "alipay" as ReceivePayType
- });
- const payAccountLabel = computed(() => {
- const v = step2Form.receivePayType;
- return payAccountOptions.find(o => o.value === v)?.label ?? "支付宝支付";
- });
- const handleSetPayAccount = () => {
- payAccountDialogVisible.value = true;
- };
- const onPayAccountDialogOpen = () => {
- payAccountTemp.value = step2Form.receivePayType;
- };
- const confirmPayAccount = () => {
- step2Form.receivePayType = payAccountTemp.value;
- payAccountDialogVisible.value = false;
- if (payAccountTemp.value === "alipay") {
- router.push({ path: "/businessInfo/zfbIndex" });
- } else if (payAccountTemp.value === "wechat") {
- router.push({ path: "/businessInfo/weChartIndex" });
- }
- };
- // 返回按钮
- const handleBack = () => {
- if (currentStep.value === 1) {
- setStep(0);
- } else if (currentStep.value === 2) {
- setStep(1);
- } else if (currentStep.value === 3) {
- setStep(2);
- }
- };
- // 地区选择
- const areaProps: any = {
- lazy: true,
- async lazyLoad(node, resolve) {
- const { level } = node;
- try {
- let param = { adCode: node.data.adCode ? node.data.adCode : "" };
- const response: any = await getDistrict(param as any);
- const nodes = (response?.data?.districts?.[0]?.districts || []).map((item: any) => ({
- value: item.adcode,
- adCode: item.adcode,
- label: item.name,
- leaf: level >= 2
- }));
- resolve(nodes);
- } catch (error) {
- resolve([]);
- }
- }
- };
- watch(
- () => step2Form.region,
- (newVal: any[]) => {
- if (newVal.length > 0) {
- step2Form.administrativeRegionProvinceAdcode = newVal[0];
- step2Form.administrativeRegionCityAdcode = newVal[1];
- step2Form.administrativeRegionDistrictAdcode = newVal[2];
- }
- }
- );
- // 二级分类列表
- const secondLevelList = ref<any[]>([]);
- // 三级分类列表
- const thirdLevelList = ref<any[]>([]);
- // 二级分类变化时,加载三级分类
- const changeBusinessSecondLevel = async (dictId: string | number | boolean | undefined) => {
- const dictIdStr = String(dictId || "");
- if (!dictIdStr) {
- thirdLevelList.value = [];
- step2Form.businessTypes = "";
- step2Form.businessTypesList = [];
- return;
- }
- // 清空三级分类(但不清空 businessTypes,因为这是用户刚选择的值)
- thirdLevelList.value = [];
- step2Form.businessTypesList = [];
- // 加载三级分类
- try {
- const res: any = await getThirdLevelList(dictIdStr);
- if (res && (res.code === 200 || res.code === "200") && res.data && Array.isArray(res.data) && res.data.length > 0) {
- thirdLevelList.value = res.data;
- } else {
- // 如果没有三级分类数据,确保清空
- thirdLevelList.value = [];
- }
- } catch (error) {
- console.error("获取三级分类失败:", error);
- // 如果没有三级分类,不显示错误,因为可能该二级分类下没有三级分类
- // 确保清空三级分类列表
- thirdLevelList.value = [];
- }
- };
- // 经纬度查询
- const getLonAndLat = async (keyword: string) => {
- if (keyword) {
- let param = {
- addressName: keyword
- };
- let res: any = await getInputPrompt(param as any);
- if (res.code == "200") {
- addressList.value = res?.data?.tips || [];
- } else {
- ElMessage.error("查询失败!");
- }
- } else {
- addressList.value = [];
- }
- };
- const selectAddress = async () => {
- if (!step2Form.address || typeof step2Form.address !== "string") {
- ElMessage.warning("地址格式不正确,请重新选择");
- return;
- }
- if (!step2Form.address.includes(",")) {
- ElMessage.warning("地址格式不正确,缺少经纬度信息");
- return;
- }
- let locationList = step2Form.address.split(",");
- if (locationList.length < 2) {
- ElMessage.warning("地址格式不正确,无法获取经纬度");
- return;
- }
- addressList.value.forEach((item: any) => {
- if (item.location == step2Form.address) {
- queryAddress.value = item.name;
- }
- });
- step2Form.storePositionLongitude = locationList[0]?.trim() || "";
- step2Form.storePositionLatitude = locationList[1]?.trim() || "";
- if (!step2Form.storePositionLongitude || !step2Form.storePositionLatitude) {
- ElMessage.warning("无法获取有效的经纬度信息");
- return;
- }
- latShow.value = true;
- };
- //文件上传
- const handleHttpUpload = async (options: UploadRequestOptions) => {
- let formData = new FormData();
- formData.append("file", options.file);
- try {
- const res: any = await uploadImg(formData);
- const fileUrl = res?.data?.fileUrl || res?.data?.[0] || res?.fileUrl;
- if (fileUrl) {
- options.onSuccess({ fileUrl });
- } else {
- throw new Error("上传失败:未获取到文件URL");
- }
- } catch (error) {
- options.onError(error as any);
- ElMessage.error("文件上传失败,请重试");
- }
- };
- // 自动调用 OCR 识别
- const autoOcrRecognition = async (ocrType: string, name: string) => {
- // 如果正在识别中,不重复调用
- if (isOcrProcessing.value) {
- return;
- }
- let imageUrls = "";
- let fileList: UploadUserFile[] = [];
- // 根据不同的 ocrType 获取对应的图片 URL
- if (ocrType === "ID_CARD") {
- // 身份证:需要检查正反面是否都已上传完成
- if (idCardFrontList.value.length === 0 || idCardBackList.value.length === 0) {
- return;
- }
- const frontFile = idCardFrontList.value[0];
- const backFile = idCardBackList.value[0];
- // 验证上传的文件是否成功
- if (frontFile.status !== "success" || !frontFile.url || backFile.status !== "success" || !backFile.url) {
- return;
- }
- // 获取身份证正反面的 URL
- const frontUrl = getFileUrls(idCardFrontList.value)[0] || "";
- const backUrl = getFileUrls(idCardBackList.value)[0] || "";
- if (!frontUrl || !backUrl) {
- return;
- }
- // 将正反面 URL 用逗号分隔
- imageUrls = `${frontUrl},${backUrl}`;
- } else if (ocrType === "BUSINESS_LICENSE") {
- // 营业执照或其他资质证明:检查是否已上传
- // 优先检查营业执照,如果没有再检查其他资质证明
- let fileList: UploadUserFile[] = [];
- if (name == "营业执照") {
- fileList = step2Form.businessLicenseAddress;
- } else if (name == "其他资质证明") {
- fileList = step2Form.disportLicenceImgList;
- } else {
- return;
- }
- const file = fileList[0];
- if (file.status !== "success" || !file.url) {
- return;
- }
- const fileUrl = getFileUrls(fileList)[0] || "";
- if (!fileUrl) {
- return;
- }
- imageUrls = fileUrl;
- } else if (ocrType === "FOOD_MANAGE_LICENSE") {
- // 食品经营许可证:检查是否已上传
- if (step2Form.foodLicenceImgList.length === 0) {
- return;
- }
- const file = step2Form.foodLicenceImgList[0];
- if (file.status !== "success" || !file.url) {
- return;
- }
- const fileUrl = getFileUrls(step2Form.foodLicenceImgList)[0] || "";
- if (!fileUrl) {
- return;
- }
- imageUrls = fileUrl;
- } else {
- // 其他类型不进行 OCR
- return;
- }
- let params = {
- imageUrls: imageUrls,
- ocrType: ocrType,
- storeId: userInfo.storeId,
- storeUserId: userInfo.id
- };
- try {
- isOcrProcessing.value = true;
- const res: any = await ocrRequestUrl(params);
- if (res && (res.code === 200 || res.code === "200")) {
- // 只有身份证类型才需要保存识别结果到 ocrResult
- if (ocrType === "ID_CARD" && res.data && Array.isArray(res.data) && res.data.length > 0) {
- // 从第一个元素获取正面或反面数据
- const firstItem = res.data[0];
- const secondItem = res.data[1];
- // 根据数据键值判断哪一个是正面(face)或反面(back)
- const faceData = firstItem?.face?.data || secondItem?.face?.data;
- const backData = firstItem?.back?.data || secondItem?.back?.data;
- // 提取姓名(从正面数据中获取)
- const name = faceData?.name || "";
- // 提取身份证号(优先从正面数据中获取,如果没有则从反面获取)
- let idCard = faceData?.idNumber || backData?.idNumber || "";
- // 如果从 data 中获取不到,尝试从 prism_keyValueInfo 中查找
- if (!idCard) {
- // 先从正面查找
- if (firstItem?.face?.prism_keyValueInfo) {
- const idNumberInfo = firstItem.face.prism_keyValueInfo.find((item: any) => item.key === "idNumber" && item.value);
- if (idNumberInfo) {
- idCard = idNumberInfo.value;
- }
- }
- // 如果正面没有,再从反面查找
- if (!idCard && secondItem?.face?.prism_keyValueInfo) {
- const idNumberInfo = secondItem.face.prism_keyValueInfo.find((item: any) => item.key === "idNumber" && item.value);
- if (idNumberInfo) {
- idCard = idNumberInfo.value;
- }
- }
- }
- ocrResult.value = {
- name: name,
- idCard: idCard
- };
- // 更新本地存储中的用户信息
- const geekerUser = localGet("geeker-user");
- if (geekerUser && geekerUser.userInfo) {
- if (ocrResult.value.name) {
- geekerUser.userInfo.name = ocrResult.value.name;
- }
- if (ocrResult.value.idCard) {
- geekerUser.userInfo.idCard = ocrResult.value.idCard;
- }
- localSet("geeker-user", geekerUser);
- }
- ElMessage.success("身份证识别成功");
- } else if (ocrType === "BUSINESS_LICENSE") {
- // 判断是营业执照还是其他资质证明
- const isBusinessLicense = step2Form.businessLicenseAddress.length > 0;
- // 提取 validToDate 字段(其他资质证明)
- if (!isBusinessLicense && res.data && Array.isArray(res.data) && res.data.length > 0) {
- const validToDate = res.data[0]?.validToDate || "";
- if (validToDate) {
- entertainmentLicenceExpirationTime.value = formatDate(validToDate);
- }
- }
- if (name == "营业执照") {
- businessLicenseOcrStatus.value = "success";
- ElMessage.success("营业执照识别成功");
- } else if (name == "其他资质证明") {
- entertainmentLicenseOcrStatus.value = "success";
- ElMessage.success("其他资质证明识别成功");
- }
- } else if (ocrType === "FOOD_MANAGE_LICENSE") {
- // 提取食品经营许可证的 validToDate 字段
- if (res.data && Array.isArray(res.data) && res.data.length > 0) {
- const validToDate = res.data[0]?.validToDate || "";
- if (validToDate) {
- foodLicenceExpirationTime.value = formatDate(validToDate);
- }
- }
- foodLicenseOcrStatus.value = "success";
- ElMessage.success("食品经营许可证识别成功");
- }
- } else {
- console.warn("OCR 识别失败:", res?.msg);
- if (name === "营业执照") {
- businessLicenseOcrStatus.value = "failed";
- step2Form.businessLicenseAddress = [];
- } else if (name === "其他资质证明") {
- entertainmentLicenseOcrStatus.value = "failed";
- step2Form.disportLicenceImgList = [];
- } else if (ocrType === "FOOD_MANAGE_LICENSE") {
- foodLicenseOcrStatus.value = "failed";
- step2Form.foodLicenceImgList = [];
- } else if (ocrType === "ID_CARD") {
- idCardFrontList.value = [];
- idCardBackList.value = [];
- }
- ElMessage.error(res?.msg || "识别失败,已清除该图片,请重新上传");
- }
- } catch (error) {
- if (name === "营业执照") {
- businessLicenseOcrStatus.value = "failed";
- step2Form.businessLicenseAddress = [];
- } else if (name === "其他资质证明") {
- entertainmentLicenseOcrStatus.value = "failed";
- step2Form.disportLicenceImgList = [];
- } else if (ocrType === "FOOD_MANAGE_LICENSE") {
- foodLicenseOcrStatus.value = "failed";
- step2Form.foodLicenceImgList = [];
- } else if (ocrType === "ID_CARD") {
- idCardFrontList.value = [];
- idCardBackList.value = [];
- }
- ElMessage.error("识别失败,已清除该图片,请重新上传");
- } finally {
- isOcrProcessing.value = false;
- }
- };
- // 文件上传成功回调
- const handleUploadSuccess = (response: any, uploadFile: UploadUserFile, ocrType: string, name: string) => {
- if (response?.fileUrl) {
- uploadFile.url = response.fileUrl;
- }
- // 其他资质证明不做 OCR,直接返回
- if (name === "其他资质证明") {
- return;
- }
- // 仅对身份证、营业执照、食品许可证做 OCR
- if (ocrType && (ocrType === "ID_CARD" || ocrType === "BUSINESS_LICENSE" || ocrType === "FOOD_MANAGE_LICENSE")) {
- if (name === "营业执照") {
- businessLicenseOcrStatus.value = "none";
- } else if (ocrType === "FOOD_MANAGE_LICENSE") {
- foodLicenseOcrStatus.value = "none";
- }
- // 延迟一下,确保文件状态已更新,然后检查是否需要自动 OCR
- setTimeout(() => {
- autoOcrRecognition(ocrType, name);
- }, 100);
- }
- };
- // 图片预览处理函数
- const handlePictureCardPreview = (file: UploadUserFile) => {
- if (file.status === "uploading" && file.url) {
- imageViewerUrlList.value = [file.url];
- imageViewerInitialIndex.value = 0;
- imageViewerVisible.value = true;
- return;
- }
- let urlList: string[] = [];
- let currentFileList: UploadUserFile[] = [];
- // 判断是哪个上传组件的文件
- if (idCardFrontList.value.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = idCardFrontList.value;
- } else if (idCardBackList.value.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = idCardBackList.value;
- } else if (step2Form.businessLicenseAddress.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = step2Form.businessLicenseAddress;
- } else if (step2Form.contractImageList.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = step2Form.contractImageList;
- } else if (step2Form.foodLicenceImgList.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = step2Form.foodLicenceImgList;
- } else if (step2Form.disportLicenceImgList.some((f: UploadUserFile) => f.uid === file.uid)) {
- currentFileList = step2Form.disportLicenceImgList;
- }
- urlList = currentFileList
- .filter((item: UploadUserFile) => item.status === "success" && (item.url || (item.response as any)?.fileUrl))
- .map((item: UploadUserFile) => item.url || (item.response as any)?.fileUrl);
- const currentUrl = file.url || (file.response as any)?.fileUrl;
- const currentIndex = urlList.findIndex((url: string) => url === currentUrl);
- if (currentIndex < 0) {
- ElMessage.warning("图片尚未上传完成,无法预览");
- return;
- }
- imageViewerUrlList.value = urlList;
- imageViewerInitialIndex.value = currentIndex;
- imageViewerVisible.value = true;
- };
- // 文件移除处理
- const handleRemove = (file: UploadUserFile) => {
- // 文件移除时,清空 OCR 识别结果
- ocrResult.value = {};
- isOcrProcessing.value = false;
- // 根据文件所属列表重置对应的OCR状态
- if (step2Form.businessLicenseAddress.some((f: UploadUserFile) => f.uid === file.uid)) {
- // 移除的是营业执照
- businessLicenseOcrStatus.value = "none";
- } else if (step2Form.foodLicenceImgList.some((f: UploadUserFile) => f.uid === file.uid)) {
- // 移除的是食品经营许可证
- foodLicenseOcrStatus.value = "none";
- } else if (step2Form.disportLicenceImgList.some((f: UploadUserFile) => f.uid === file.uid)) {
- // 移除的是其他资质证明
- entertainmentLicenseOcrStatus.value = "none";
- }
- };
- // 提取文件列表中的URL
- const getFileUrls = (fileList: UploadUserFile[]): string[] => {
- return fileList
- .map((file: UploadUserFile) => {
- const response = file.response as any;
- return file.url || response?.fileUrl || "";
- })
- .filter((url: string) => url);
- };
- // 根据adcode获取地区详细信息
- const getDistrictInfo = async (adcode: string) => {
- try {
- const response: any = await getDistrict({ adCode: adcode } as any);
- const district = response?.data?.districts?.[0];
- if (district) {
- return {
- citycode: district.citycode ? [district.citycode] : [],
- adcode: district.adcode,
- level: district.level,
- center: district.center,
- name: district.name,
- districts: []
- };
- }
- } catch (error) {
- console.error("获取地区信息失败:", error);
- }
- return null;
- };
- // 构建whereAddress数组
- const buildWhereAddress = async (regionCodes: string[]) => {
- const whereAddress: any[] = [];
- if (regionCodes && regionCodes.length > 0) {
- for (const code of regionCodes) {
- const districtInfo = await getDistrictInfo(code);
- if (districtInfo) {
- whereAddress.push(districtInfo);
- }
- }
- }
- return whereAddress;
- };
- // 店铺入驻成功后调用 AI 审核接口(参考商家端:后台调用,不阻塞、不向用户展示结果)
- const handleAi = () => {
- const businessLicenseUrls = getFileUrls(step2Form.businessLicenseAddress);
- const contractImageUrls = getFileUrls(step2Form.contractImageList);
- const foodLicenceUrls = getFileUrls(step2Form.foodLicenceImgList);
- const disportLicenceUrls = getFileUrls(step2Form.disportLicenceImgList);
- const licenseImages = [...businessLicenseUrls, ...contractImageUrls, ...foodLicenceUrls, ...disportLicenceUrls].filter(Boolean);
- const params: any = {
- business_scope: step2Form.storeBlurb || "",
- contact_email: "",
- contact_name: userInfo.name || "",
- contact_phone: userInfo.phone || "",
- license_images: licenseImages,
- merchant_name: step2Form.storeName || "",
- userId: userInfo.id || ""
- };
- getAiapprovestoreInfo(params).catch(aiError => {
- console.error("AI店铺审核接口调用失败:", aiError);
- });
- };
- // 提交
- const handleSubmit = async () => {
- if (!step2FormRef.value) return;
- await step2FormRef.value.validate(async valid => {
- if (valid) {
- const businessLicenseUrls = getFileUrls(step2Form.businessLicenseAddress);
- const contractImageUrls = getFileUrls(step2Form.contractImageList);
- const foodLicenceUrls = getFileUrls(step2Form.foodLicenceImgList);
- const disportLicenceUrls = getFileUrls(step2Form.disportLicenceImgList);
- const whereAddress = await buildWhereAddress(step2Form.region);
- const storePosition =
- step2Form.storePositionLongitude && step2Form.storePositionLatitude
- ? `${step2Form.storePositionLongitude},${step2Form.storePositionLatitude}`
- : "";
- const storePositionLatitude = parseFloat(step2Form.storePositionLatitude) || 0;
- const storePositionLongitude = parseFloat(step2Form.storePositionLongitude) || 0;
- let finalBusinessTypes: string[] = [];
- if (thirdLevelList.value.length > 0) {
- if (step2Form.businessTypes) {
- finalBusinessTypes = [step2Form.businessTypes];
- }
- if (
- Array.isArray(step2Form.businessSecondLevel) &&
- step2Form.businessSecondLevel.length > 0 &&
- finalBusinessTypes.length === 0
- ) {
- finalBusinessTypes = step2Form.businessSecondLevel;
- }
- } else {
- if (Array.isArray(step2Form.businessSecondLevel) && step2Form.businessSecondLevel.length > 0) {
- finalBusinessTypes = step2Form.businessSecondLevel;
- } else if (step2Form.businessTypes) {
- finalBusinessTypes = [step2Form.businessTypes];
- } else if (step2Form.businessTypesList.length > 0) {
- finalBusinessTypes = step2Form.businessTypesList;
- }
- }
- const businessTypesListVal = finalBusinessTypes.length > 0 ? finalBusinessTypes[0] : "";
- // const categoryListVal = step2Form.businessCategoryName ? [step2Form.businessCategoryName] : [];
- // 与商家端 storeInfo saveStoreInfo 入参保持一致(storeInfoDto + 提交覆盖项)
- const storeInfoDto: any = {
- updatedTime: null,
- storeTel: userInfo.phone,
- storeName: step2Form.storeName,
- storeCapacity: step2Form.storeCapacity,
- storeArea: typeof step2Form.storeArea === "string" ? parseInt(step2Form.storeArea) : step2Form.storeArea,
- isChain: step2Form.isChain,
- storeAddress: step2Form.storeDetailAddress,
- storeBlurb: step2Form.storeBlurb,
- businessSection: String(step2Form.businessSection),
- businessSectionName:
- step2Form.businessSection == 1 ? "特色美食" : step2Form.businessSection == 2 ? "休闲娱乐" : "生活服务",
- businessTypeName: step2Form.businessTypeName,
- storeStatus: step2Form.businessType === "暂停营业" ? 0 : step2Form.businessType === "筹建中" ? 2 : 1,
- queryAddress: queryAddress.value || "",
- storePosition,
- storePositionLatitude,
- storePositionLongitude,
- // businessTypesList: [businessTypesListVal],
- // businessTypes: businessTypesListVal,
- businessClassify: step2Form.businessCategoryName,
- businessLicenseAddress: businessLicenseUrls,
- businessLicenseUrl: businessLicenseUrls.join(","),
- contractImageList: contractImageUrls,
- foodLicenceUrl: foodLicenceUrls,
- otherQualificationImages: disportLicenceUrls,
- otherLicenses: disportLicenceUrls.join(","),
- storeEvaluate: (step2Form.storePj || []).join(","),
- evaluation1: step2Form.storePj[0],
- evaluation2: step2Form.storePj[1],
- evaluation3: step2Form.storePj[2],
- userAccount: userInfo.id,
- administrativeRegionProvinceAdcode: step2Form.administrativeRegionProvinceAdcode || whereAddress[0]?.adcode || "",
- administrativeRegionProvinceName: whereAddress[0]?.name || "",
- administrativeRegionCityAdcode: step2Form.administrativeRegionCityAdcode || whereAddress[1]?.adcode || "",
- administrativeRegionCityName: whereAddress[1]?.name || "",
- administrativeRegionDistrictAdcode: step2Form.administrativeRegionDistrictAdcode || whereAddress[2]?.adcode || "",
- administrativeRegionDistrictName: whereAddress[2]?.name || "",
- businessStatus: step2Form.businessStatus,
- storeContact: userInfo.name || (localGet("smName") as string) || "",
- idCard: localGet("idCard") || "",
- bookingService: step2Form.appointment === "提供" ? 1 : 0
- };
- storeInfoDto.storeTickets = step2Form.storeTickets;
- // 营业时间:从缓存读取并转为提交格式
- const businessHoursRaw = localGet("geeker-entry-businessHours");
- const businessHoursCopy = Array.isArray(businessHoursRaw)
- ? businessHoursRaw
- : businessHoursRaw && typeof businessHoursRaw === "object" && Array.isArray((businessHoursRaw as any).list)
- ? (businessHoursRaw as any).list
- : [];
- const storeBusinessTime = businessHoursCopy.map((item: any) => {
- const obj: any = {
- businessType: item.businessType,
- startTime: item.startTime,
- endTime: item.endTime,
- storeId: userInfo.storeId ?? null
- };
- if (item.businessType === 2) {
- obj.essentialId = item.holidayId; // geeker-entry-businessHours 缓存里的 holidayId(getHolidayList 返回的 id)
- }
- if (item.businessType === 1) obj.businessDate = item.businessDate;
- return obj;
- });
- const saveStoreInfoParams = {
- ...storeInfoDto,
- foodLicenceUrl: foodLicenceUrls.join(","),
- mealsFlag: step2Form.businessSecondMeal === 1 ? 1 : 0,
- createdUserId: userInfo.id || "",
- storeBusinessTime: storeBusinessTime.length > 0 ? storeBusinessTime : undefined,
- receivePayType: step2Form.receivePayType
- };
- ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- })
- .then(async () => {
- try {
- const res: any = await applyStore(saveStoreInfoParams);
- if (res && res.code == 200) {
- storeApplicationStatus.value = 0;
- ElMessage.success(res.msg || "提交成功");
- if (res.data?.id) {
- localSet("createdId", res.data.id);
- }
- callGetUserInfo();
- setStep(0);
- handleAi();
- } else {
- ElMessage.error(res?.msg || "提交失败");
- }
- } catch (error) {
- ElMessage.error("提交失败,请重试");
- }
- })
- .catch(() => {});
- } else {
- ElMessage.error("请完善表单信息");
- }
- });
- };
- // 文件上传超出限制
- const handleExceed = () => {
- ElMessage.warning("文件数量超出限制");
- };
- </script>
- <style>
- .el-dialog__body {
- height: 600px;
- overflow: scroll;
- }
- </style>
- <style scoped lang="scss">
- // 店铺评价三个输入框纵向排列
- .store-pj-inputs {
- display: flex;
- flex-direction: column;
- gap: 12px;
- width: 100%;
- .store-pj-input {
- width: 100%;
- }
- }
- // 表单页面样式
- .form-container {
- min-height: calc(100vh - 100px);
- padding: 30px;
- background: #ffffff;
- border-radius: 8px;
- .back-btn {
- margin-bottom: 30px;
- color: #606266;
- border-color: #dcdfe6;
- }
- .progress-container {
- margin-bottom: 40px;
- :deep(.el-step__head.is-process .el-step__icon) {
- color: #909399;
- border-color: #909399 !important;
- }
- :deep(.el-steps) {
- .is-finish {
- .el-step__icon {
- color: #ffffff;
- background-color: #6c8ff8 !important;
- border-color: #6c8ff8 !important;
- }
- }
- .el-step__head {
- .el-step__icon {
- width: 30px;
- height: 30px;
- font-size: 16px;
- font-weight: 600;
- }
- }
- .el-step__title {
- .step-title-wrapper {
- display: flex;
- flex-direction: column;
- gap: 8px;
- align-items: center;
- .step-title {
- font-size: 16px;
- font-weight: 600;
- color: #6c8ff8;
- }
- }
- }
- }
- }
- // 第一步内容样式
- .step1-content {
- .form-content {
- max-width: 800px;
- margin: 0 auto 40px;
- .section-title {
- margin-bottom: 30px;
- font-size: 18px;
- font-weight: 600;
- color: #303133;
- text-align: center;
- }
- .id-card-upload-container {
- display: flex;
- gap: 40px;
- align-items: flex-start;
- justify-content: center;
- :deep(.el-upload-list--picture-card) {
- width: 100%;
- }
- .upload-item {
- flex: 1;
- max-width: 300px;
- .upload-label {
- margin-bottom: 12px;
- font-size: 14px;
- color: #606266;
- text-align: center;
- }
- .id-card-upload {
- width: 100%;
- :deep(.el-upload) {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 200px;
- cursor: pointer;
- background-color: #f5f7fa;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- transition: all 0.3s;
- &:hover {
- border-color: #6c8ff8;
- }
- }
- // 当上传完成后隐藏上传按钮
- &.upload-complete {
- :deep(.el-upload) {
- display: none !important;
- }
- }
- :deep(.el-upload-list) {
- .el-upload-list__item {
- width: 100%;
- height: 200px;
- margin: 0;
- }
- }
- .upload-placeholder {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 100%;
- .placeholder-text {
- font-size: 14px;
- color: #909399;
- }
- }
- }
- }
- }
- // OCR 识别结果展示样式
- .ocr-result-container {
- width: 670px;
- padding: 20px;
- margin: 60px auto;
- .ocr-result-item {
- display: flex;
- align-items: center;
- margin-bottom: 16px;
- font-size: 16px;
- line-height: 1.5;
- &:last-child {
- margin-bottom: 0;
- }
- .label {
- min-width: 100px;
- font-weight: 600;
- color: #606266;
- }
- .value {
- flex: 1;
- color: #303133;
- word-break: break-all;
- }
- }
- .ocr-result-tip {
- padding: 10px 0;
- font-size: 14px;
- color: #909399;
- text-align: center;
- }
- }
- }
- }
- .form-content {
- max-width: 800px;
- margin: 0 auto;
- &.step2-form {
- max-width: 100%;
- .form-row {
- display: flex;
- gap: 40px;
- .form-col {
- flex: 1;
- }
- }
- }
- }
- .form-actions {
- display: flex;
- gap: 20px;
- justify-content: center;
- padding-top: 30px;
- margin-top: 40px;
- border-top: 1px solid #e4e7ed;
- .el-button {
- width: 200px;
- height: 44px;
- font-size: 16px;
- font-weight: 500;
- color: #ffffff;
- background: #6c8ff8;
- border: none;
- border-radius: 4px;
- outline: none;
- }
- }
- .pay-account-trigger {
- display: inline-flex;
- gap: 10px;
- align-items: center;
- &__text {
- font-size: 14px;
- color: #303133;
- }
- &__arrow {
- cursor: pointer;
- }
- }
- }
- </style>
- <style lang="scss">
- /* 弹窗挂到 body,需非 scoped;并抵消本页全局 .el-dialog__body { height: 600px } */
- .pay-account-setup-dialog.el-dialog {
- padding: 0;
- overflow: hidden;
- border-radius: 12px;
- box-shadow: 0 8px 32px rgb(0 0 0 / 12%);
- }
- .pay-account-setup-dialog .el-dialog__header {
- padding: 20px 24px 12px;
- margin: 0;
- }
- .pay-account-setup-dialog .el-dialog__headerbtn {
- top: 16px;
- right: 16px;
- font-size: 18px;
- }
- .pay-account-setup-dialog .el-dialog__body {
- height: auto !important;
- max-height: none !important;
- padding: 4px 24px 8px !important;
- overflow: visible !important;
- }
- .pay-account-setup-dialog .el-dialog__footer {
- padding: 16px 24px 24px;
- }
- .pay-account-setup-dialog__title {
- width: 100%;
- font-size: 17px;
- font-weight: 600;
- color: #303133;
- text-align: center;
- }
- .pay-account-option-list {
- display: flex;
- flex-direction: column;
- }
- .pay-account-option {
- display: flex;
- gap: 14px;
- align-items: center;
- width: 100%;
- padding: 16px 0;
- margin: 0;
- font: inherit;
- text-align: left;
- cursor: pointer;
- background: transparent;
- border: none;
- border-bottom: 1px solid #ebeef5;
- outline: none;
- }
- .pay-account-option:last-of-type {
- border-bottom: none;
- }
- .pay-account-option__icon {
- flex-shrink: 0;
- width: 36px;
- height: 36px;
- border-radius: 8px;
- }
- .pay-account-option__icon--alipay {
- background: #1677ff;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M8.5 7.2h2.2v1.9H8.5V7.2zm0 3.1h2.2v5.4H8.5v-5.4zm3.8-3.1h4.6c1.4 0 2.4 1 2.4 2.3 0 1.1-.7 2-1.7 2.3l1.9 3.8h-2.5l-1.6-3.2h-1.4v3.2h-2.2V7.2zm2.2 3.6h2.1c.6 0 1-.4 1-.9 0-.5-.4-.9-1-.9h-2.1v1.8z'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: center;
- background-size: 26px 26px;
- }
- .pay-account-option__icon--wechat {
- background: #07c160;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M8.5 10.5c-.8 0-1.5-.7-1.5-1.5S7.7 7.5 8.5 7.5 10 8.2 10 9s-.7 1.5-1.5 1.5zm7 0c-.8 0-1.5-.7-1.5-1.5S14.7 7.5 15.5 7.5 17 8.2 17 9s-.7 1.5-1.5 1.5z'/%3E%3Cpath fill='%23fff' d='M9 14.5c-2.5 0-4.5-1.6-4.5-3.5 0-1 .5-1.9 1.3-2.6-.1-.3-.2-.7-.2-1C5.6 5.8 8.9 4 13 4s7.4 1.8 7.4 4c0 .4-.1.8-.2 1 .8.7 1.3 1.6 1.3 2.6 0 1.9-2 3.5-4.5 3.5-.6 0-1.2-.1-1.8-.3l-2 1.1.5-1.8c-.9-.5-1.6-1.2-2-2z'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: center;
- background-size: 24px 24px;
- }
- .pay-account-option__icon--bank {
- background-color: #3b7cff;
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='7' width='18' height='11' rx='2' fill='%23fff' opacity='.95'/%3E%3Crect x='3' y='10' width='18' height='2' fill='%233b7cff'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: center;
- background-size: 28px 22px;
- }
- .pay-account-option__label {
- flex: 1;
- font-size: 15px;
- color: #303133;
- }
- .pay-account-option__radio {
- display: flex;
- flex-shrink: 0;
- align-items: center;
- justify-content: center;
- width: 22px;
- height: 22px;
- border: 2px solid #dcdfe6;
- border-radius: 50%;
- transition:
- border-color 0.2s,
- background 0.2s;
- }
- .pay-account-option__radio.is-checked {
- background: #7395ff;
- border-color: #7395ff;
- }
- .pay-account-option__check {
- font-size: 14px;
- font-weight: 700;
- color: #ffffff;
- }
- .pay-account-setup-dialog__confirm {
- width: 100%;
- height: 44px;
- font-size: 16px;
- font-weight: 500;
- color: #ffffff;
- background: #7395ff !important;
- border-color: #7395ff !important;
- border-radius: 8px;
- }
- .pay-account-setup-dialog__confirm:hover {
- background: #5f82f0 !important;
- border-color: #5f82f0 !important;
- }
- </style>
|