Просмотр исходного кода

Merge remote-tracking branch 'origin/development_new' into development_new

spy 2 недель назад
Родитель
Сommit
43a7e1b925

+ 2 - 2
src/api/modules/homeEntry.ts

@@ -116,6 +116,6 @@ export const getSecondLevelList = (params: { parentDictId: string }) => {
 };
 
 // 经营板块三级分类接口 - 三级分类
-export const getThirdLevelList = (params: { parentDictId: string }) => {
-  return http.get(PORT_NONE + `/businessSection/getThirdLevelList`, params, { loading: false });
+export const getThirdLevelList = (parentDictId: string) => {
+  return http.get(PORT_NONE + `/businessSection/getThirdLevelList`, { parentDictId }, { loading: false });
 };

+ 6 - 2
src/api/modules/storeDecoration.ts

@@ -9,14 +9,18 @@ import httpApi from "@/api/indexApi";
 
 //获取商铺经营板块列表
 export const getBusinessSection = () => {
-  return httpApi.get(`/alienStorePlatform/storePlatformRenovation/getBusinessSection`, {}, { loading: false });
+  return httpApi.get(`/alienStorePlatform/businessSection/getFirstLevelList`, {}, { loading: false });
 };
 
 //获取商铺经营种类列表
 export const getBusinessSectionTypes = params => {
-  return httpApi.get(`/alienStorePlatform/storePlatformRenovation/getBusinessSectionTypes`, params, { loading: false });
+  return httpApi.get(`/alienStorePlatform/businessSection/getSecondLevelList`, params, { loading: false });
 };
 
+//获取商铺经营分类
+export const getThirdLevelList = params => {
+  return httpApi.get(`/alienStorePlatform/businessSection/getThirdLevelList`, params, { loading: false });
+};
 //所在地区
 export const getDistrict = (params?: any) => {
   return httpApi.get(`/alienStore/gaode/getDistrict`, params, { loading: false });

+ 3 - 73
src/assets/json/authMenuList.json

@@ -371,7 +371,7 @@
           "name": "entertainmentLicense",
           "component": "/licenseManagement/entertainmentLicense",
           "meta": {
-            "icon": "Memo",
+            "icon": "CreditCard",
             "title": "娱乐经营许可证",
             "isLink": "",
             "isHide": false,
@@ -532,7 +532,7 @@
         "icon": "Operation",
         "title": "运营管理",
         "isLink": "",
-        "isHide": true,
+        "isHide": false,
         "isFull": false,
         "isAffix": false,
         "isKeepAlive": false
@@ -623,83 +623,13 @@
             "icon": "FolderOpened",
             "title": "优惠券发放记录",
             "isLink": "",
-            "isHide": false,
+            "isHide": true,
             "isFull": false,
             "isAffix": false,
             "isKeepAlive": false
           }
         }
       ]
-    },
-    {
-      "path": "/barManagement",
-      "name": "barManagement",
-      "component": "/barManagement/index",
-      "meta": {
-        "icon": "Shop",
-        "title": "酒吧",
-        "isLink": "",
-        "isHide": false,
-        "isFull": false,
-        "isAffix": false,
-        "isKeepAlive": false
-      }
-    },
-    {
-      "path": "/footManagement",
-      "name": "footManagement",
-      "component": "/footManagement/index",
-      "meta": {
-        "icon": "User",
-        "title": "按摩足疗",
-        "isLink": "",
-        "isHide": false,
-        "isFull": false,
-        "isAffix": false,
-        "isKeepAlive": false
-      }
-    },
-    {
-      "path": "/hairManagement",
-      "name": "hairManagement",
-      "component": "/hairManagement/index",
-      "meta": {
-        "icon": "Star",
-        "title": "丽人美发",
-        "isLink": "",
-        "isHide": false,
-        "isFull": false,
-        "isAffix": false,
-        "isKeepAlive": false
-      }
-    },
-    {
-      "path": "/fitnessManagement",
-      "name": "fitnessManagement",
-      "component": "/fitnessManagement/index",
-      "meta": {
-        "icon": "Trophy",
-        "title": "运动健身",
-        "isLink": "",
-        "isHide": false,
-        "isFull": false,
-        "isAffix": false,
-        "isKeepAlive": false
-      }
-    },
-    {
-      "path": "/spaManagement",
-      "name": "spaManagement",
-      "component": "/spaManagement/index",
-      "meta": {
-        "icon": "Sunny",
-        "title": "洗浴汗蒸",
-        "isLink": "",
-        "isHide": false,
-        "isFull": false,
-        "isAffix": false,
-        "isKeepAlive": false
-      }
     }
   ],
   "msg": "成功"

+ 47 - 26
src/utils/permission.ts

@@ -51,11 +51,12 @@ export async function usePermission(tip?: string) {
 
 /**
  * @description 检查菜单访问权限(新方法)
- * @returns {Object} 返回合同管理和食品经营许可证的权限状态
+ * @returns {Object} 返回合同管理、食品经营许可证、娱乐经营许可证的权限状态
  */
 export async function checkMenuAccessPermission(): Promise<{
   contractManagement: boolean;
   foodBusinessLicense: boolean;
+  entertainmentBusinessLicense: boolean;
 }> {
   try {
     // 调用单个API,返回两个字段
@@ -79,23 +80,33 @@ export async function checkMenuAccessPermission(): Promise<{
         foodPermission = value == "0";
       }
 
+      // 解析娱乐经营许可证权限
+      let entertainmentPermission = false;
+      if (data.entertainmentLicenceExpirationTime !== undefined) {
+        const value = data.entertainmentLicenceExpirationTime;
+        entertainmentPermission = value == "0";
+      }
+
       return {
         contractManagement: contractPermission,
-        foodBusinessLicense: foodPermission
+        foodBusinessLicense: foodPermission,
+        entertainmentBusinessLicense: entertainmentPermission
       };
     }
 
-    // 如果API调用失败或返回格式不正确,默认返回两个都为false(不做限制)
+    // 如果API调用失败或返回格式不正确,默认返回都为 false(不做限制)
     return {
       contractManagement: false,
-      foodBusinessLicense: false
+      foodBusinessLicense: false,
+      entertainmentBusinessLicense: false
     };
   } catch (error) {
     console.error("检查菜单权限失败:", error);
-    // 如果API调用失败,默认返回两个都为false(不做限制)
+    // 如果API调用失败,默认返回都为 false(不做限制)
     return {
       contractManagement: false,
-      foodBusinessLicense: false
+      foodBusinessLicense: false,
+      entertainmentBusinessLicense: false
     };
   }
 }
@@ -103,31 +114,34 @@ export async function checkMenuAccessPermission(): Promise<{
 /**
  * @description 检查菜单项是否可以点击
  * @param {string} path 菜单路径
- * @returns {Promise<Object>} 返回包含canClick、contractManagement、foodBusinessLicense的对象
+ * @returns {Promise<Object>} 返回包含 canClick、contractManagement、foodBusinessLicense、entertainmentBusinessLicense 的对象
  */
 export async function checkMenuClickPermission(path?: string): Promise<{
   canClick: boolean;
   contractManagement: boolean;
   foodBusinessLicense: boolean;
+  entertainmentBusinessLicense: boolean;
 }> {
   // 页面路径常量
   const CONTRACT_MANAGEMENT_PATH = "/licenseManagement/contractManagement"; // 合同管理
   const FOOD_BUSINESS_LICENSE_PATH = "/licenseManagement/foodBusinessLicense"; // 食品经营许可证
+  const ENTERTAINMENT_LICENSE_PATH = "/licenseManagement/entertainmentLicense"; // 娱乐经营许可证
 
   // 调用权限检查方法,获取两个权限状态
   const permissions = await checkMenuAccessPermission();
-  const { contractManagement, foodBusinessLicense } = permissions;
+  const { contractManagement, foodBusinessLicense, entertainmentBusinessLicense } = permissions;
 
-  // 如果两者都为false,不做限制,所有页面都可以点击
-  if (!contractManagement && !foodBusinessLicense) {
+  // 如果全部为 false,不做限制,所有页面都可以点击
+  if (!contractManagement && !foodBusinessLicense && !entertainmentBusinessLicense) {
     return {
       canClick: true,
       contractManagement: false,
-      foodBusinessLicense: false
+      foodBusinessLicense: false,
+      entertainmentBusinessLicense: false
     };
   }
 
-  // 如果至少有一个为true,需要检查权限
+  // 如果至少有一个为 true,需要检查权限
   // 构建允许访问的路径列表
   const allowedPaths: string[] = [];
   if (contractManagement) {
@@ -136,6 +150,9 @@ export async function checkMenuClickPermission(path?: string): Promise<{
   if (foodBusinessLicense) {
     allowedPaths.push(FOOD_BUSINESS_LICENSE_PATH);
   }
+  if (entertainmentBusinessLicense) {
+    allowedPaths.push(ENTERTAINMENT_LICENSE_PATH);
+  }
 
   const canClick = true;
   // 检查当前路径是否在允许访问的列表中
@@ -144,21 +161,24 @@ export async function checkMenuClickPermission(path?: string): Promise<{
 
     // 如果不可点击,根据权限状态显示相应的提示信息
     if (!canClick) {
-      let message = "";
-
-      // 如果两者都为true,显示两行提示
-      if (contractManagement && foodBusinessLicense) {
-        message = "合同已到期,请上传最新合同。\n经营许可证已到期,请上传最新许可证。";
-      } else if (contractManagement) {
-        // 只有合同管理为true
-        message = "合同已到期,请上传最新合同。";
-      } else if (foodBusinessLicense) {
-        // 只有食品经营许可证为true
-        message = "经营许可证已到期,请上传最新许可证。";
+      const messages: string[] = [];
+
+      if (contractManagement) {
+        messages.push("合同已到期,请上传最新合同。");
+      }
+      if (foodBusinessLicense) {
+        messages.push("食品经营许可证已到期,请上传最新许可证。");
+      }
+      if (entertainmentBusinessLicense) {
+        messages.push("娱乐经营许可证已到期,请上传最新许可证。");
       }
 
-      if (message) {
-        ElMessage.warning(message);
+      if (messages.length) {
+        ElMessage.warning({
+          // message: messages.join('\n'),
+          message: messages.join("<br>"),
+          dangerouslyUseHTMLString: true
+        });
       }
     }
   }
@@ -166,6 +186,7 @@ export async function checkMenuClickPermission(path?: string): Promise<{
   return {
     canClick,
     contractManagement,
-    foodBusinessLicense
+    foodBusinessLicense,
+    entertainmentBusinessLicense
   };
 }

+ 46 - 9
src/views/barManagement/go-flow.vue

@@ -157,6 +157,14 @@
                   <el-checkbox v-for="item in secondLevelList" :key="item.dictId" :label="item.dictDetail" :value="item.dictId" />
                 </el-checkbox-group>
               </el-form-item>
+
+              <el-form-item label="是否提供餐食" prop="businessSecondMeal">
+                <el-radio-group v-model="step2Form.businessSecondMeal">
+                  <el-radio v-for="item in secondMealList" :value="item.value" :key="item.key">
+                    {{ item.dictDetail }}
+                  </el-radio>
+                </el-radio-group>
+              </el-form-item>
             </div>
 
             <!-- 右列 -->
@@ -350,6 +358,10 @@ const handleNextStep = async () => {
   setStep(2);
 };
 
+const secondMealList = ref([
+  { key: 0, value: 0, dictDetail: "提供" },
+  { key: 1, value: 1, dictDetail: "不提供" }
+]);
 const step2Rules: FormRules = {
   storeName: [{ required: true, message: "请输入店铺名称", trigger: "blur" }],
   storeCapacity: [{ required: true, message: "请输入容纳人数", trigger: "blur" }],
@@ -357,6 +369,7 @@ const step2Rules: FormRules = {
   storeBlurb: [{ required: true, message: "请输入门店简介", trigger: "change" }],
   storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
   businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
+  businessSecondMeal: [{ required: true, message: "请选择是否提供餐食", trigger: "change" }],
   businessTypes: [
     {
       required: true,
@@ -522,6 +535,7 @@ const setStep = (val: number) => {
 // 第二步表单
 const step2FormRef = ref<FormInstance>();
 const step2Form = reactive({
+  businessSecondMeal: 0,
   storeName: "",
   storeCapacity: 1,
   storeArea: "1",
@@ -533,7 +547,7 @@ const step2Form = reactive({
   administrativeRegionDistrictAdcode: "",
   storeAddress: "",
   storeBlurb: "",
-  businessSection: "",
+  businessSection: "1",
   businessSectionName: "",
   businessSecondLevel: "",
   businessTypes: [],
@@ -790,11 +804,37 @@ const autoOcrRecognition = async () => {
     const res: any = await ocrRequestUrl(params);
     if (res && (res.code === 200 || res.code === "200")) {
       // 保存识别结果
-      if (res.data) {
-        console.log(res.data[0]);
+      if (res.data && Array.isArray(res.data) && res.data.length > 0) {
+        // 从正面(第一个元素)获取姓名
+        const frontData = res.data[0]?.face?.data;
+        // 从反面(第二个元素)获取身份证号,如果没有第二个元素则从正面获取
+        const backData = res.data[1]?.face?.data || frontData;
+
+        // 提取姓名
+        const name = frontData?.name || "";
+
+        // 提取身份证号,优先从反面获取,如果没有则从正面获取
+        let idCard = backData?.idNumber || frontData?.idNumber || "";
+
+        // 如果从 data 中获取不到,尝试从 prism_keyValueInfo 中查找
+        if (!idCard && res.data[1]?.face?.prism_keyValueInfo) {
+          const idNumberInfo = res.data[1].face.prism_keyValueInfo.find((item: any) => item.key === "idNumber" && item.value);
+          if (idNumberInfo) {
+            idCard = idNumberInfo.value;
+          }
+        }
+
+        // 如果反面没有,尝试从正面查找
+        if (!idCard && res.data[0]?.face?.prism_keyValueInfo) {
+          const idNumberInfo = res.data[0].face.prism_keyValueInfo.find((item: any) => item.key === "idNumber" && item.value);
+          if (idNumberInfo) {
+            idCard = idNumberInfo.value;
+          }
+        }
+
         ocrResult.value = {
-          name: res.data.name || res.data.realName || "",
-          idCard: res.data.idCard || res.data.idNumber || res.data.idNo || ""
+          name: name,
+          idCard: idCard
         };
 
         // 更新本地存储中的用户信息
@@ -1187,12 +1227,9 @@ const handleExceed = () => {
 
       // OCR 识别结果展示样式
       .ocr-result-container {
-        width: 635px;
+        width: 670px;
         padding: 20px;
         margin: 60px auto;
-        background-color: #f5f7fa;
-        border: 1px solid #e4e7ed;
-        border-radius: 8px;
         .ocr-result-item {
           display: flex;
           align-items: center;

+ 0 - 1252
src/views/fitnessManagement/go-flow.vue

@@ -1,1252 +0,0 @@
-<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="handleUploadSuccess"
-              :on-preview="handlePictureCardPreview"
-              :on-remove="handleRemove"
-              accept="image/*"
-              class="id-card-upload"
-              :class="{ 'upload-complete': isIdCardUploadComplete }"
-            >
-              <template v-if="idCardFrontList.length === 0 && !isIdCardUploadComplete">
-                <div class="upload-placeholder">
-                  <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="handleUploadSuccess"
-              :on-preview="handlePictureCardPreview"
-              :on-remove="handleRemove"
-              accept="image/*"
-              class="id-card-upload"
-              :class="{ 'upload-complete': isIdCardUploadComplete }"
-            >
-              <template v-if="idCardBackList.length === 0 && !isIdCardUploadComplete">
-                <div class="upload-placeholder">
-                  <span class="placeholder-text">示例图</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="businessSecondMeal">
-                <el-radio-group v-model="step2Form.businessSecondMeal">
-                  <el-radio v-for="item in secondMealList" :value="item.value" :key="item.key">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营板块" prop="businessSection">
-                <el-radio-group v-model="step2Form.businessSection" @change="changeBusinessSector">
-                  <el-radio v-for="businessSection in businessSectionList" :value="businessSection.id" :key="businessSection.id">
-                    {{ businessSection.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营种类" prop="businessSecondLevel" v-if="secondLevelList.length > 0">
-                <el-radio-group v-model="step2Form.businessSecondLevel" @change="changeBusinessSecondLevel">
-                  <el-radio v-for="item in secondLevelList" :value="item.dictId" :key="item.dictId">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <!-- 如果没有三级分类,则显示二级分类作为经营种类 -->
-              <el-form-item label="分类" prop="businessTypes" v-if="secondLevelList.length > 0 && thirdLevelList.length === 0">
-                <el-checkbox-group v-model="step2Form.businessTypes">
-                  <el-checkbox v-for="item in secondLevelList" :key="item.dictId" :label="item.dictDetail" :value="item.dictId" />
-                </el-checkbox-group>
-              </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>
-
-              <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="handleUploadSuccess"
-                  :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="contractImageList">
-                <el-upload
-                  v-model:file-list="step2Form.contractImageList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="20"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.contractImageList.length }}/20)</div>
-                  </template>
-                </el-upload>
-              </el-form-item>
-
-              <el-form-item label="食品经营许可证" prop="foodLicenceImgList">
-                <el-upload
-                  v-model:file-list="step2Form.foodLicenceImgList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="1"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.foodLicenceImgList.length }}/1)</div>
-                  </template>
-                </el-upload>
-              </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>
-
-  <!-- 图片预览 -->
-  <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 } from "vue";
-import {
-  ElMessage,
-  ElMessageBox,
-  type FormInstance,
-  type FormRules,
-  UploadProps,
-  UploadUserFile,
-  UploadRequestOptions
-} from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-
-import {
-  applyStore,
-  getMerchantByPhone,
-  getFirstLevelList,
-  getSecondLevelList,
-  getThirdLevelList
-} from "@/api/modules/homeEntry";
-import { getInputPrompt, getDistrict, uploadImg, ocrRequestUrl } from "@/api/modules/newLoginApi";
-import { localGet, localSet } from "@/utils/index";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const userInfo = localGet("geeker-user")?.userInfo || {};
-const latShow = ref(false);
-
-// 图片预览相关
-const imageViewerVisible = ref(false);
-const imageViewerUrlList = ref<string[]>([]);
-const imageViewerInitialIndex = ref(0);
-
-const entryList = ref([
-  {
-    title: "个人实名"
-  },
-  {
-    title: "填写信息"
-  },
-  {
-    title: "等待审核"
-  },
-  {
-    title: "入驻成功"
-  }
-]);
-
-// 身份证正反面上传列表
-const idCardFrontList = ref<UploadUserFile[]>([]);
-const idCardBackList = ref<UploadUserFile[]>([]);
-
-// OCR 识别结果
-const ocrResult = ref<{
-  name?: string;
-  idCard?: string;
-}>({});
-
-// 是否正在识别中
-const isOcrProcessing = ref(false);
-
-// 计算是否已上传完成(正反面都上传完成)
-const isIdCardUploadComplete = computed(() => {
-  return idCardFrontList.value.length > 0 && idCardBackList.value.length > 0;
-});
-// 下一步 - 验证身份证正反面是否已上传
-const handleNextStep = async () => {
-  // 识别成功,进入下一步
-  setStep(2);
-};
-
-const secondMealList = ref([
-  { key: 0, value: 0, dictDetail: "提供" },
-  { key: 1, value: 1, dictDetail: "不提供" }
-]);
-
-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" }],
-  storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
-  businessSecondMeal: [{ required: true, message: "请选择是否提供餐食", trigger: "change" }],
-  businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
-  businessTypes: [
-    {
-      required: true,
-      message: "请选择经营种类",
-      trigger: "change",
-      validator: (rule: any, value: any, callback: any) => {
-        if (!value || value.length === 0) {
-          callback(new Error("请选择经营种类"));
-        } else {
-          callback();
-        }
-      }
-    }
-  ],
-  address: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
-  businessLicenseAddress: [{ required: true, message: "请上传营业执照", trigger: "change" }],
-  contractImageList: [{ required: true, message: "请上传合同图片", trigger: "change" }],
-  foodLicenceImgList: [{ 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 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(() => {
-  getBusinessSectionList();
-  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({
-  businessSecondMeal: 0,
-  storeName: "",
-  storeCapacity: 1,
-  storeArea: "1",
-  isChain: 0,
-  storeDetailAddress: "",
-  region: [],
-  administrativeRegionProvinceAdcode: "",
-  administrativeRegionCityAdcode: "",
-  administrativeRegionDistrictAdcode: "",
-  storeAddress: "",
-  storeBlurb: "",
-  businessSection: "",
-  businessSectionName: "",
-  businessSecondLevel: "",
-  businessTypes: [],
-  businessTypesList: [],
-  businessStatus: 0,
-  storeStatus: 1,
-  businessType: "正常营业",
-  storePositionLongitude: "",
-  storePositionLatitude: "",
-  businessLicenseAddress: [] as UploadUserFile[],
-  contractImageList: [] as UploadUserFile[],
-  foodLicenceImgList: [] as UploadUserFile[],
-  address: ""
-});
-
-// 返回按钮
-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 businessSectionList = ref<any[]>([]);
-const getBusinessSectionList = async () => {
-  try {
-    const res: any = await getFirstLevelList({});
-    if (res && res.code === 200 && res.data) {
-      businessSectionList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取一级分类失败:", error);
-    ElMessage.error("获取经营板块失败");
-  }
-};
-
-// 二级分类列表
-const secondLevelList = ref<any[]>([]);
-// 三级分类列表
-const thirdLevelList = ref<any[]>([]);
-
-// 一级分类变化时,加载二级分类
-const changeBusinessSector = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    secondLevelList.value = [];
-    thirdLevelList.value = [];
-    step2Form.businessSecondLevel = "";
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 更新一级分类信息
-  const selectedSection = businessSectionList.value.find((item: any) => item.dictId === dictIdStr);
-  if (selectedSection) {
-    step2Form.businessSection = selectedSection.dictId;
-    step2Form.businessSectionName = selectedSection.dictDetail;
-  }
-
-  // 清空二级和三级分类
-  secondLevelList.value = [];
-  thirdLevelList.value = [];
-  step2Form.businessSecondLevel = "";
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载二级分类
-  try {
-    const res: any = await getSecondLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      secondLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取二级分类失败:", error);
-    ElMessage.error("获取经营种类失败");
-  }
-};
-
-// 二级分类变化时,加载三级分类
-const changeBusinessSecondLevel = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    thirdLevelList.value = [];
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 清空三级分类
-  thirdLevelList.value = [];
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载三级分类
-  try {
-    const res: any = await getThirdLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      thirdLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取三级分类失败:", error);
-    // 如果没有三级分类,不显示错误,因为可能该二级分类下没有三级分类
-  }
-};
-
-// 经纬度查询
-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 (param: any) => {
-  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 () => {
-  // 检查正反面是否都已上传完成
-  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;
-  }
-
-  // 如果正在识别中,不重复调用
-  if (isOcrProcessing.value) {
-    return;
-  }
-
-  // 将正反面 URL 用逗号分隔
-  const imageUrls = `${frontUrl},${backUrl}`;
-
-  let params = {
-    imageUrls: imageUrls,
-    ocrType: "ID_CARD",
-    storeId: userInfo.storeId,
-    storeUserId: userInfo.id
-  };
-
-  try {
-    isOcrProcessing.value = true;
-    const res: any = await ocrRequestUrl(params);
-    if (res && (res.code === 200 || res.code === "200")) {
-      // 保存识别结果
-      if (res.data) {
-        console.log(res.data[0]);
-        ocrResult.value = {
-          name: res.data.name || res.data.realName || "",
-          idCard: res.data.idCard || res.data.idNumber || res.data.idNo || ""
-        };
-
-        // 更新本地存储中的用户信息
-        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 {
-      console.warn("OCR 识别失败:", res?.msg);
-    }
-  } catch (error) {
-    console.error("身份证识别失败:", error);
-  } finally {
-    isOcrProcessing.value = false;
-  }
-};
-
-// 文件上传成功回调
-const handleUploadSuccess = (response: any, uploadFile: UploadUserFile) => {
-  if (response?.fileUrl) {
-    uploadFile.url = response.fileUrl;
-  }
-
-  // 延迟一下,确保文件状态已更新,然后检查是否需要自动 OCR
-  setTimeout(() => {
-    autoOcrRecognition();
-  }, 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;
-  }
-
-  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;
-};
-
-// 提取文件列表中的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;
-};
-
-// 提交
-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 whereAddress = await buildWhereAddress(step2Form.region);
-
-      let storeStatus = 1;
-      if (step2Form.businessType === "正常营业") {
-        storeStatus = 1;
-      } else if (step2Form.businessType === "暂停营业") {
-        storeStatus = 0;
-      } else if (step2Form.businessType === "筹建中") {
-        storeStatus = 2;
-      }
-
-      const storeAreaNum = typeof step2Form.storeArea === "string" ? parseInt(step2Form.storeArea) : step2Form.storeArea;
-
-      const addressObj = {
-        address: queryAddress.value || "",
-        longitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        latitude: parseFloat(step2Form.storePositionLatitude) || 0
-      };
-
-      const storePosition =
-        step2Form.storePositionLongitude && step2Form.storePositionLatitude
-          ? `${step2Form.storePositionLongitude},${step2Form.storePositionLatitude}`
-          : "";
-
-      let fullStoreAddress = "";
-      if (whereAddress.length > 0) {
-        const provinceName = whereAddress[0]?.name || "";
-        const cityName = whereAddress[1]?.name || "";
-        const districtName = whereAddress[2]?.name || "";
-        fullStoreAddress = `${provinceName}${cityName}${districtName}`;
-      }
-
-      // 获取身份证正反面URL
-      const idCardFrontUrl = getFileUrls(idCardFrontList.value)[0] || "";
-      const idCardBackUrl = getFileUrls(idCardBackList.value)[0] || "";
-
-      // 处理经营种类:优先使用三级分类,如果没有三级分类则使用二级分类
-      let finalBusinessTypes: string[] = [];
-      if (step2Form.businessTypes.length > 0) {
-        // 有三级分类选择
-        finalBusinessTypes = step2Form.businessTypes;
-      } else if (step2Form.businessSecondLevel) {
-        // 没有三级分类,使用二级分类
-        finalBusinessTypes = [step2Form.businessSecondLevel];
-      } else {
-        // 都没有,使用旧的逻辑
-        finalBusinessTypes = step2Form.businessTypesList;
-      }
-
-      const params = {
-        storeTel: userInfo.phone,
-        storeName: step2Form.storeName,
-        storeCapacity: step2Form.storeCapacity,
-        storeArea: storeAreaNum,
-        isChain: step2Form.isChain,
-        storeDetailAddress: step2Form.storeDetailAddress,
-        storeBlurb: step2Form.storeBlurb,
-        businessSection: step2Form.businessSection,
-        businessTypesList: finalBusinessTypes,
-        storeStatus: storeStatus,
-        businessStatus: step2Form.businessStatus,
-        address: addressObj,
-        businessLicenseAddress: businessLicenseUrls,
-        contractImageList: contractImageUrls,
-        foodLicenceImgList: foodLicenceUrls,
-        disportLicenceUrls: disportLicenceUrls,
-        storeAddress: fullStoreAddress,
-        whereAddress: whereAddress,
-        updatedTime: null,
-        queryAddress: queryAddress.value,
-        storePosition: storePosition,
-        storePositionLatitude: parseFloat(step2Form.storePositionLatitude) || 0,
-        storePositionLongitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        businessSectionName: step2Form.businessSectionName,
-        businessTypes: finalBusinessTypes,
-        foodLicenceUrl: foodLicenceUrls.length > 0 ? foodLicenceUrls[0] : "",
-        userAccount: userInfo.id,
-        administrativeRegionProvinceAdcode: step2Form.administrativeRegionProvinceAdcode,
-        administrativeRegionCityAdcode: step2Form.administrativeRegionCityAdcode,
-        administrativeRegionDistrictAdcode: step2Form.administrativeRegionDistrictAdcode,
-        idCardFrontUrl: idCardFrontUrl,
-        idCardBackUrl: idCardBackUrl
-      };
-
-      ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      })
-        .then(async () => {
-          try {
-            const res: any = await applyStore(params);
-            if (res && res.code == 200) {
-              storeApplicationStatus.value = 0;
-              ElMessage.success(res.msg);
-              callGetUserInfo();
-              setStep(0);
-            } else {
-              ElMessage.error(res.msg || "提交失败");
-            }
-          } catch (error) {
-            ElMessage.error("提交失败,请重试");
-          }
-        })
-        .catch(() => {
-          // 取消提交
-        });
-    } else {
-      ElMessage.error("请完善表单信息");
-    }
-  });
-};
-
-// 文件上传超出限制
-const handleExceed = () => {
-  ElMessage.warning("文件数量超出限制");
-};
-</script>
-
-<style scoped lang="scss">
-// 表单页面样式
-.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: 635px;
-        padding: 20px;
-        margin: 60px auto;
-        background-color: #f5f7fa;
-        border: 1px solid #e4e7ed;
-        border-radius: 8px;
-        .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;
-    }
-  }
-}
-</style>

+ 0 - 99
src/views/fitnessManagement/index.vue

@@ -1,99 +0,0 @@
-<template>
-  <div id="home">
-    <!--已入驻-->
-    <go-examine v-if="isExaime" />
-    <!-- 第一步  未入驻 -->
-    <go-enter
-      :current-step="currentStep"
-      :store-application-status="storeApplicationStatus"
-      @update:current-step="handleUpdateCurrentStep"
-    />
-    <!-- 第二步 
-      @update:get-user-info="getUserInfo"-->
-    <go-flow
-      :current-step="currentStep"
-      @update:current-step="handleUpdateCurrentStep"
-      :store-application-status="storeApplicationStatus"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, ref, watch } from "vue";
-import { localGet, localSet } from "@/utils/index";
-import goEnter from "../home/components/go-enter.vue";
-import goFlow from "./go-flow.vue";
-import goExamine from "../home/components/go-examine.vue";
-import { getMerchantByPhone, getDetail } from "@/api/modules/homeEntry";
-import { is } from "@/utils/is";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const isEntry = ref<boolean>(false);
-const isExaime = ref<boolean>(false);
-
-onMounted(() => {
-  //   getUserInfo();
-});
-
-// 当前步骤:0-首页,1-第一步,2-第二步
-const currentStep = ref(0);
-const storeId = ref<Number | undefined>(undefined);
-// 处理更新currentStep事件
-const handleUpdateCurrentStep = (step: number) => {
-  currentStep.value = step;
-};
-let storeApplicationStatus = ref<number | undefined>(undefined);
-
-// const getUserInfo = async () => {
-//   try {
-//     const geekerUser = localGet("geeker-user");
-//     if (!geekerUser || !geekerUser.userInfo || !geekerUser.userInfo.phone) {
-//       console.error("用户信息不存在");
-//       return;
-//     }
-//     let param = {
-//       phone: geekerUser.userInfo.phone
-//     };
-//     const res: any = await getMerchantByPhone(param);
-//     storeId.value = res.data.storeId;
-//     if (res && res.code == 200 && res.data) {
-//       // 更新缓存中的 storeId
-//       geekerUser.userInfo.storeId = res.data.storeId;
-//       localSet("geeker-user", geekerUser);
-//       // 同时更新 createdId 缓存
-//       if (res.data.storeId) {
-//         localSet("createdId", res.data.storeId);
-//       }
-//       if (res.data.storeId == null) {
-//         isEntry.value = true;
-//       }
-//       if (res.data.storeId != null) {
-//         let param1 = {
-//           id: res.data.storeId
-//         };
-//         const resStore: any = await getDetail(param1);
-//         if (resStore && resStore.code == 200 && resStore.data) {
-//         //   storeApplicationStatus.value = resStore.data.storeApplicationStatus;
-//         //   // 如果是等待审核(0)或审核拒绝(2),且当前步骤为0,显示 go-enter 组件
-//         //   // 如果用户已经主动跳转到其他步骤,则不重置步骤
-//         //   if ((storeApplicationStatus.value == 0 || storeApplicationStatus.value == 2) && currentStep.value === 0) {
-//         //     currentStep.value = 0;
-//         //   }
-
-//           if (resStore.data.storeApplicationStatus !== 1 && res.data.storeId != null) {
-//             //storeId && storeDetail.storeApplicationStatus === 1
-//             isEntry.value = true;
-//           } else {
-//             isExaime.value = true;
-//           }
-//         }
-//       }
-//     }
-//   } catch (error) {
-//     console.error(error);
-//   }
-// };
-</script>
-
-<style scoped lang="scss"></style>

+ 0 - 1252
src/views/footManagement/go-flow.vue

@@ -1,1252 +0,0 @@
-<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="handleUploadSuccess"
-              :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">
-                  <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="handleUploadSuccess"
-              :on-preview="handlePictureCardPreview"
-              :on-remove="handleRemove"
-              accept="image/*"
-              class="id-card-upload"
-              :class="{ 'upload-complete': isIdCardUploadComplete }"
-            >
-              <template v-if="idCardBackList.length === 0 && !isIdCardUploadComplete">
-                <div class="upload-placeholder">
-                  <span class="placeholder-text">示例图</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="businessSecondMeal">
-                <el-radio-group v-model="step2Form.businessSecondMeal">
-                  <el-radio v-for="item in secondMealList" :value="item.value" :key="item.key">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营板块" prop="businessSection">
-                <el-radio-group v-model="step2Form.businessSection" @change="changeBusinessSector">
-                  <el-radio v-for="businessSection in businessSectionList" :value="businessSection.id" :key="businessSection.id">
-                    {{ businessSection.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营种类" prop="businessSecondLevel" v-if="secondLevelList.length > 0">
-                <el-radio-group v-model="step2Form.businessSecondLevel" @change="changeBusinessSecondLevel">
-                  <el-radio v-for="item in secondLevelList" :value="item.dictId" :key="item.dictId">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <!-- 如果没有三级分类,则显示二级分类作为经营种类 -->
-              <el-form-item label="分类" prop="businessTypes" v-if="secondLevelList.length > 0 && thirdLevelList.length === 0">
-                <el-checkbox-group v-model="step2Form.businessTypes">
-                  <el-checkbox v-for="item in secondLevelList" :key="item.dictId" :label="item.dictDetail" :value="item.dictId" />
-                </el-checkbox-group>
-              </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>
-
-              <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="handleUploadSuccess"
-                  :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="contractImageList">
-                <el-upload
-                  v-model:file-list="step2Form.contractImageList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="20"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.contractImageList.length }}/20)</div>
-                  </template>
-                </el-upload>
-              </el-form-item>
-
-              <el-form-item label="食品经营许可证" prop="foodLicenceImgList">
-                <el-upload
-                  v-model:file-list="step2Form.foodLicenceImgList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="1"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.foodLicenceImgList.length }}/1)</div>
-                  </template>
-                </el-upload>
-              </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>
-
-  <!-- 图片预览 -->
-  <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 } from "vue";
-import {
-  ElMessage,
-  ElMessageBox,
-  type FormInstance,
-  type FormRules,
-  UploadProps,
-  UploadUserFile,
-  UploadRequestOptions
-} from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-
-import {
-  applyStore,
-  getMerchantByPhone,
-  getFirstLevelList,
-  getSecondLevelList,
-  getThirdLevelList
-} from "@/api/modules/homeEntry";
-import { getInputPrompt, getDistrict, uploadImg, ocrRequestUrl } from "@/api/modules/newLoginApi";
-import { localGet, localSet } from "@/utils/index";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const userInfo = localGet("geeker-user")?.userInfo || {};
-const latShow = ref(false);
-
-// 图片预览相关
-const imageViewerVisible = ref(false);
-const imageViewerUrlList = ref<string[]>([]);
-const imageViewerInitialIndex = ref(0);
-
-const entryList = ref([
-  {
-    title: "个人实名"
-  },
-  {
-    title: "填写信息"
-  },
-  {
-    title: "等待审核"
-  },
-  {
-    title: "入驻成功"
-  }
-]);
-
-// 身份证正反面上传列表
-const idCardFrontList = ref<UploadUserFile[]>([]);
-const idCardBackList = ref<UploadUserFile[]>([]);
-
-// OCR 识别结果
-const ocrResult = ref<{
-  name?: string;
-  idCard?: string;
-}>({});
-
-// 是否正在识别中
-const isOcrProcessing = ref(false);
-
-// 计算是否已上传完成(正反面都上传完成)
-const isIdCardUploadComplete = computed(() => {
-  return idCardFrontList.value.length > 0 && idCardBackList.value.length > 0;
-});
-// 下一步 - 验证身份证正反面是否已上传
-const handleNextStep = async () => {
-  // 识别成功,进入下一步
-  setStep(2);
-};
-
-const secondMealList = ref([
-  { key: 0, value: 0, dictDetail: "提供" },
-  { key: 1, value: 1, dictDetail: "不提供" }
-]);
-
-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" }],
-  storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
-  businessSecondMeal: [{ required: true, message: "请选择是否提供餐食", trigger: "change" }],
-  businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
-  businessTypes: [
-    {
-      required: true,
-      message: "请选择经营种类",
-      trigger: "change",
-      validator: (rule: any, value: any, callback: any) => {
-        if (!value || value.length === 0) {
-          callback(new Error("请选择经营种类"));
-        } else {
-          callback();
-        }
-      }
-    }
-  ],
-  address: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
-  businessLicenseAddress: [{ required: true, message: "请上传营业执照", trigger: "change" }],
-  contractImageList: [{ required: true, message: "请上传合同图片", trigger: "change" }],
-  foodLicenceImgList: [{ 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 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(() => {
-  getBusinessSectionList();
-  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({
-  businessSecondMeal: 0,
-  storeName: "",
-  storeCapacity: 1,
-  storeArea: "1",
-  isChain: 0,
-  storeDetailAddress: "",
-  region: [],
-  administrativeRegionProvinceAdcode: "",
-  administrativeRegionCityAdcode: "",
-  administrativeRegionDistrictAdcode: "",
-  storeAddress: "",
-  storeBlurb: "",
-  businessSection: "",
-  businessSectionName: "",
-  businessSecondLevel: "",
-  businessTypes: [],
-  businessTypesList: [],
-  businessStatus: 0,
-  storeStatus: 1,
-  businessType: "正常营业",
-  storePositionLongitude: "",
-  storePositionLatitude: "",
-  businessLicenseAddress: [] as UploadUserFile[],
-  contractImageList: [] as UploadUserFile[],
-  foodLicenceImgList: [] as UploadUserFile[],
-  address: ""
-});
-
-// 返回按钮
-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 businessSectionList = ref<any[]>([]);
-const getBusinessSectionList = async () => {
-  try {
-    const res: any = await getFirstLevelList({});
-    if (res && res.code === 200 && res.data) {
-      businessSectionList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取一级分类失败:", error);
-    ElMessage.error("获取经营板块失败");
-  }
-};
-
-// 二级分类列表
-const secondLevelList = ref<any[]>([]);
-// 三级分类列表
-const thirdLevelList = ref<any[]>([]);
-
-// 一级分类变化时,加载二级分类
-const changeBusinessSector = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    secondLevelList.value = [];
-    thirdLevelList.value = [];
-    step2Form.businessSecondLevel = "";
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 更新一级分类信息
-  const selectedSection = businessSectionList.value.find((item: any) => item.dictId === dictIdStr);
-  if (selectedSection) {
-    step2Form.businessSection = selectedSection.dictId;
-    step2Form.businessSectionName = selectedSection.dictDetail;
-  }
-
-  // 清空二级和三级分类
-  secondLevelList.value = [];
-  thirdLevelList.value = [];
-  step2Form.businessSecondLevel = "";
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载二级分类
-  try {
-    const res: any = await getSecondLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      secondLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取二级分类失败:", error);
-    ElMessage.error("获取经营种类失败");
-  }
-};
-
-// 二级分类变化时,加载三级分类
-const changeBusinessSecondLevel = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    thirdLevelList.value = [];
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 清空三级分类
-  thirdLevelList.value = [];
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载三级分类
-  try {
-    const res: any = await getThirdLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      thirdLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取三级分类失败:", error);
-    // 如果没有三级分类,不显示错误,因为可能该二级分类下没有三级分类
-  }
-};
-
-// 经纬度查询
-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 (param: any) => {
-  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 () => {
-  // 检查正反面是否都已上传完成
-  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;
-  }
-
-  // 如果正在识别中,不重复调用
-  if (isOcrProcessing.value) {
-    return;
-  }
-
-  // 将正反面 URL 用逗号分隔
-  const imageUrls = `${frontUrl},${backUrl}`;
-
-  let params = {
-    imageUrls: imageUrls,
-    ocrType: "ID_CARD",
-    storeId: userInfo.storeId,
-    storeUserId: userInfo.id
-  };
-
-  try {
-    isOcrProcessing.value = true;
-    const res: any = await ocrRequestUrl(params);
-    if (res && (res.code === 200 || res.code === "200")) {
-      // 保存识别结果
-      if (res.data) {
-        console.log(res.data[0]);
-        ocrResult.value = {
-          name: res.data.name || res.data.realName || "",
-          idCard: res.data.idCard || res.data.idNumber || res.data.idNo || ""
-        };
-
-        // 更新本地存储中的用户信息
-        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 {
-      console.warn("OCR 识别失败:", res?.msg);
-    }
-  } catch (error) {
-    console.error("身份证识别失败:", error);
-  } finally {
-    isOcrProcessing.value = false;
-  }
-};
-
-// 文件上传成功回调
-const handleUploadSuccess = (response: any, uploadFile: UploadUserFile) => {
-  if (response?.fileUrl) {
-    uploadFile.url = response.fileUrl;
-  }
-
-  // 延迟一下,确保文件状态已更新,然后检查是否需要自动 OCR
-  setTimeout(() => {
-    autoOcrRecognition();
-  }, 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;
-  }
-
-  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;
-};
-
-// 提取文件列表中的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;
-};
-
-// 提交
-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 whereAddress = await buildWhereAddress(step2Form.region);
-
-      let storeStatus = 1;
-      if (step2Form.businessType === "正常营业") {
-        storeStatus = 1;
-      } else if (step2Form.businessType === "暂停营业") {
-        storeStatus = 0;
-      } else if (step2Form.businessType === "筹建中") {
-        storeStatus = 2;
-      }
-
-      const storeAreaNum = typeof step2Form.storeArea === "string" ? parseInt(step2Form.storeArea) : step2Form.storeArea;
-
-      const addressObj = {
-        address: queryAddress.value || "",
-        longitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        latitude: parseFloat(step2Form.storePositionLatitude) || 0
-      };
-
-      const storePosition =
-        step2Form.storePositionLongitude && step2Form.storePositionLatitude
-          ? `${step2Form.storePositionLongitude},${step2Form.storePositionLatitude}`
-          : "";
-
-      let fullStoreAddress = "";
-      if (whereAddress.length > 0) {
-        const provinceName = whereAddress[0]?.name || "";
-        const cityName = whereAddress[1]?.name || "";
-        const districtName = whereAddress[2]?.name || "";
-        fullStoreAddress = `${provinceName}${cityName}${districtName}`;
-      }
-
-      // 获取身份证正反面URL
-      const idCardFrontUrl = getFileUrls(idCardFrontList.value)[0] || "";
-      const idCardBackUrl = getFileUrls(idCardBackList.value)[0] || "";
-
-      // 处理经营种类:优先使用三级分类,如果没有三级分类则使用二级分类
-      let finalBusinessTypes: string[] = [];
-      if (step2Form.businessTypes.length > 0) {
-        // 有三级分类选择
-        finalBusinessTypes = step2Form.businessTypes;
-      } else if (step2Form.businessSecondLevel) {
-        // 没有三级分类,使用二级分类
-        finalBusinessTypes = [step2Form.businessSecondLevel];
-      } else {
-        // 都没有,使用旧的逻辑
-        finalBusinessTypes = step2Form.businessTypesList;
-      }
-
-      const params = {
-        storeTel: userInfo.phone,
-        storeName: step2Form.storeName,
-        storeCapacity: step2Form.storeCapacity,
-        storeArea: storeAreaNum,
-        isChain: step2Form.isChain,
-        storeDetailAddress: step2Form.storeDetailAddress,
-        storeBlurb: step2Form.storeBlurb,
-        businessSection: step2Form.businessSection,
-        businessTypesList: finalBusinessTypes,
-        storeStatus: storeStatus,
-        businessStatus: step2Form.businessStatus,
-        address: addressObj,
-        businessLicenseAddress: businessLicenseUrls,
-        contractImageList: contractImageUrls,
-        foodLicenceImgList: foodLicenceUrls,
-        disportLicenceUrls: disportLicenceUrls,
-        storeAddress: fullStoreAddress,
-        whereAddress: whereAddress,
-        updatedTime: null,
-        queryAddress: queryAddress.value,
-        storePosition: storePosition,
-        storePositionLatitude: parseFloat(step2Form.storePositionLatitude) || 0,
-        storePositionLongitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        businessSectionName: step2Form.businessSectionName,
-        businessTypes: finalBusinessTypes,
-        foodLicenceUrl: foodLicenceUrls.length > 0 ? foodLicenceUrls[0] : "",
-        userAccount: userInfo.id,
-        administrativeRegionProvinceAdcode: step2Form.administrativeRegionProvinceAdcode,
-        administrativeRegionCityAdcode: step2Form.administrativeRegionCityAdcode,
-        administrativeRegionDistrictAdcode: step2Form.administrativeRegionDistrictAdcode,
-        idCardFrontUrl: idCardFrontUrl,
-        idCardBackUrl: idCardBackUrl
-      };
-
-      ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      })
-        .then(async () => {
-          try {
-            const res: any = await applyStore(params);
-            if (res && res.code == 200) {
-              storeApplicationStatus.value = 0;
-              ElMessage.success(res.msg);
-              callGetUserInfo();
-              setStep(0);
-            } else {
-              ElMessage.error(res.msg || "提交失败");
-            }
-          } catch (error) {
-            ElMessage.error("提交失败,请重试");
-          }
-        })
-        .catch(() => {
-          // 取消提交
-        });
-    } else {
-      ElMessage.error("请完善表单信息");
-    }
-  });
-};
-
-// 文件上传超出限制
-const handleExceed = () => {
-  ElMessage.warning("文件数量超出限制");
-};
-</script>
-
-<style scoped lang="scss">
-// 表单页面样式
-.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: 635px;
-        padding: 20px;
-        margin: 60px auto;
-        background-color: #f5f7fa;
-        border: 1px solid #e4e7ed;
-        border-radius: 8px;
-        .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;
-    }
-  }
-}
-</style>

+ 0 - 99
src/views/footManagement/index.vue

@@ -1,99 +0,0 @@
-<template>
-  <div id="home">
-    <!--已入驻-->
-    <go-examine v-if="isExaime" />
-    <!-- 第一步  未入驻 -->
-    <go-enter
-      :current-step="currentStep"
-      :store-application-status="storeApplicationStatus"
-      @update:current-step="handleUpdateCurrentStep"
-    />
-    <!-- 第二步 
-      @update:get-user-info="getUserInfo"-->
-    <go-flow
-      :current-step="currentStep"
-      @update:current-step="handleUpdateCurrentStep"
-      :store-application-status="storeApplicationStatus"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, ref, watch } from "vue";
-import { localGet, localSet } from "@/utils/index";
-import goEnter from "../home/components/go-enter.vue";
-import goFlow from "./go-flow.vue";
-import goExamine from "../home/components/go-examine.vue";
-import { getMerchantByPhone, getDetail } from "@/api/modules/homeEntry";
-import { is } from "@/utils/is";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const isEntry = ref<boolean>(false);
-const isExaime = ref<boolean>(false);
-
-onMounted(() => {
-  //   getUserInfo();
-});
-
-// 当前步骤:0-首页,1-第一步,2-第二步
-const currentStep = ref(0);
-const storeId = ref<Number | undefined>(undefined);
-// 处理更新currentStep事件
-const handleUpdateCurrentStep = (step: number) => {
-  currentStep.value = step;
-};
-let storeApplicationStatus = ref<number | undefined>(undefined);
-
-// const getUserInfo = async () => {
-//   try {
-//     const geekerUser = localGet("geeker-user");
-//     if (!geekerUser || !geekerUser.userInfo || !geekerUser.userInfo.phone) {
-//       console.error("用户信息不存在");
-//       return;
-//     }
-//     let param = {
-//       phone: geekerUser.userInfo.phone
-//     };
-//     const res: any = await getMerchantByPhone(param);
-//     storeId.value = res.data.storeId;
-//     if (res && res.code == 200 && res.data) {
-//       // 更新缓存中的 storeId
-//       geekerUser.userInfo.storeId = res.data.storeId;
-//       localSet("geeker-user", geekerUser);
-//       // 同时更新 createdId 缓存
-//       if (res.data.storeId) {
-//         localSet("createdId", res.data.storeId);
-//       }
-//       if (res.data.storeId == null) {
-//         isEntry.value = true;
-//       }
-//       if (res.data.storeId != null) {
-//         let param1 = {
-//           id: res.data.storeId
-//         };
-//         const resStore: any = await getDetail(param1);
-//         if (resStore && resStore.code == 200 && resStore.data) {
-//         //   storeApplicationStatus.value = resStore.data.storeApplicationStatus;
-//         //   // 如果是等待审核(0)或审核拒绝(2),且当前步骤为0,显示 go-enter 组件
-//         //   // 如果用户已经主动跳转到其他步骤,则不重置步骤
-//         //   if ((storeApplicationStatus.value == 0 || storeApplicationStatus.value == 2) && currentStep.value === 0) {
-//         //     currentStep.value = 0;
-//         //   }
-
-//           if (resStore.data.storeApplicationStatus !== 1 && res.data.storeId != null) {
-//             //storeId && storeDetail.storeApplicationStatus === 1
-//             isEntry.value = true;
-//           } else {
-//             isExaime.value = true;
-//           }
-//         }
-//       }
-//     }
-//   } catch (error) {
-//     console.error(error);
-//   }
-// };
-</script>
-
-<style scoped lang="scss"></style>

+ 0 - 1252
src/views/hairManagement/go-flow.vue

@@ -1,1252 +0,0 @@
-<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="handleUploadSuccess"
-              :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">
-                  <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="handleUploadSuccess"
-              :on-preview="handlePictureCardPreview"
-              :on-remove="handleRemove"
-              accept="image/*"
-              class="id-card-upload"
-              :class="{ 'upload-complete': isIdCardUploadComplete }"
-            >
-              <template v-if="idCardBackList.length === 0 && !isIdCardUploadComplete">
-                <div class="upload-placeholder">
-                  <span class="placeholder-text">示例图</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="businessSecondMeal">
-                <el-radio-group v-model="step2Form.businessSecondMeal">
-                  <el-radio v-for="item in secondMealList" :value="item.value" :key="item.key">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营板块" prop="businessSection">
-                <el-radio-group v-model="step2Form.businessSection" @change="changeBusinessSector">
-                  <el-radio v-for="businessSection in businessSectionList" :value="businessSection.id" :key="businessSection.id">
-                    {{ businessSection.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营种类" prop="businessSecondLevel" v-if="secondLevelList.length > 0">
-                <el-radio-group v-model="step2Form.businessSecondLevel" @change="changeBusinessSecondLevel">
-                  <el-radio v-for="item in secondLevelList" :value="item.dictId" :key="item.dictId">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <!-- 如果没有三级分类,则显示二级分类作为经营种类 -->
-              <el-form-item label="分类" prop="businessTypes" v-if="secondLevelList.length > 0 && thirdLevelList.length === 0">
-                <el-checkbox-group v-model="step2Form.businessTypes">
-                  <el-checkbox v-for="item in secondLevelList" :key="item.dictId" :label="item.dictDetail" :value="item.dictId" />
-                </el-checkbox-group>
-              </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>
-
-              <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="handleUploadSuccess"
-                  :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="contractImageList">
-                <el-upload
-                  v-model:file-list="step2Form.contractImageList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="20"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.contractImageList.length }}/20)</div>
-                  </template>
-                </el-upload>
-              </el-form-item>
-
-              <el-form-item label="食品经营许可证" prop="foodLicenceImgList">
-                <el-upload
-                  v-model:file-list="step2Form.foodLicenceImgList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="1"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.foodLicenceImgList.length }}/1)</div>
-                  </template>
-                </el-upload>
-              </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>
-
-  <!-- 图片预览 -->
-  <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 } from "vue";
-import {
-  ElMessage,
-  ElMessageBox,
-  type FormInstance,
-  type FormRules,
-  UploadProps,
-  UploadUserFile,
-  UploadRequestOptions
-} from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-
-import {
-  applyStore,
-  getMerchantByPhone,
-  getFirstLevelList,
-  getSecondLevelList,
-  getThirdLevelList
-} from "@/api/modules/homeEntry";
-import { getInputPrompt, getDistrict, uploadImg, ocrRequestUrl } from "@/api/modules/newLoginApi";
-import { localGet, localSet } from "@/utils/index";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const userInfo = localGet("geeker-user")?.userInfo || {};
-const latShow = ref(false);
-
-// 图片预览相关
-const imageViewerVisible = ref(false);
-const imageViewerUrlList = ref<string[]>([]);
-const imageViewerInitialIndex = ref(0);
-
-const entryList = ref([
-  {
-    title: "个人实名"
-  },
-  {
-    title: "填写信息"
-  },
-  {
-    title: "等待审核"
-  },
-  {
-    title: "入驻成功"
-  }
-]);
-
-// 身份证正反面上传列表
-const idCardFrontList = ref<UploadUserFile[]>([]);
-const idCardBackList = ref<UploadUserFile[]>([]);
-
-// OCR 识别结果
-const ocrResult = ref<{
-  name?: string;
-  idCard?: string;
-}>({});
-
-// 是否正在识别中
-const isOcrProcessing = ref(false);
-
-// 计算是否已上传完成(正反面都上传完成)
-const isIdCardUploadComplete = computed(() => {
-  return idCardFrontList.value.length > 0 && idCardBackList.value.length > 0;
-});
-// 下一步 - 验证身份证正反面是否已上传
-const handleNextStep = async () => {
-  // 识别成功,进入下一步
-  setStep(2);
-};
-
-const secondMealList = ref([
-  { key: 0, value: 0, dictDetail: "提供" },
-  { key: 1, value: 1, dictDetail: "不提供" }
-]);
-
-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" }],
-  storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
-  businessSecondMeal: [{ required: true, message: "请选择是否提供餐食", trigger: "change" }],
-  businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
-  businessTypes: [
-    {
-      required: true,
-      message: "请选择经营种类",
-      trigger: "change",
-      validator: (rule: any, value: any, callback: any) => {
-        if (!value || value.length === 0) {
-          callback(new Error("请选择经营种类"));
-        } else {
-          callback();
-        }
-      }
-    }
-  ],
-  address: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
-  businessLicenseAddress: [{ required: true, message: "请上传营业执照", trigger: "change" }],
-  contractImageList: [{ required: true, message: "请上传合同图片", trigger: "change" }],
-  foodLicenceImgList: [{ 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 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(() => {
-  getBusinessSectionList();
-  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({
-  businessSecondMeal: 0,
-  storeName: "",
-  storeCapacity: 1,
-  storeArea: "1",
-  isChain: 0,
-  storeDetailAddress: "",
-  region: [],
-  administrativeRegionProvinceAdcode: "",
-  administrativeRegionCityAdcode: "",
-  administrativeRegionDistrictAdcode: "",
-  storeAddress: "",
-  storeBlurb: "",
-  businessSection: "",
-  businessSectionName: "",
-  businessSecondLevel: "",
-  businessTypes: [],
-  businessTypesList: [],
-  businessStatus: 0,
-  storeStatus: 1,
-  businessType: "正常营业",
-  storePositionLongitude: "",
-  storePositionLatitude: "",
-  businessLicenseAddress: [] as UploadUserFile[],
-  contractImageList: [] as UploadUserFile[],
-  foodLicenceImgList: [] as UploadUserFile[],
-  address: ""
-});
-
-// 返回按钮
-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 businessSectionList = ref<any[]>([]);
-const getBusinessSectionList = async () => {
-  try {
-    const res: any = await getFirstLevelList({});
-    if (res && res.code === 200 && res.data) {
-      businessSectionList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取一级分类失败:", error);
-    ElMessage.error("获取经营板块失败");
-  }
-};
-
-// 二级分类列表
-const secondLevelList = ref<any[]>([]);
-// 三级分类列表
-const thirdLevelList = ref<any[]>([]);
-
-// 一级分类变化时,加载二级分类
-const changeBusinessSector = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    secondLevelList.value = [];
-    thirdLevelList.value = [];
-    step2Form.businessSecondLevel = "";
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 更新一级分类信息
-  const selectedSection = businessSectionList.value.find((item: any) => item.dictId === dictIdStr);
-  if (selectedSection) {
-    step2Form.businessSection = selectedSection.dictId;
-    step2Form.businessSectionName = selectedSection.dictDetail;
-  }
-
-  // 清空二级和三级分类
-  secondLevelList.value = [];
-  thirdLevelList.value = [];
-  step2Form.businessSecondLevel = "";
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载二级分类
-  try {
-    const res: any = await getSecondLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      secondLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取二级分类失败:", error);
-    ElMessage.error("获取经营种类失败");
-  }
-};
-
-// 二级分类变化时,加载三级分类
-const changeBusinessSecondLevel = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    thirdLevelList.value = [];
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 清空三级分类
-  thirdLevelList.value = [];
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载三级分类
-  try {
-    const res: any = await getThirdLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      thirdLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取三级分类失败:", error);
-    // 如果没有三级分类,不显示错误,因为可能该二级分类下没有三级分类
-  }
-};
-
-// 经纬度查询
-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 (param: any) => {
-  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 () => {
-  // 检查正反面是否都已上传完成
-  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;
-  }
-
-  // 如果正在识别中,不重复调用
-  if (isOcrProcessing.value) {
-    return;
-  }
-
-  // 将正反面 URL 用逗号分隔
-  const imageUrls = `${frontUrl},${backUrl}`;
-
-  let params = {
-    imageUrls: imageUrls,
-    ocrType: "ID_CARD",
-    storeId: userInfo.storeId,
-    storeUserId: userInfo.id
-  };
-
-  try {
-    isOcrProcessing.value = true;
-    const res: any = await ocrRequestUrl(params);
-    if (res && (res.code === 200 || res.code === "200")) {
-      // 保存识别结果
-      if (res.data) {
-        console.log(res.data[0]);
-        ocrResult.value = {
-          name: res.data.name || res.data.realName || "",
-          idCard: res.data.idCard || res.data.idNumber || res.data.idNo || ""
-        };
-
-        // 更新本地存储中的用户信息
-        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 {
-      console.warn("OCR 识别失败:", res?.msg);
-    }
-  } catch (error) {
-    console.error("身份证识别失败:", error);
-  } finally {
-    isOcrProcessing.value = false;
-  }
-};
-
-// 文件上传成功回调
-const handleUploadSuccess = (response: any, uploadFile: UploadUserFile) => {
-  if (response?.fileUrl) {
-    uploadFile.url = response.fileUrl;
-  }
-
-  // 延迟一下,确保文件状态已更新,然后检查是否需要自动 OCR
-  setTimeout(() => {
-    autoOcrRecognition();
-  }, 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;
-  }
-
-  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;
-};
-
-// 提取文件列表中的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;
-};
-
-// 提交
-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 whereAddress = await buildWhereAddress(step2Form.region);
-
-      let storeStatus = 1;
-      if (step2Form.businessType === "正常营业") {
-        storeStatus = 1;
-      } else if (step2Form.businessType === "暂停营业") {
-        storeStatus = 0;
-      } else if (step2Form.businessType === "筹建中") {
-        storeStatus = 2;
-      }
-
-      const storeAreaNum = typeof step2Form.storeArea === "string" ? parseInt(step2Form.storeArea) : step2Form.storeArea;
-
-      const addressObj = {
-        address: queryAddress.value || "",
-        longitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        latitude: parseFloat(step2Form.storePositionLatitude) || 0
-      };
-
-      const storePosition =
-        step2Form.storePositionLongitude && step2Form.storePositionLatitude
-          ? `${step2Form.storePositionLongitude},${step2Form.storePositionLatitude}`
-          : "";
-
-      let fullStoreAddress = "";
-      if (whereAddress.length > 0) {
-        const provinceName = whereAddress[0]?.name || "";
-        const cityName = whereAddress[1]?.name || "";
-        const districtName = whereAddress[2]?.name || "";
-        fullStoreAddress = `${provinceName}${cityName}${districtName}`;
-      }
-
-      // 获取身份证正反面URL
-      const idCardFrontUrl = getFileUrls(idCardFrontList.value)[0] || "";
-      const idCardBackUrl = getFileUrls(idCardBackList.value)[0] || "";
-
-      // 处理经营种类:优先使用三级分类,如果没有三级分类则使用二级分类
-      let finalBusinessTypes: string[] = [];
-      if (step2Form.businessTypes.length > 0) {
-        // 有三级分类选择
-        finalBusinessTypes = step2Form.businessTypes;
-      } else if (step2Form.businessSecondLevel) {
-        // 没有三级分类,使用二级分类
-        finalBusinessTypes = [step2Form.businessSecondLevel];
-      } else {
-        // 都没有,使用旧的逻辑
-        finalBusinessTypes = step2Form.businessTypesList;
-      }
-
-      const params = {
-        storeTel: userInfo.phone,
-        storeName: step2Form.storeName,
-        storeCapacity: step2Form.storeCapacity,
-        storeArea: storeAreaNum,
-        isChain: step2Form.isChain,
-        storeDetailAddress: step2Form.storeDetailAddress,
-        storeBlurb: step2Form.storeBlurb,
-        businessSection: step2Form.businessSection,
-        businessTypesList: finalBusinessTypes,
-        storeStatus: storeStatus,
-        businessStatus: step2Form.businessStatus,
-        address: addressObj,
-        businessLicenseAddress: businessLicenseUrls,
-        contractImageList: contractImageUrls,
-        foodLicenceImgList: foodLicenceUrls,
-        disportLicenceUrls: disportLicenceUrls,
-        storeAddress: fullStoreAddress,
-        whereAddress: whereAddress,
-        updatedTime: null,
-        queryAddress: queryAddress.value,
-        storePosition: storePosition,
-        storePositionLatitude: parseFloat(step2Form.storePositionLatitude) || 0,
-        storePositionLongitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        businessSectionName: step2Form.businessSectionName,
-        businessTypes: finalBusinessTypes,
-        foodLicenceUrl: foodLicenceUrls.length > 0 ? foodLicenceUrls[0] : "",
-        userAccount: userInfo.id,
-        administrativeRegionProvinceAdcode: step2Form.administrativeRegionProvinceAdcode,
-        administrativeRegionCityAdcode: step2Form.administrativeRegionCityAdcode,
-        administrativeRegionDistrictAdcode: step2Form.administrativeRegionDistrictAdcode,
-        idCardFrontUrl: idCardFrontUrl,
-        idCardBackUrl: idCardBackUrl
-      };
-
-      ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      })
-        .then(async () => {
-          try {
-            const res: any = await applyStore(params);
-            if (res && res.code == 200) {
-              storeApplicationStatus.value = 0;
-              ElMessage.success(res.msg);
-              callGetUserInfo();
-              setStep(0);
-            } else {
-              ElMessage.error(res.msg || "提交失败");
-            }
-          } catch (error) {
-            ElMessage.error("提交失败,请重试");
-          }
-        })
-        .catch(() => {
-          // 取消提交
-        });
-    } else {
-      ElMessage.error("请完善表单信息");
-    }
-  });
-};
-
-// 文件上传超出限制
-const handleExceed = () => {
-  ElMessage.warning("文件数量超出限制");
-};
-</script>
-
-<style scoped lang="scss">
-// 表单页面样式
-.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: 635px;
-        padding: 20px;
-        margin: 60px auto;
-        background-color: #f5f7fa;
-        border: 1px solid #e4e7ed;
-        border-radius: 8px;
-        .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;
-    }
-  }
-}
-</style>

+ 0 - 99
src/views/hairManagement/index.vue

@@ -1,99 +0,0 @@
-<template>
-  <div id="home">
-    <!--已入驻-->
-    <go-examine v-if="isExaime" />
-    <!-- 第一步  未入驻 -->
-    <go-enter
-      :current-step="currentStep"
-      :store-application-status="storeApplicationStatus"
-      @update:current-step="handleUpdateCurrentStep"
-    />
-    <!-- 第二步 
-      @update:get-user-info="getUserInfo"-->
-    <go-flow
-      :current-step="currentStep"
-      @update:current-step="handleUpdateCurrentStep"
-      :store-application-status="storeApplicationStatus"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, ref, watch } from "vue";
-import { localGet, localSet } from "@/utils/index";
-import goEnter from "../home/components/go-enter.vue";
-import goFlow from "./go-flow.vue";
-import goExamine from "../home/components/go-examine.vue";
-import { getMerchantByPhone, getDetail } from "@/api/modules/homeEntry";
-import { is } from "@/utils/is";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const isEntry = ref<boolean>(false);
-const isExaime = ref<boolean>(false);
-
-onMounted(() => {
-  //   getUserInfo();
-});
-
-// 当前步骤:0-首页,1-第一步,2-第二步
-const currentStep = ref(0);
-const storeId = ref<Number | undefined>(undefined);
-// 处理更新currentStep事件
-const handleUpdateCurrentStep = (step: number) => {
-  currentStep.value = step;
-};
-let storeApplicationStatus = ref<number | undefined>(undefined);
-
-// const getUserInfo = async () => {
-//   try {
-//     const geekerUser = localGet("geeker-user");
-//     if (!geekerUser || !geekerUser.userInfo || !geekerUser.userInfo.phone) {
-//       console.error("用户信息不存在");
-//       return;
-//     }
-//     let param = {
-//       phone: geekerUser.userInfo.phone
-//     };
-//     const res: any = await getMerchantByPhone(param);
-//     storeId.value = res.data.storeId;
-//     if (res && res.code == 200 && res.data) {
-//       // 更新缓存中的 storeId
-//       geekerUser.userInfo.storeId = res.data.storeId;
-//       localSet("geeker-user", geekerUser);
-//       // 同时更新 createdId 缓存
-//       if (res.data.storeId) {
-//         localSet("createdId", res.data.storeId);
-//       }
-//       if (res.data.storeId == null) {
-//         isEntry.value = true;
-//       }
-//       if (res.data.storeId != null) {
-//         let param1 = {
-//           id: res.data.storeId
-//         };
-//         const resStore: any = await getDetail(param1);
-//         if (resStore && resStore.code == 200 && resStore.data) {
-//         //   storeApplicationStatus.value = resStore.data.storeApplicationStatus;
-//         //   // 如果是等待审核(0)或审核拒绝(2),且当前步骤为0,显示 go-enter 组件
-//         //   // 如果用户已经主动跳转到其他步骤,则不重置步骤
-//         //   if ((storeApplicationStatus.value == 0 || storeApplicationStatus.value == 2) && currentStep.value === 0) {
-//         //     currentStep.value = 0;
-//         //   }
-
-//           if (resStore.data.storeApplicationStatus !== 1 && res.data.storeId != null) {
-//             //storeId && storeDetail.storeApplicationStatus === 1
-//             isEntry.value = true;
-//           } else {
-//             isExaime.value = true;
-//           }
-//         }
-//       }
-//     }
-//   } catch (error) {
-//     console.error(error);
-//   }
-// };
-</script>
-
-<style scoped lang="scss"></style>

Разница между файлами не показана из-за своего большого размера
+ 521 - 153
src/views/home/components/go-flow.vue


+ 1 - 1
src/views/licenseManagement/businessLicense.vue

@@ -40,7 +40,7 @@ const initData = async () => {
     id: id
   };
   const res: any = await getBusinessLicense(params);
-  if (res.code === 200) {
+  if (res.code == 200) {
     licenseImage.value = res.data[0].imgUrl;
   }
 };

+ 1 - 1
src/views/licenseManagement/contractManagement.vue

@@ -201,7 +201,7 @@ const initData = async () => {
     id: id
   };
   const res: any = await getContractImages(params);
-  if (res.code === 200) {
+  if (res.code == 200) {
     contractList.value = res.data;
   }
 };

+ 5 - 5
src/views/licenseManagement/entertainmentLicense.vue

@@ -1,9 +1,7 @@
 <template>
   <div class="card content-box">
     <div class="content-section">
-      <div class="tip-text">
-        如需变更请在此处上传,重新上传之后需要重新进行审核,审核通过后,新的娱乐经营许可证将会覆盖之前的娱乐经营许可证
-      </div>
+      <div class="tip-text">娱乐经营许可证到期时间:{{ entertainmentLicenseExpireTime || "--" }}</div>
       <div class="action-buttons">
         <el-button type="primary" @click="handleReplace"> 更换 </el-button>
         <el-button type="primary" @click="handleViewChangeRecord"> 查看变更记录 </el-button>
@@ -134,7 +132,7 @@ const statusMap: Record<number, { name: string; class: string }> = {
 };
 
 const id = localGet("createdId");
-
+const entertainmentLicenseExpireTime = ref<string>("");
 const licenseImage = ref<string>("");
 const replaceDialogVisible = ref(false);
 const changeRecordDialogVisible = ref(false);
@@ -180,8 +178,9 @@ const initData = async () => {
     id: id
   };
   const res: any = await getEntertainmentBusinessLicense(params);
-  if (res.code === 200) {
+  if (res.code == 200) {
     licenseImage.value = res.data[0].imgUrl;
+    entertainmentLicenseExpireTime.value = res.data[0].expireTime;
   }
 };
 
@@ -608,6 +607,7 @@ const getStatusText = (status: string) => {
   margin-bottom: 50px;
 }
 .tip-text {
+  margin-right: 450px;
   font-size: 18px;
   color: var(--el-text-color-regular);
 }

+ 1 - 1
src/views/licenseManagement/foodBusinessLicense.vue

@@ -180,7 +180,7 @@ const initData = async () => {
     id: id
   };
   const res: any = await getFoodBusinessLicense(params);
-  if (res.code === 200) {
+  if (res.code == 200) {
     licenseImage.value = res.data[0].imgUrl;
   }
 };

+ 0 - 519
src/views/licenseManagement/window.vue

@@ -1,519 +0,0 @@
-<template>
-  <!-- 更换合同弹窗 -->
-  <el-dialog
-    v-model="replaceDialogVisible"
-    title="更换合同"
-    width="860px"
-    :before-close="handleReplaceDialogClose"
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-  >
-    <el-scrollbar height="400px" class="replace-upload-scrollbar">
-      <div class="replace-upload-area" :class="{ 'upload-full': uploadedImageCount >= uploadMaxCount }">
-        <el-upload
-          v-model:file-list="fileList"
-          list-type="picture-card"
-          :accept="'.jpg,.png'"
-          :limit="uploadMaxCount"
-          :auto-upload="false"
-          :disabled="hasUnuploadedImages"
-          multiple
-          :on-change="handleUploadChange"
-          :on-exceed="handleUploadExceed"
-          :on-preview="handlePictureCardPreview"
-          :before-remove="handleBeforeRemove"
-          :on-remove="handleRemove"
-          :show-file-list="true"
-        >
-          <template #trigger>
-            <div v-if="uploadedImageCount < uploadMaxCount" class="upload-trigger-card el-upload--picture-card">
-              <el-icon>
-                <Plus />
-              </el-icon>
-              <div class="upload-tip">({{ uploadedImageCount }}/{{ uploadMaxCount }})</div>
-            </div>
-          </template>
-        </el-upload>
-      </div>
-    </el-scrollbar>
-    <template #footer>
-      <div class="dialog-footer">
-        <el-button @click="handleCancelReplace" :disabled="hasUnuploadedImages"> 取消 </el-button>
-        <el-button type="primary" @click="handleSubmitReplace" :disabled="hasUnuploadedImages"> 去审核 </el-button>
-      </div>
-    </template>
-  </el-dialog>
-
-  <!-- 图片预览 -->
-  <el-image-viewer
-    v-if="imageViewerVisible"
-    :url-list="imageViewerUrlList"
-    :initial-index="imageViewerInitialIndex"
-    @close="imageViewerVisible = false"
-  />
-</template>
-
-<script setup lang="ts" name="contractManagementwindow">
-import { ref, computed } from "vue";
-import { ElMessage, ElMessageBox } from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-import type { UploadProps, UploadFile } from "element-plus";
-import { localGet } from "@/utils";
-import { uploadContractImage, submitContractReview, getStoreContractStatus } from "@/api/modules/licenseManagement";
-
-const replaceDialogVisible = ref(false);
-const fileList = ref<UploadFile[]>([]);
-
-// ==================== 图片上传相关变量 ====================
-const uploadMaxCount = 20;
-const uploading = ref(false);
-const pendingUploadFiles = ref<UploadFile[]>([]);
-const imageUrlList = ref<string[]>([]); // 存储图片URL列表
-
-// 图片预览相关
-const imageViewerVisible = ref(false);
-const imageViewerUrlList = ref<string[]>([]);
-const imageViewerInitialIndex = ref(0);
-
-// 计算属性:获取已成功上传的图片数量
-const uploadedImageCount = computed(() => {
-  return fileList.value.filter((file: any) => file.status === "success" && file.url).length;
-});
-
-// 计算属性:检查是否有未上传完成的图片
-const hasUnuploadedImages = computed(() => {
-  // 检查是否有正在上传的文件
-  if (uploading.value || pendingUploadFiles.value.length > 0) {
-    return true;
-  }
-  // 检查文件列表中是否有状态为 "ready"(待上传)或 "uploading"(上传中)的图片
-  if (fileList.value && fileList.value.length > 0) {
-    return fileList.value.some((file: any) => {
-      return file.status === "ready" || file.status === "uploading";
-    });
-  }
-  return false;
-});
-
-const handleReplace = async () => {
-  fileList.value = [];
-  imageUrlList.value = [];
-  pendingUploadFiles.value = [];
-  uploading.value = false;
-  const params = {
-    id: localGet("createdId")
-  };
-  const res: any = await getStoreContractStatus(params);
-  if (res.data.renewContractStatus === 2) {
-    ElMessage.warning("合同审核中,请耐心等待");
-  } else {
-    replaceDialogVisible.value = true;
-  }
-};
-
-/**
- * 检查文件是否在排队中(未上传)
- * @param file 文件对象
- * @returns 是否在排队中
- */
-const isFilePending = (file: any): boolean => {
-  // 只检查 ready 状态(排队中),不包括 uploading(正在上传)
-  if (file.status === "ready") {
-    return true;
-  }
-  // 检查是否在待上传队列中
-  if (pendingUploadFiles.value.some(item => item.uid === file.uid)) {
-    return true;
-  }
-  return false;
-};
-
-/**
- * 图片上传 - 删除前确认
- * @param uploadFile 要删除的文件对象
- * @param uploadFiles 当前文件列表
- * @returns Promise<boolean>,true 允许删除,false 阻止删除
- */
-const handleBeforeRemove = async (uploadFile: any, uploadFiles: any[]): Promise<boolean> => {
-  // 如果文件在排队中(未上传),禁止删除
-  if (isFilePending(uploadFile)) {
-    ElMessage.warning("图片尚未上传,请等待上传完成后再删除");
-    return false;
-  }
-  try {
-    await ElMessageBox.confirm("确定要删除这张图片吗?", "提示", {
-      confirmButtonText: "确定",
-      cancelButtonText: "取消",
-      type: "warning"
-    });
-    // 用户确认删除,返回 true 允许删除
-    return true;
-  } catch {
-    // 用户取消删除,返回 false 阻止删除
-    return false;
-  }
-};
-
-/**
- * 图片上传 - 移除图片回调(删除成功后调用)
- * @param uploadFile 已删除的文件对象
- * @param uploadFiles 删除后的文件列表
- */
-const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
-  // 从被删除的文件对象中获取 url
-  const file = uploadFile as any;
-  const imageUrl = file.url;
-
-  if (imageUrl) {
-    // 从 imageUrl 数组中删除对应的 URL
-    const urlIndex = imageUrlList.value.indexOf(imageUrl);
-    if (urlIndex > -1) {
-      imageUrlList.value.splice(urlIndex, 1);
-    }
-  }
-
-  if (file.url && file.url.startsWith("blob:")) {
-    URL.revokeObjectURL(file.url);
-  }
-  // 同步文件列表
-  fileList.value = [...uploadFiles];
-  // 删除成功后提示
-  ElMessage.success("图片已删除");
-};
-
-/**
- * 上传文件超出限制提示
- */
-const handleUploadExceed: UploadProps["onExceed"] = () => {
-  ElMessage.warning(`最多只能上传${uploadMaxCount}张图片`);
-};
-
-/**
- * el-upload 文件变更(选中或移除)
- */
-const handleUploadChange: UploadProps["onChange"] = async (uploadFile, uploadFiles) => {
-  // 检查文件类型,只允许 jpg 和 png
-  if (uploadFile.raw) {
-    const fileType = uploadFile.raw.type.toLowerCase();
-    const fileName = uploadFile.name.toLowerCase();
-    const validTypes = ["image/jpeg", "image/jpg", "image/png"];
-    const validExtensions = [".jpg", ".jpeg", ".png"];
-
-    // 检查 MIME 类型或文件扩展名
-    const isValidType = validTypes.includes(fileType) || validExtensions.some(ext => fileName.endsWith(ext));
-
-    if (!isValidType) {
-      // 从文件列表中移除不符合类型的文件
-      const index = fileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
-      if (index > -1) {
-        fileList.value.splice(index, 1);
-      }
-      // 从 uploadFiles 中移除
-      const uploadIndex = uploadFiles.findIndex((f: any) => f.uid === uploadFile.uid);
-      if (uploadIndex > -1) {
-        uploadFiles.splice(uploadIndex, 1);
-      }
-      // 如果文件有 blob URL,释放它
-      if (uploadFile.url && uploadFile.url.startsWith("blob:")) {
-        URL.revokeObjectURL(uploadFile.url);
-      }
-      ElMessage.warning("只支持上传 JPG 和 PNG 格式的图片");
-      return;
-    }
-  }
-
-  // 同步文件列表到表单数据(只添加通过验证的文件)
-  const existingIndex = fileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
-  if (existingIndex === -1) {
-    fileList.value.push(uploadFile);
-  }
-
-  const readyFiles = fileList.value.filter(file => file.status === "ready");
-  if (readyFiles.length) {
-    readyFiles.forEach(file => {
-      if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
-        pendingUploadFiles.value.push(file);
-      }
-    });
-  }
-  processUploadQueue();
-};
-
-/**
- * 处理上传队列 - 逐个上传文件
- */
-const processUploadQueue = async () => {
-  if (uploading.value || pendingUploadFiles.value.length === 0) {
-    return;
-  }
-  // 每次只取一个文件进行上传
-  const file = pendingUploadFiles.value.shift();
-  if (file) {
-    await uploadSingleFile(file);
-    // 继续处理队列中的下一个文件
-    processUploadQueue();
-  }
-};
-
-/**
- * 单文件上传图片
- * @param file 待上传的文件
- */
-const uploadSingleFile = async (file: UploadFile) => {
-  if (!file.raw) {
-    return;
-  }
-  const rawFile = file.raw as File;
-  const formData = new FormData();
-  formData.append("file", rawFile);
-  formData.append("user", "text");
-  file.status = "uploading";
-  file.percentage = 0;
-  uploading.value = true;
-
-  try {
-    // 上传过程中先保持进度为 0,避免接口异常时进度条误显示 100%
-    const result: any = await uploadContractImage(formData);
-    if (result?.code === 200 && result.data) {
-      // 处理单个文件的上传结果
-      let imageUrl = result.data[0];
-      if (!imageUrl) {
-        throw new Error("上传成功但未获取到图片URL");
-      }
-
-      file.status = "success";
-      file.percentage = 100;
-      // 保存图片URL到文件对象
-      file.url = imageUrl;
-      file.response = { url: imageUrl };
-
-      // 保存图片URL
-      if (!Array.isArray(imageUrlList.value)) {
-        imageUrlList.value = [];
-      }
-      if (!imageUrlList.value.includes(imageUrl)) {
-        imageUrlList.value.push(imageUrl);
-      }
-    } else {
-      throw new Error(result?.msg || "图片上传失败");
-    }
-  } catch (error: any) {
-    // 上传失败时保持进度条为 0
-    file.percentage = 0;
-    file.status = "fail";
-    if (file.url && file.url.startsWith("blob:")) {
-      URL.revokeObjectURL(file.url);
-    }
-    // 从文件列表中移除失败的文件
-    const index = fileList.value.findIndex((f: any) => f.uid === file.uid);
-    if (index > -1) {
-      fileList.value.splice(index, 1);
-    }
-  } finally {
-    uploading.value = false;
-    // 触发视图更新
-    fileList.value = [...fileList.value];
-  }
-};
-
-/**
- * 图片预览 - 使用 el-image-viewer 预览功能
- * @param file 上传文件对象
- */
-const handlePictureCardPreview = (file: any) => {
-  // 如果文件在排队中(未上传),禁止预览
-  if (isFilePending(file)) {
-    ElMessage.warning("图片尚未上传,请等待上传完成后再预览");
-    return;
-  }
-  // 如果文件正在上传中,允许预览(使用本地预览)
-  if (file.status === "uploading" && file.url) {
-    imageViewerUrlList.value = [file.url];
-    imageViewerInitialIndex.value = 0;
-    imageViewerVisible.value = true;
-    return;
-  }
-  // 获取所有图片的 URL 列表(只包含已上传成功的图片)
-  const urlList = fileList.value
-    .filter((item: any) => item.status === "success" && (item.url || item.response?.data))
-    .map((item: any) => item.url || item.response?.data);
-  // 找到当前点击的图片索引
-  const currentIndex = urlList.findIndex((url: string) => url === (file.url || file.response?.data));
-  if (currentIndex < 0) {
-    ElMessage.warning("图片尚未上传完成,无法预览");
-    return;
-  }
-  imageViewerUrlList.value = urlList;
-  imageViewerInitialIndex.value = currentIndex;
-  imageViewerVisible.value = true;
-};
-
-const handleCancelReplace = async () => {
-  // 如果有图片正在上传,阻止关闭
-  if (hasUnuploadedImages.value) {
-    ElMessage.warning("请等待图片上传完成后再关闭");
-    return;
-  }
-  if (fileList.value.length > 0) {
-    try {
-      await ElMessageBox.confirm("确定要取消本次图片上传吗?已上传的图片将不保存", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      });
-      // 用户确认取消
-      fileList.value = [];
-      imageUrlList.value = [];
-      pendingUploadFiles.value = [];
-      uploading.value = false;
-      replaceDialogVisible.value = false;
-    } catch {
-      // 用户取消操作,不做任何处理
-    }
-  } else {
-    replaceDialogVisible.value = false;
-  }
-};
-
-const handleReplaceDialogClose = async (done: () => void) => {
-  // 如果有图片正在上传,阻止关闭
-  if (hasUnuploadedImages.value) {
-    ElMessage.warning("请等待图片上传完成后再关闭");
-    return; // 不调用 done(),阻止关闭弹窗
-  }
-  if (fileList.value.length > 0) {
-    try {
-      await ElMessageBox.confirm("确定要取消本次图片上传吗?已上传的图片将不保存", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      });
-      // 用户确认取消,清空数据并关闭弹窗
-      fileList.value = [];
-      imageUrlList.value = [];
-      pendingUploadFiles.value = [];
-      uploading.value = false;
-      done(); // 调用 done() 允许关闭弹窗
-    } catch {
-      // 用户取消操作,不调用 done(),阻止关闭弹窗
-    }
-  } else {
-    // 没有文件,直接关闭
-    done();
-  }
-};
-
-const handleSubmitReplace = async () => {
-  // 检查是否有未上传完成的图片
-  if (hasUnuploadedImages.value) {
-    ElMessage.warning("请等待图片上传完成后再提交");
-    return;
-  }
-  if (fileList.value.length === 0) {
-    ElMessage.warning("请至少上传一张图片");
-    return;
-  }
-  const uploadedFiles = fileList.value.filter(file => file.status === "success");
-  if (uploadedFiles.length === 0) {
-    ElMessage.warning("请先上传图片");
-    return;
-  }
-  try {
-    // 根据文件列表顺序,生成带排序的图片数据(排序从0开始)
-    const imageDataWithSort = uploadedFiles.map((file, index) => ({
-      imgUrl: file.url,
-      imgSort: index,
-      storeId: localGet("createdId")
-    }));
-    await submitContractReview(imageDataWithSort);
-    ElMessage.success("提交审核成功");
-    replaceDialogVisible.value = false;
-    fileList.value = [];
-    imageUrlList.value = [];
-    pendingUploadFiles.value = [];
-    uploading.value = false;
-  } catch (error) {
-    ElMessage.error("提交审核失败");
-  }
-};
-</script>
-
-<style lang="scss" scoped>
-.replace-upload-scrollbar {
-  :deep(.el-scrollbar__wrap) {
-    overflow-x: hidden;
-  }
-}
-.replace-upload-area {
-  min-height: 300px;
-  padding: 20px;
-  :deep(.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label) {
-    display: inline-flex !important;
-    opacity: 1 !important;
-  }
-  :deep(.el-upload-list__item.is-success:focus .el-upload-list__item-status-label) {
-    display: inline-flex !important;
-    opacity: 1 !important;
-  }
-  :deep(.el-upload-list--picture-card .el-icon--close-tip) {
-    display: none !important;
-  }
-  &.upload-full {
-    :deep(.el-upload--picture-card) {
-      display: none !important;
-    }
-  }
-}
-.dialog-footer {
-  display: flex;
-  gap: 10px;
-  justify-content: center;
-}
-
-/* el-upload 图片预览铺满容器 */
-:deep(.el-upload-list--picture-card) {
-  .el-upload-list__item {
-    overflow: hidden;
-    .el-upload-list__item-thumbnail {
-      width: 100%;
-      height: 100%;
-      object-fit: fill;
-    }
-  }
-
-  /* 排队中(未上传)的图片禁用样式 */
-  .el-upload-list__item[data-status="ready"],
-  .el-upload-list__item.is-ready {
-    position: relative;
-    pointer-events: none;
-    cursor: not-allowed;
-    opacity: 0.6;
-    &::after {
-      position: absolute;
-      inset: 0;
-      z-index: 1;
-      content: "";
-      background-color: rgb(0 0 0 / 30%);
-    }
-    .el-upload-list__item-actions {
-      pointer-events: none;
-      opacity: 0.5;
-    }
-  }
-}
-.upload-trigger-card {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  width: 100%;
-  height: 100%;
-  font-size: 28px;
-  color: #8c939d;
-  .upload-tip {
-    margin-top: 8px;
-    font-size: 14px;
-    color: #8c939d;
-  }
-}
-</style>

+ 7 - 4
src/views/login/index.vue

@@ -939,14 +939,17 @@ const handleLogin = async () => {
         // 4.等待路由完全初始化后再跳转
         // 使用 nextTick 确保路由已完全添加
         await nextTick();
-        const { contractManagement, foodBusinessLicense } = await checkMenuClickPermission();
-        // 可以使用所有三个值
-        if ((contractManagement && foodBusinessLicense) || contractManagement) {
-          // 合同管理权限
+        const { contractManagement, foodBusinessLicense, entertainmentBusinessLicense } = await checkMenuClickPermission();
+        // 登录后根据不同证照权限跳转
+        if ((contractManagement && foodBusinessLicense && entertainmentBusinessLicense) || contractManagement) {
+          // 合同管理权限优先
           router.replace("/licenseManagement/contractManagement");
         } else if (foodBusinessLicense) {
           // 食品经营许可证权限
           router.replace("/licenseManagement/foodBusinessLicense");
+        } else if (entertainmentBusinessLicense) {
+          // 娱乐经营许可证权限
+          router.replace("/licenseManagement/entertainmentLicense");
         } else {
           // 5.跳转到首页,使用 replace 避免历史记录问题
           await router.replace(HOME_URL);

+ 462 - 0
src/views/operationManagement/activityDetail.vue

@@ -0,0 +1,462 @@
+<template>
+  <!-- 运营活动管理 - 详情页面 -->
+  <div class="table-box" style="width: 100%; min-height: 100%; background-color: white">
+    <div class="header">
+      <el-button @click="goBack"> 返回 </el-button>
+      <h2 class="title">运营活动详情</h2>
+    </div>
+    <div class="content">
+      <!-- 左侧内容区域 -->
+      <div class="contentLeft">
+        <!-- 基础信息模块 -->
+        <div class="model">
+          <h3 style="font-weight: bold">基础信息:</h3>
+          <!-- 活动名称 -->
+          <div class="detail-item">
+            <div class="detail-label">活动名称</div>
+            <div class="detail-value">
+              {{ activityModel.activityName || "--" }}
+            </div>
+          </div>
+          <!-- 活动时间 -->
+          <div class="detail-item">
+            <div class="detail-label">活动时间</div>
+            <div class="detail-value">
+              <span v-if="activityModel.startTime && activityModel.endTime">
+                {{ formatDate(activityModel.startTime) }} - {{ formatDate(activityModel.endTime) }}
+              </span>
+              <span v-else>--</span>
+            </div>
+          </div>
+          <!-- 用户可参与次数 -->
+          <div class="detail-item">
+            <div class="detail-label">用户可参与次数</div>
+            <div class="detail-value">
+              {{ activityModel.participationLimit || "--" }}
+            </div>
+          </div>
+          <!-- 活动规则 -->
+          <div class="detail-item">
+            <div class="detail-label">活动规则</div>
+            <div class="detail-value">
+              {{ getRuleDisplayText(activityModel.activityRule) || "--" }}
+            </div>
+          </div>
+          <!-- 优惠券名称 -->
+          <div class="detail-item">
+            <div class="detail-label">优惠券</div>
+            <div class="detail-value">
+              {{ activityModel.couponName || "--" }}
+            </div>
+          </div>
+          <!-- 优惠券发放数量 -->
+          <div class="detail-item">
+            <div class="detail-label">优惠券发放数量</div>
+            <div class="detail-value">
+              {{ activityModel.couponQuantity || "--" }}
+            </div>
+          </div>
+          <!-- 状态 -->
+          <div class="detail-item">
+            <div class="detail-label">状态</div>
+            <div class="detail-value">
+              {{ getStatusLabel(activityModel.status) }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 右侧内容区域 -->
+      <div class="contentRight">
+        <!-- 活动宣传图模块 -->
+        <div class="model">
+          <div class="promotion-images-container">
+            <!-- 活动标题图 -->
+            <div class="promotion-image-item">
+              <h3 style="font-weight: bold">活动标题图:</h3>
+              <div class="image-container">
+                <div v-if="getImageUrl(activityModel.activityTitleImgUrl)" class="image-item">
+                  <el-image
+                    :src="getImageUrl(activityModel.activityTitleImgUrl)"
+                    fit=""
+                    class="promotion-image"
+                    :preview-src-list="getPreviewImageList()"
+                    :initial-index="0"
+                  >
+                    <template #error>
+                      <div class="image-slot">
+                        <el-icon><Picture /></el-icon>
+                      </div>
+                    </template>
+                  </el-image>
+                </div>
+                <div v-else class="empty-text">--</div>
+              </div>
+            </div>
+            <!-- 活动详情图 -->
+            <div class="promotion-image-item">
+              <h3 style="font-weight: bold">活动详情图:</h3>
+              <div class="image-container">
+                <div v-if="getImageUrl(activityModel.activityDetailImgUrl)" class="image-item">
+                  <el-image
+                    :src="getImageUrl(activityModel.activityDetailImgUrl)"
+                    fit=""
+                    class="promotion-image"
+                    :preview-src-list="getPreviewImageList()"
+                    :initial-index="getImageUrl(activityModel.activityTitleImgUrl) ? 1 : 0"
+                  >
+                    <template #error>
+                      <div class="image-slot">
+                        <el-icon><Picture /></el-icon>
+                      </div>
+                    </template>
+                  </el-image>
+                </div>
+                <div v-else class="empty-text">--</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="tsx" name="activityDetail">
+/**
+ * 运营活动管理 - 详情页面
+ * 功能:显示运营活动的详细信息
+ */
+import { ref, onMounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { ElMessage } from "element-plus";
+import { Picture } from "@element-plus/icons-vue";
+import { getActivityDetail } from "@/api/modules/operationManagement";
+
+// ==================== 响应式数据定义 ====================
+
+// 路由相关
+const router = useRouter();
+const route = useRoute();
+
+// 页面ID参数
+const id = ref<string>("");
+
+// ==================== 活动信息数据模型 ====================
+const activityModel = ref<any>({
+  // 活动名称
+  activityName: "",
+  // 活动开始时间
+  startTime: "",
+  // 活动结束时间
+  endTime: "",
+  // 用户可参与次数
+  participationLimit: 0,
+  // 活动规则
+  activityRule: "",
+  // 优惠券ID
+  couponId: "",
+  // 优惠券名称
+  couponName: "",
+  // 优惠券发放数量
+  couponQuantity: 0,
+  // 活动标题图片
+  activityTitleImgUrl: null,
+  // 活动详情图片
+  activityDetailImgUrl: null,
+  // 状态
+  status: 0
+});
+
+// ==================== 生命周期钩子 ====================
+
+/**
+ * 组件挂载时初始化
+ * 从路由参数中获取ID并加载详情数据
+ */
+onMounted(async () => {
+  id.value = (route.query.id as string) || "";
+  if (id.value) {
+    await loadDetailData();
+  } else {
+    ElMessage.warning("缺少活动ID参数");
+  }
+});
+
+// ==================== 事件处理函数 ====================
+
+/**
+ * 返回上一页
+ */
+const goBack = () => {
+  router.go(-1);
+};
+
+// ==================== 数据加载函数 ====================
+
+/**
+ * 加载详情数据
+ */
+const loadDetailData = async () => {
+  try {
+    const res: any = await getActivityDetail({ id: id.value });
+    if (res && res.code == 200) {
+      // 合并主数据
+      activityModel.value = { ...activityModel.value, ...res.data };
+    } else {
+      ElMessage.error("加载详情数据失败");
+    }
+  } catch (error) {
+    console.error("加载详情数据出错:", error);
+    ElMessage.error("加载详情数据出错");
+  }
+};
+
+// ==================== 工具函数 ====================
+
+/**
+ * 格式化日期
+ * @param date 日期字符串 (YYYY-MM-DD)
+ * @returns 格式化后的日期字符串 (YYYY/MM/DD)
+ */
+const formatDate = (date: string) => {
+  if (!date) return "--";
+  return date.replace(/-/g, "/");
+};
+
+/**
+ * 获取状态标签
+ */
+const getStatusLabel = (status: number) => {
+  const statusMap: Record<number, string> = {
+    1: "待审核",
+    2: "未开始",
+    3: "审核驳回",
+    5: "进行中",
+    6: "已下架",
+    7: "已结束"
+  };
+  return statusMap[status] || "--";
+};
+
+/**
+ * 获取活动规则显示文本
+ */
+const getRuleDisplayText = (ruleValue: any) => {
+  if (!ruleValue) return "--";
+
+  // 如果是字符串,尝试解析为数组
+  let ruleArray: any[] = [];
+  if (typeof ruleValue === "string") {
+    try {
+      ruleArray = JSON.parse(ruleValue);
+    } catch {
+      return ruleValue.replace(/,/g, " / ");
+    }
+  } else if (Array.isArray(ruleValue)) {
+    ruleArray = ruleValue;
+  } else {
+    return ruleValue.replace(/,/g, " / ");
+  }
+
+  // 将数组转换为显示文本,用 " / " 连接
+  if (ruleArray && ruleArray.length > 0) {
+    return ruleArray.filter(item => item).join(" / ");
+  }
+
+  return "--";
+};
+
+/**
+ * 获取图片URL(支持对象和字符串格式)
+ */
+const getImageUrl = (img: any): string => {
+  if (!img) return "";
+  if (typeof img === "string") return img;
+  if (img.url) return img.url;
+  return "";
+};
+
+/**
+ * 获取预览图片列表
+ */
+const getPreviewImageList = () => {
+  const list: string[] = [];
+  const titleUrl = getImageUrl(activityModel.value.activityTitleImgUrl);
+  const detailUrl = getImageUrl(activityModel.value.activityDetailImgUrl);
+  if (titleUrl) {
+    list.push(titleUrl);
+  }
+  if (detailUrl) {
+    list.push(detailUrl);
+  }
+  return list;
+};
+</script>
+
+<style scoped lang="scss">
+/* 页面容器 */
+.table-box {
+  display: flex;
+  flex-direction: column;
+  height: auto !important;
+  min-height: 100%;
+}
+
+/* 头部区域 */
+.header {
+  display: flex;
+  align-items: center;
+  padding: 20px 24px;
+  background-color: #ffffff;
+  border-bottom: 1px solid #e4e7ed;
+  box-shadow: 0 2px 4px rgb(0 0 0 / 2%);
+}
+.title {
+  flex: 1;
+  margin: 0;
+  font-size: 18px;
+  font-weight: 600;
+  color: #303133;
+  text-align: center;
+}
+
+/* 内容区域布局 */
+.content {
+  display: flex;
+  flex: 1;
+  column-gap: 24px;
+  width: 100%;
+  max-width: 800px;
+  padding: 24px;
+  margin: 0 auto;
+  background-color: #ffffff;
+  .contentLeft {
+    width: 50%;
+    padding-right: 12px;
+  }
+  .contentRight {
+    width: 50%;
+    padding-left: 12px;
+  }
+}
+
+/* 模块容器 */
+.model {
+  margin-bottom: 50px;
+  h3 {
+    width: 100%;
+    padding-bottom: 12px;
+    margin: 0 0 20px;
+    font-size: 16px;
+    color: #303133;
+    border-bottom: 2px solid #e4e7ed;
+  }
+}
+
+/* 详情项样式 */
+.detail-item {
+  display: flex;
+  align-items: flex-start;
+  min-height: 32px;
+  margin-bottom: 24px;
+}
+.detail-label {
+  flex-shrink: 0;
+  width: 140px;
+  font-size: 14px;
+  font-weight: 500;
+  line-height: 32px;
+  color: #606266;
+}
+.detail-value {
+  flex: 1;
+  font-size: 14px;
+  line-height: 32px;
+  color: #303133;
+  word-break: break-word;
+}
+
+/* 活动宣传图容器 */
+.promotion-images-container {
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+  align-items: flex-start;
+  width: 100%;
+}
+.promotion-image-item {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  align-items: flex-start;
+  width: 100%;
+  .image-label {
+    font-size: 14px;
+    font-weight: 500;
+    color: #409eff;
+  }
+}
+
+/* 图片容器样式 */
+.image-container {
+  width: 100%;
+  min-height: 100px;
+}
+.image-item {
+  width: 100%;
+}
+.promotion-image {
+  width: 100%;
+  border-radius: 6px;
+  box-shadow: 0 2px 12px rgb(0 0 0 / 10%);
+}
+.empty-text {
+  padding: 20px 0;
+  font-size: 14px;
+  color: #909399;
+}
+
+/* 活动标题图 - 21:9横向样式 */
+.promotion-image-item:first-child {
+  .image-container {
+    width: 100%;
+  }
+  .image-item {
+    width: 100%;
+    aspect-ratio: 21 / 9;
+  }
+  .promotion-image {
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
+  }
+}
+
+/* 活动详情图 - 竖版样式 */
+.promotion-image-item:last-child {
+  .image-container {
+    width: 100%;
+    max-width: 300px;
+  }
+  .image-item {
+    width: 100%;
+    aspect-ratio: 3 / 4;
+  }
+  .promotion-image {
+    width: 100%;
+    height: 100%;
+    object-fit: contain;
+  }
+}
+.image-slot {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  min-height: 200px;
+  font-size: 30px;
+  color: var(--el-text-color-placeholder);
+  background: var(--el-fill-color-light);
+}
+</style>

+ 314 - 0
src/views/operationManagement/couponDetail.vue

@@ -0,0 +1,314 @@
+<template>
+  <!-- 优惠券管理 - 详情页面 -->
+  <div class="table-box" style="width: 100%; min-height: 100%; background-color: white">
+    <div class="header">
+      <el-button @click="goBack"> 返回 </el-button>
+      <h2 class="title">优惠券模板详情</h2>
+    </div>
+    <div class="content">
+      <!-- 左侧内容区域 -->
+      <div class="contentLeft">
+        <!-- 基础信息模块 -->
+        <div class="model">
+          <h3 style="font-weight: bold">基础信息:</h3>
+          <!-- 优惠券名称 -->
+          <div class="detail-item">
+            <div class="detail-label">优惠券名称</div>
+            <div class="detail-value">
+              {{ couponModel.name || "--" }}
+            </div>
+          </div>
+          <!-- 面值 -->
+          <div class="detail-item">
+            <div class="detail-label">面值(元)</div>
+            <div class="detail-value">
+              {{ formatCurrency(couponModel.nominalValue, 2, "¥") }}
+            </div>
+          </div>
+          <!-- 开始领取时间 -->
+          <div class="detail-item">
+            <div class="detail-label">开始领取时间</div>
+            <div class="detail-value">
+              {{ couponModel.beginGetDate ? formatDate(couponModel.beginGetDate) : "--" }}
+            </div>
+          </div>
+          <!-- 结束领取时间 -->
+          <div class="detail-item">
+            <div class="detail-label">结束领取时间</div>
+            <div class="detail-value">
+              {{ couponModel.endGetDate ? formatDate(couponModel.endGetDate) : "--" }}
+            </div>
+          </div>
+          <!-- 有效期 -->
+          <div class="detail-item">
+            <div class="detail-label">有效期</div>
+            <div class="detail-value">
+              {{ couponModel.specifiedDay ? `购买后${couponModel.specifiedDay}天` : "--" }}
+            </div>
+          </div>
+          <!-- 库存 -->
+          <div class="detail-item">
+            <div class="detail-label">库存</div>
+            <div class="detail-value">
+              {{ couponModel.singleQty || "--" }}
+            </div>
+          </div>
+        </div>
+        <!-- 领取规则模块 -->
+        <div class="model">
+          <h3 style="font-weight: bold">领取规则:</h3>
+          <!-- 用户领取规则 -->
+          <div class="detail-item">
+            <div class="detail-label">用户领取规则</div>
+            <div class="detail-value">
+              {{ getClaimRuleText() }}
+            </div>
+          </div>
+          <!-- 用户是否需要收藏店铺领取 -->
+          <div class="detail-item">
+            <div class="detail-label">用户是否需要收藏店铺领取</div>
+            <div class="detail-value">
+              {{ couponModel.attentionCanReceived === 1 ? "是" : couponModel.attentionCanReceived === 0 ? "否" : "--" }}
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 右侧内容区域 -->
+      <div class="contentRight">
+        <!-- 使用规则模块 -->
+        <div class="model">
+          <h3 style="font-weight: bold">使用规则:</h3>
+          <!-- 是否有低消 -->
+          <div class="detail-item">
+            <div class="detail-label">是否有低消</div>
+            <div class="detail-value">
+              {{ couponModel.hasMinimumSpend === 1 ? "是" : couponModel.hasMinimumSpend === 0 ? "否" : "--" }}
+            </div>
+          </div>
+          <!-- 最低消费金额 -->
+          <div class="detail-item" v-if="couponModel.hasMinimumSpend === 1">
+            <div class="detail-label">最低消费金额</div>
+            <div class="detail-value">
+              {{ couponModel.minimumSpendingAmount ? `¥${couponModel.minimumSpendingAmount}` : "--" }}
+            </div>
+          </div>
+          <!-- 补充说明 -->
+          <div class="detail-item">
+            <div class="detail-label">补充说明</div>
+            <div class="detail-value" v-html="couponModel.supplementaryInstruction || '--'" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="tsx" name="couponTemplateDetail">
+/**
+ * 优惠券模板 - 详情页面
+ * 功能:显示优惠券的详细信息
+ */
+import { ref, onMounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { ElMessage } from "element-plus";
+import { getCouponDetail } from "@/api/modules/couponManagement";
+import { formatCurrency } from "@/utils/formatCurrency";
+
+// ==================== 响应式数据定义 ====================
+
+// 路由相关
+const router = useRouter();
+const route = useRoute();
+
+// 页面ID参数
+const id = ref<string>("");
+
+// ==================== 优惠券信息数据模型 ====================
+const couponModel = ref<any>({
+  // 优惠券名称
+  name: "",
+  // 面值(元)
+  nominalValue: "",
+  // 开始领取时间
+  beginGetDate: "",
+  // 结束领取时间
+  endGetDate: "",
+  // 有效期
+  specifiedDay: "",
+  // 库存
+  singleQty: "",
+  // 用户领取规则:day-每日一领,week-每周一领,month-每月一领
+  claimRule: "day",
+  // 用户是否需要收藏店铺领取:1-是,0-否
+  attentionCanReceived: 0,
+  // 是否有低消:1-是,0-否
+  hasMinimumSpend: 0,
+  // 最低消费金额
+  minimumSpendingAmount: "",
+  // 补充说明
+  supplementaryInstruction: ""
+});
+
+// ==================== 生命周期钩子 ====================
+
+/**
+ * 组件挂载时初始化
+ * 从路由参数中获取ID并加载详情数据
+ */
+onMounted(async () => {
+  id.value = (route.query.id as string) || "";
+  if (id.value) {
+    await loadDetailData();
+  } else {
+    ElMessage.warning("缺少优惠券ID参数");
+  }
+});
+
+// ==================== 事件处理函数 ====================
+
+/**
+ * 返回上一页
+ */
+const goBack = () => {
+  router.go(-1);
+};
+
+// ==================== 数据加载函数 ====================
+
+/**
+ * 加载详情数据
+ */
+const loadDetailData = async () => {
+  try {
+    const res: any = await getCouponDetail({ counponId: id.value });
+    if (res && res.code == 200) {
+      // 合并主数据
+      couponModel.value = { ...couponModel.value, ...res.data };
+      // 根据最低消费金额设置是否有低消
+      const amount = Number(couponModel.value.minimumSpendingAmount);
+      if (!isNaN(amount) && amount > 0) {
+        couponModel.value.hasMinimumSpend = 1;
+      } else {
+        couponModel.value.hasMinimumSpend = 0;
+      }
+    } else {
+      ElMessage.error("加载详情数据失败");
+    }
+  } catch (error) {
+    console.error("加载详情数据出错:", error);
+    ElMessage.error("加载详情数据出错");
+  }
+};
+
+// ==================== 工具函数 ====================
+
+/**
+ * 格式化日期
+ * @param date 日期字符串 (YYYY-MM-DD)
+ * @returns 格式化后的日期字符串 (YYYY.MM.DD)
+ */
+const formatDate = (date: string) => {
+  if (!date) return "--";
+  return date.replace(/-/g, "/");
+};
+
+/**
+ * 获取用户领取规则文本
+ */
+const getClaimRuleText = () => {
+  const ruleMap: Record<string, string> = {
+    day: "每日一领",
+    week: "每周一领",
+    month: "每月一领"
+  };
+  return ruleMap[couponModel.value.claimRule] || "--";
+};
+</script>
+
+<style scoped lang="scss">
+/* 页面容器 */
+.table-box {
+  display: flex;
+  flex-direction: column;
+  height: auto !important;
+  min-height: 100%;
+}
+
+/* 头部区域 */
+.header {
+  display: flex;
+  align-items: center;
+  padding: 20px 24px;
+  background-color: #ffffff;
+  border-bottom: 1px solid #e4e7ed;
+  box-shadow: 0 2px 4px rgb(0 0 0 / 2%);
+}
+.title {
+  flex: 1;
+  margin: 0;
+  font-size: 18px;
+  font-weight: 600;
+  color: #303133;
+  text-align: center;
+}
+
+/* 内容区域布局 */
+.content {
+  display: flex;
+  flex: 1;
+  column-gap: 24px;
+  width: 98%;
+  padding: 0 12px;
+  margin: 24px auto;
+
+  /* 左侧内容区域 */
+  .contentLeft {
+    width: 50%;
+    padding-right: 12px;
+  }
+
+  /* 右侧内容区域 */
+  .contentRight {
+    width: 50%;
+    padding-left: 12px;
+  }
+}
+
+/* 模块容器 */
+.model {
+  margin-bottom: 50px;
+  h3 {
+    padding-bottom: 12px;
+    margin: 0 0 20px;
+    font-size: 16px;
+    color: #303133;
+    border-bottom: 2px solid #e4e7ed;
+  }
+}
+
+/* 详情项样式 */
+.detail-item {
+  display: flex;
+  align-items: flex-start;
+  min-height: 32px;
+  margin-bottom: 24px;
+}
+.detail-label {
+  flex-shrink: 0;
+  min-width: 200px;
+  font-size: 14px;
+  font-weight: 500;
+  line-height: 32px;
+  color: #606266;
+}
+.detail-value {
+  flex: 1;
+  font-size: 14px;
+  line-height: 32px;
+  color: #303133;
+  word-break: break-word;
+}
+.empty-text {
+  color: #909399;
+}
+</style>

+ 120 - 0
src/views/operationManagement/couponIssuanceRecords.vue

@@ -0,0 +1,120 @@
+<template>
+  <div class="table-box button-table">
+    <ProTable
+      ref="proTable"
+      :columns="columns"
+      :data-callback="dataCallback"
+      :init-param="initParam"
+      :request-api="getTableList"
+    />
+  </div>
+</template>
+
+<script lang="tsx" name="couponIssuanceRecords" setup>
+import { onMounted, reactive, ref } from "vue";
+import ProTable from "@/components/ProTable/index.vue";
+import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
+import { getActivityList, getCouponTemplateList } from "@/api/modules/operationManagement";
+import { localGet } from "@/utils";
+
+const proTable = ref<ProTableInstance>();
+
+// 表格列配置
+const columns = reactive<ColumnProps<any>[]>([
+  {
+    prop: "couponName",
+    label: "优惠券名称"
+  },
+  {
+    prop: "couponId",
+    label: "优惠券ID"
+  },
+  {
+    prop: "issuanceTime",
+    label: "发放时间",
+    render: (scope: any) => {
+      return scope.row.issuanceTime?.replace(/-/g, "/") || "--";
+    }
+  },
+  {
+    prop: "activityName",
+    label: "活动名称",
+    search: {
+      el: "select",
+      props: { placeholder: "请选择", filterable: true }
+    },
+    enum: async () => {
+      const params = {
+        storeId: localGet("createdId"),
+        status: "5",
+        pageNum: 1,
+        pageSize: 99999
+      };
+      const res: any = await getActivityList(params);
+      if (res && res.code == 200 && res.data) {
+        const data = res.data as any;
+        if (data.records && Array.isArray(data.records)) {
+          return {
+            data: data.records.map((item: any) => ({
+              label: item.activityName,
+              value: item.activityName
+            }))
+          };
+        }
+        return { data: [] };
+      }
+      return { data: [] };
+    },
+    fieldNames: { label: "label", value: "value" }
+  },
+  {
+    prop: "activityId",
+    label: "活动ID"
+  },
+  {
+    prop: "userId",
+    label: "用户ID"
+  },
+  {
+    prop: "isUsed",
+    label: "是否使用",
+    render: (scope: any) => {
+      return scope.row.isUsed === 1 || scope.row.isUsed === true ? "是" : "否";
+    },
+    // search: {
+    //   el: "select",
+    //   props: { placeholder: "请选择" }
+    // },
+    // enum: [
+    //   { label: "是", value: 1 },
+    //   { label: "否", value: 0 }
+    // ],
+    fieldNames: { label: "label", value: "value" }
+  }
+]);
+
+// 初始化请求参数
+const initParam = reactive({
+  storeId: localGet("createdId")
+});
+
+// 数据回调处理
+const dataCallback = (data: any) => {
+  return {
+    list: data?.records || [],
+    total: data?.total || 0
+  };
+};
+
+// 获取表格列表
+const getTableList = (params: any) => {
+  return getCouponTemplateList(params);
+};
+
+// 页面加载时触发查询
+onMounted(() => {
+  proTable.value?.getTableList();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 126 - 0
src/views/operationManagement/couponTemplate.vue

@@ -0,0 +1,126 @@
+<template>
+  <div class="table-box button-table">
+    <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :init-param="initParam" :data-callback="dataCallback">
+      <!-- 表格操作 -->
+      <template #operation="scope">
+        <el-button link type="primary" @click="toDetail(scope.row)"> 查看详情 </el-button>
+      </template>
+    </ProTable>
+  </div>
+</template>
+
+<script setup lang="tsx" name="couponTemplate">
+import { reactive, ref, onMounted } from "vue";
+import { useRouter } from "vue-router";
+import ProTable from "@/components/ProTable/index.vue";
+import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
+import { getCouponList } from "@/api/modules/operationManagement";
+import { localGet, usePermission } from "@/utils";
+import { formatCurrency } from "@/utils/formatCurrency";
+
+const router = useRouter();
+const proTable = ref<ProTableInstance>();
+
+// 优惠券状态枚举
+const statusEnumY = [
+  { label: "草稿", value: "3" },
+  { label: "进行中", value: "1" },
+  { label: "已结束", value: "2" }
+];
+
+// 表格列配置
+const columns = reactive<ColumnProps<any>[]>([
+  {
+    prop: "name",
+    label: "优惠券名称",
+    search: {
+      el: "input",
+      props: { placeholder: "请输入" }
+    }
+  },
+  {
+    prop: "id",
+    label: "优惠券ID"
+  },
+  {
+    prop: "createdTime",
+    label: "创建时间",
+    render: (scope: any) => {
+      if (scope.row.createdTime) {
+        return scope.row.createdTime.replace(/-/g, "/");
+      }
+      return "--";
+    }
+  },
+  {
+    prop: "nominalValue",
+    label: "面值",
+    render: (scope: any) => {
+      return formatCurrency(scope.row.nominalValue, 2, "¥") || "--";
+    }
+  },
+  {
+    prop: "minimumSpendingAmount",
+    label: "消费金额门槛",
+    render: (scope: any) => {
+      if (scope.row.minimumSpendingAmount) {
+        return formatCurrency(scope.row.minimumSpendingAmount, 2, "¥");
+      }
+      return "--";
+    }
+  },
+  {
+    prop: "couponStatus",
+    label: "优惠券状态",
+    isShow: false,
+    search: {
+      el: "select",
+      props: { placeholder: "请选择" }
+    },
+    enum: statusEnumY,
+    fieldNames: { label: "label", value: "value" }
+  },
+  { prop: "operation", label: "操作", fixed: "right" }
+]);
+
+// 初始化请求参数
+const initParam = reactive({
+  storeId: localGet("createdId"),
+  groupType: localGet("businessSection"),
+  couponType: "2", // 优惠券类型
+  couponsFromType: 1
+});
+
+// 数据回调处理
+const dataCallback = (data: any) => {
+  // 优惠券从 discountList.records 取值
+  return {
+    list: data.discountList?.records || [],
+    total: data.discountList?.total || 0
+  };
+};
+
+// 获取表格列表
+const getTableList = (params: any) => {
+  let newParams = JSON.parse(JSON.stringify(params));
+  // 优惠券相关参数
+  delete newParams.dataType;
+  newParams.couponType = "2";
+  newParams.couponsFromType = 1;
+  return getCouponList(newParams);
+};
+
+// 跳转详情页
+const toDetail = (row: any) => {
+  router.push(`/operationManagement/couponTemplate/detail?id=${row.id}`);
+};
+
+const type = ref(false);
+// 页面加载时触发查询
+onMounted(async () => {
+  type.value = await usePermission("查看优惠券模板");
+  proTable.value?.getTableList();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 0 - 1252
src/views/spaManagement/go-flow.vue

@@ -1,1252 +0,0 @@
-<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="handleUploadSuccess"
-              :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">
-                  <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="handleUploadSuccess"
-              :on-preview="handlePictureCardPreview"
-              :on-remove="handleRemove"
-              accept="image/*"
-              class="id-card-upload"
-              :class="{ 'upload-complete': isIdCardUploadComplete }"
-            >
-              <template v-if="idCardBackList.length === 0 && !isIdCardUploadComplete">
-                <div class="upload-placeholder">
-                  <span class="placeholder-text">示例图</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="businessSecondMeal">
-                <el-radio-group v-model="step2Form.businessSecondMeal">
-                  <el-radio v-for="item in secondMealList" :value="item.value" :key="item.key">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营板块" prop="businessSection">
-                <el-radio-group v-model="step2Form.businessSection" @change="changeBusinessSector">
-                  <el-radio v-for="businessSection in businessSectionList" :value="businessSection.id" :key="businessSection.id">
-                    {{ businessSection.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <el-form-item label="经营种类" prop="businessSecondLevel" v-if="secondLevelList.length > 0">
-                <el-radio-group v-model="step2Form.businessSecondLevel" @change="changeBusinessSecondLevel">
-                  <el-radio v-for="item in secondLevelList" :value="item.dictId" :key="item.dictId">
-                    {{ item.dictDetail }}
-                  </el-radio>
-                </el-radio-group>
-              </el-form-item>
-
-              <!-- 如果没有三级分类,则显示二级分类作为经营种类 -->
-              <el-form-item label="分类" prop="businessTypes" v-if="secondLevelList.length > 0 && thirdLevelList.length === 0">
-                <el-checkbox-group v-model="step2Form.businessTypes">
-                  <el-checkbox v-for="item in secondLevelList" :key="item.dictId" :label="item.dictDetail" :value="item.dictId" />
-                </el-checkbox-group>
-              </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>
-
-              <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="handleUploadSuccess"
-                  :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="contractImageList">
-                <el-upload
-                  v-model:file-list="step2Form.contractImageList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="20"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.contractImageList.length }}/20)</div>
-                  </template>
-                </el-upload>
-              </el-form-item>
-
-              <el-form-item label="食品经营许可证" prop="foodLicenceImgList">
-                <el-upload
-                  v-model:file-list="step2Form.foodLicenceImgList"
-                  :http-request="handleHttpUpload"
-                  list-type="picture-card"
-                  :limit="1"
-                  :on-exceed="handleExceed"
-                  :on-success="handleUploadSuccess"
-                  :on-preview="handlePictureCardPreview"
-                >
-                  <el-icon><Plus /></el-icon>
-                  <template #tip>
-                    <div class="el-upload__tip">({{ step2Form.foodLicenceImgList.length }}/1)</div>
-                  </template>
-                </el-upload>
-              </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>
-
-  <!-- 图片预览 -->
-  <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 } from "vue";
-import {
-  ElMessage,
-  ElMessageBox,
-  type FormInstance,
-  type FormRules,
-  UploadProps,
-  UploadUserFile,
-  UploadRequestOptions
-} from "element-plus";
-import { Plus } from "@element-plus/icons-vue";
-
-import {
-  applyStore,
-  getMerchantByPhone,
-  getFirstLevelList,
-  getSecondLevelList,
-  getThirdLevelList
-} from "@/api/modules/homeEntry";
-import { getInputPrompt, getDistrict, uploadImg, ocrRequestUrl } from "@/api/modules/newLoginApi";
-import { localGet, localSet } from "@/utils/index";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const userInfo = localGet("geeker-user")?.userInfo || {};
-const latShow = ref(false);
-
-// 图片预览相关
-const imageViewerVisible = ref(false);
-const imageViewerUrlList = ref<string[]>([]);
-const imageViewerInitialIndex = ref(0);
-
-const entryList = ref([
-  {
-    title: "个人实名"
-  },
-  {
-    title: "填写信息"
-  },
-  {
-    title: "等待审核"
-  },
-  {
-    title: "入驻成功"
-  }
-]);
-
-// 身份证正反面上传列表
-const idCardFrontList = ref<UploadUserFile[]>([]);
-const idCardBackList = ref<UploadUserFile[]>([]);
-
-// OCR 识别结果
-const ocrResult = ref<{
-  name?: string;
-  idCard?: string;
-}>({});
-
-// 是否正在识别中
-const isOcrProcessing = ref(false);
-
-// 计算是否已上传完成(正反面都上传完成)
-const isIdCardUploadComplete = computed(() => {
-  return idCardFrontList.value.length > 0 && idCardBackList.value.length > 0;
-});
-// 下一步 - 验证身份证正反面是否已上传
-const handleNextStep = async () => {
-  // 识别成功,进入下一步
-  setStep(2);
-};
-
-const secondMealList = ref([
-  { key: 0, value: 0, dictDetail: "提供" },
-  { key: 1, value: 1, dictDetail: "不提供" }
-]);
-
-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" }],
-  storeIntro: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
-  businessSecondMeal: [{ required: true, message: "请选择是否提供餐食", trigger: "change" }],
-  businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
-  businessTypes: [
-    {
-      required: true,
-      message: "请选择经营种类",
-      trigger: "change",
-      validator: (rule: any, value: any, callback: any) => {
-        if (!value || value.length === 0) {
-          callback(new Error("请选择经营种类"));
-        } else {
-          callback();
-        }
-      }
-    }
-  ],
-  address: [{ required: true, message: "请输入经纬度", trigger: "blur" }],
-  businessLicenseAddress: [{ required: true, message: "请上传营业执照", trigger: "change" }],
-  contractImageList: [{ required: true, message: "请上传合同图片", trigger: "change" }],
-  foodLicenceImgList: [{ 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 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(() => {
-  getBusinessSectionList();
-  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({
-  businessSecondMeal: 0,
-  storeName: "",
-  storeCapacity: 1,
-  storeArea: "1",
-  isChain: 0,
-  storeDetailAddress: "",
-  region: [],
-  administrativeRegionProvinceAdcode: "",
-  administrativeRegionCityAdcode: "",
-  administrativeRegionDistrictAdcode: "",
-  storeAddress: "",
-  storeBlurb: "",
-  businessSection: "",
-  businessSectionName: "",
-  businessSecondLevel: "",
-  businessTypes: [],
-  businessTypesList: [],
-  businessStatus: 0,
-  storeStatus: 1,
-  businessType: "正常营业",
-  storePositionLongitude: "",
-  storePositionLatitude: "",
-  businessLicenseAddress: [] as UploadUserFile[],
-  contractImageList: [] as UploadUserFile[],
-  foodLicenceImgList: [] as UploadUserFile[],
-  address: ""
-});
-
-// 返回按钮
-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 businessSectionList = ref<any[]>([]);
-const getBusinessSectionList = async () => {
-  try {
-    const res: any = await getFirstLevelList({});
-    if (res && res.code === 200 && res.data) {
-      businessSectionList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取一级分类失败:", error);
-    ElMessage.error("获取经营板块失败");
-  }
-};
-
-// 二级分类列表
-const secondLevelList = ref<any[]>([]);
-// 三级分类列表
-const thirdLevelList = ref<any[]>([]);
-
-// 一级分类变化时,加载二级分类
-const changeBusinessSector = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    secondLevelList.value = [];
-    thirdLevelList.value = [];
-    step2Form.businessSecondLevel = "";
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 更新一级分类信息
-  const selectedSection = businessSectionList.value.find((item: any) => item.dictId === dictIdStr);
-  if (selectedSection) {
-    step2Form.businessSection = selectedSection.dictId;
-    step2Form.businessSectionName = selectedSection.dictDetail;
-  }
-
-  // 清空二级和三级分类
-  secondLevelList.value = [];
-  thirdLevelList.value = [];
-  step2Form.businessSecondLevel = "";
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载二级分类
-  try {
-    const res: any = await getSecondLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      secondLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取二级分类失败:", error);
-    ElMessage.error("获取经营种类失败");
-  }
-};
-
-// 二级分类变化时,加载三级分类
-const changeBusinessSecondLevel = async (dictId: string | number | boolean | undefined) => {
-  const dictIdStr = String(dictId || "");
-  if (!dictIdStr) {
-    thirdLevelList.value = [];
-    step2Form.businessTypes = [];
-    step2Form.businessTypesList = [];
-    return;
-  }
-
-  // 清空三级分类
-  thirdLevelList.value = [];
-  step2Form.businessTypes = [];
-  step2Form.businessTypesList = [];
-
-  // 加载三级分类
-  try {
-    const res: any = await getThirdLevelList({ parentDictId: dictIdStr });
-    if (res && res.code === 200 && res.data) {
-      thirdLevelList.value = res.data;
-    }
-  } catch (error) {
-    console.error("获取三级分类失败:", error);
-    // 如果没有三级分类,不显示错误,因为可能该二级分类下没有三级分类
-  }
-};
-
-// 经纬度查询
-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 (param: any) => {
-  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 () => {
-  // 检查正反面是否都已上传完成
-  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;
-  }
-
-  // 如果正在识别中,不重复调用
-  if (isOcrProcessing.value) {
-    return;
-  }
-
-  // 将正反面 URL 用逗号分隔
-  const imageUrls = `${frontUrl},${backUrl}`;
-
-  let params = {
-    imageUrls: imageUrls,
-    ocrType: "ID_CARD",
-    storeId: userInfo.storeId,
-    storeUserId: userInfo.id
-  };
-
-  try {
-    isOcrProcessing.value = true;
-    const res: any = await ocrRequestUrl(params);
-    if (res && (res.code === 200 || res.code === "200")) {
-      // 保存识别结果
-      if (res.data) {
-        console.log(res.data[0]);
-        ocrResult.value = {
-          name: res.data.name || res.data.realName || "",
-          idCard: res.data.idCard || res.data.idNumber || res.data.idNo || ""
-        };
-
-        // 更新本地存储中的用户信息
-        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 {
-      console.warn("OCR 识别失败:", res?.msg);
-    }
-  } catch (error) {
-    console.error("身份证识别失败:", error);
-  } finally {
-    isOcrProcessing.value = false;
-  }
-};
-
-// 文件上传成功回调
-const handleUploadSuccess = (response: any, uploadFile: UploadUserFile) => {
-  if (response?.fileUrl) {
-    uploadFile.url = response.fileUrl;
-  }
-
-  // 延迟一下,确保文件状态已更新,然后检查是否需要自动 OCR
-  setTimeout(() => {
-    autoOcrRecognition();
-  }, 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;
-  }
-
-  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;
-};
-
-// 提取文件列表中的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;
-};
-
-// 提交
-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 whereAddress = await buildWhereAddress(step2Form.region);
-
-      let storeStatus = 1;
-      if (step2Form.businessType === "正常营业") {
-        storeStatus = 1;
-      } else if (step2Form.businessType === "暂停营业") {
-        storeStatus = 0;
-      } else if (step2Form.businessType === "筹建中") {
-        storeStatus = 2;
-      }
-
-      const storeAreaNum = typeof step2Form.storeArea === "string" ? parseInt(step2Form.storeArea) : step2Form.storeArea;
-
-      const addressObj = {
-        address: queryAddress.value || "",
-        longitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        latitude: parseFloat(step2Form.storePositionLatitude) || 0
-      };
-
-      const storePosition =
-        step2Form.storePositionLongitude && step2Form.storePositionLatitude
-          ? `${step2Form.storePositionLongitude},${step2Form.storePositionLatitude}`
-          : "";
-
-      let fullStoreAddress = "";
-      if (whereAddress.length > 0) {
-        const provinceName = whereAddress[0]?.name || "";
-        const cityName = whereAddress[1]?.name || "";
-        const districtName = whereAddress[2]?.name || "";
-        fullStoreAddress = `${provinceName}${cityName}${districtName}`;
-      }
-
-      // 获取身份证正反面URL
-      const idCardFrontUrl = getFileUrls(idCardFrontList.value)[0] || "";
-      const idCardBackUrl = getFileUrls(idCardBackList.value)[0] || "";
-
-      // 处理经营种类:优先使用三级分类,如果没有三级分类则使用二级分类
-      let finalBusinessTypes: string[] = [];
-      if (step2Form.businessTypes.length > 0) {
-        // 有三级分类选择
-        finalBusinessTypes = step2Form.businessTypes;
-      } else if (step2Form.businessSecondLevel) {
-        // 没有三级分类,使用二级分类
-        finalBusinessTypes = [step2Form.businessSecondLevel];
-      } else {
-        // 都没有,使用旧的逻辑
-        finalBusinessTypes = step2Form.businessTypesList;
-      }
-
-      const params = {
-        storeTel: userInfo.phone,
-        storeName: step2Form.storeName,
-        storeCapacity: step2Form.storeCapacity,
-        storeArea: storeAreaNum,
-        isChain: step2Form.isChain,
-        storeDetailAddress: step2Form.storeDetailAddress,
-        storeBlurb: step2Form.storeBlurb,
-        businessSection: step2Form.businessSection,
-        businessTypesList: finalBusinessTypes,
-        storeStatus: storeStatus,
-        businessStatus: step2Form.businessStatus,
-        address: addressObj,
-        businessLicenseAddress: businessLicenseUrls,
-        contractImageList: contractImageUrls,
-        foodLicenceImgList: foodLicenceUrls,
-        disportLicenceUrls: disportLicenceUrls,
-        storeAddress: fullStoreAddress,
-        whereAddress: whereAddress,
-        updatedTime: null,
-        queryAddress: queryAddress.value,
-        storePosition: storePosition,
-        storePositionLatitude: parseFloat(step2Form.storePositionLatitude) || 0,
-        storePositionLongitude: parseFloat(step2Form.storePositionLongitude) || 0,
-        businessSectionName: step2Form.businessSectionName,
-        businessTypes: finalBusinessTypes,
-        foodLicenceUrl: foodLicenceUrls.length > 0 ? foodLicenceUrls[0] : "",
-        userAccount: userInfo.id,
-        administrativeRegionProvinceAdcode: step2Form.administrativeRegionProvinceAdcode,
-        administrativeRegionCityAdcode: step2Form.administrativeRegionCityAdcode,
-        administrativeRegionDistrictAdcode: step2Form.administrativeRegionDistrictAdcode,
-        idCardFrontUrl: idCardFrontUrl,
-        idCardBackUrl: idCardBackUrl
-      };
-
-      ElMessageBox.confirm("确认提交入驻申请吗?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      })
-        .then(async () => {
-          try {
-            const res: any = await applyStore(params);
-            if (res && res.code == 200) {
-              storeApplicationStatus.value = 0;
-              ElMessage.success(res.msg);
-              callGetUserInfo();
-              setStep(0);
-            } else {
-              ElMessage.error(res.msg || "提交失败");
-            }
-          } catch (error) {
-            ElMessage.error("提交失败,请重试");
-          }
-        })
-        .catch(() => {
-          // 取消提交
-        });
-    } else {
-      ElMessage.error("请完善表单信息");
-    }
-  });
-};
-
-// 文件上传超出限制
-const handleExceed = () => {
-  ElMessage.warning("文件数量超出限制");
-};
-</script>
-
-<style scoped lang="scss">
-// 表单页面样式
-.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: 635px;
-        padding: 20px;
-        margin: 60px auto;
-        background-color: #f5f7fa;
-        border: 1px solid #e4e7ed;
-        border-radius: 8px;
-        .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;
-    }
-  }
-}
-</style>

+ 0 - 99
src/views/spaManagement/index.vue

@@ -1,99 +0,0 @@
-<template>
-  <div id="home">
-    <!--已入驻-->
-    <go-examine v-if="isExaime" />
-    <!-- 第一步  未入驻 -->
-    <go-enter
-      :current-step="currentStep"
-      :store-application-status="storeApplicationStatus"
-      @update:current-step="handleUpdateCurrentStep"
-    />
-    <!-- 第二步 
-      @update:get-user-info="getUserInfo"-->
-    <go-flow
-      :current-step="currentStep"
-      @update:current-step="handleUpdateCurrentStep"
-      :store-application-status="storeApplicationStatus"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, ref, watch } from "vue";
-import { localGet, localSet } from "@/utils/index";
-import goEnter from "../home/components/go-enter.vue";
-import goFlow from "./go-flow.vue";
-import goExamine from "../home/components/go-examine.vue";
-import { getMerchantByPhone, getDetail } from "@/api/modules/homeEntry";
-import { is } from "@/utils/is";
-import { useAuthStore } from "@/stores/modules/auth";
-
-const authStore = useAuthStore();
-const isEntry = ref<boolean>(false);
-const isExaime = ref<boolean>(false);
-
-onMounted(() => {
-  //   getUserInfo();
-});
-
-// 当前步骤:0-首页,1-第一步,2-第二步
-const currentStep = ref(0);
-const storeId = ref<Number | undefined>(undefined);
-// 处理更新currentStep事件
-const handleUpdateCurrentStep = (step: number) => {
-  currentStep.value = step;
-};
-let storeApplicationStatus = ref<number | undefined>(undefined);
-
-// const getUserInfo = async () => {
-//   try {
-//     const geekerUser = localGet("geeker-user");
-//     if (!geekerUser || !geekerUser.userInfo || !geekerUser.userInfo.phone) {
-//       console.error("用户信息不存在");
-//       return;
-//     }
-//     let param = {
-//       phone: geekerUser.userInfo.phone
-//     };
-//     const res: any = await getMerchantByPhone(param);
-//     storeId.value = res.data.storeId;
-//     if (res && res.code == 200 && res.data) {
-//       // 更新缓存中的 storeId
-//       geekerUser.userInfo.storeId = res.data.storeId;
-//       localSet("geeker-user", geekerUser);
-//       // 同时更新 createdId 缓存
-//       if (res.data.storeId) {
-//         localSet("createdId", res.data.storeId);
-//       }
-//       if (res.data.storeId == null) {
-//         isEntry.value = true;
-//       }
-//       if (res.data.storeId != null) {
-//         let param1 = {
-//           id: res.data.storeId
-//         };
-//         const resStore: any = await getDetail(param1);
-//         if (resStore && resStore.code == 200 && resStore.data) {
-//         //   storeApplicationStatus.value = resStore.data.storeApplicationStatus;
-//         //   // 如果是等待审核(0)或审核拒绝(2),且当前步骤为0,显示 go-enter 组件
-//         //   // 如果用户已经主动跳转到其他步骤,则不重置步骤
-//         //   if ((storeApplicationStatus.value == 0 || storeApplicationStatus.value == 2) && currentStep.value === 0) {
-//         //     currentStep.value = 0;
-//         //   }
-
-//           if (resStore.data.storeApplicationStatus !== 1 && res.data.storeId != null) {
-//             //storeId && storeDetail.storeApplicationStatus === 1
-//             isEntry.value = true;
-//           } else {
-//             isExaime.value = true;
-//           }
-//         }
-//       }
-//     }
-//   } catch (error) {
-//     console.error(error);
-//   }
-// };
-</script>
-
-<style scoped lang="scss"></style>

+ 152 - 6
src/views/storeDecoration/basicStoreInformation/index.vue

@@ -171,9 +171,24 @@
           </el-form-item>
 
           <!-- 经营种类 -->
-          <el-form-item label="经营种类" prop="">
-            <el-checkbox-group v-model="formData.businessTypesList" disabled style="display: flex; flex-wrap: wrap; width: 100%">
+          <el-form-item label="经营种类" prop="" v-if="businessTypeList.length > 0">
+            <el-radio-group v-model="formData.businessTypes" disabled style="display: flex; flex-wrap: wrap; width: 100%">
               <div class="businessSection-item" v-for="type in businessTypeList" :key="type.id || type.value">
+                <el-radio :value="String(type.dictId || type.value)" :label="type.dictDetail">
+                  {{ type.dictDetail }}
+                </el-radio>
+              </div>
+            </el-radio-group>
+          </el-form-item>
+
+          <!-- 分类 -->
+          <el-form-item label="分类" prop="" v-if="categoryTypeList.length > 0">
+            <el-checkbox-group
+              v-model="formData.businessClassifyList"
+              disabled
+              style="display: flex; flex-wrap: wrap; width: 100%"
+            >
+              <div class="businessSection-item" v-for="type in categoryTypeList" :key="type.id || type.value">
                 <el-checkbox :value="type.dictId || type.value" :label="type.dictDetail" />
               </div>
             </el-checkbox-group>
@@ -218,6 +233,7 @@ import { Search, Lock } from "@element-plus/icons-vue";
 import {
   getBusinessSection,
   getBusinessSectionTypes,
+  getThirdLevelList,
   getDistrict,
   getStoreDetail,
   saveStoreInfo,
@@ -252,7 +268,9 @@ const formData = reactive({
   storeBlurb: "",
   queryAddress: "",
   businessSection: "",
+  businessTypes: "",
   businessTypesList: [] as string[],
+  businessClassifyList: [] as string[],
   expirationTime: "",
   foodLicenceExpirationTime: "",
   storePosition: "",
@@ -334,6 +352,7 @@ const rules = reactive<FormRules>({
   storeBlurb: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
   queryAddress: [{ required: true, message: "请输入地址进行经纬度查询", trigger: "blur" }],
   businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
+  businessTypes: [{ required: true, message: "请选择经营种类(单选)", trigger: "change" }],
   businessTypesList: [{ required: true, message: "请选择经营种类", trigger: "change", type: "array" }]
 });
 
@@ -357,6 +376,9 @@ const businessSectionList = ref<any[]>([
 // 经营种类列表(根据UI图静态数据)
 const businessTypeList = ref<any[]>([]);
 
+// 分类列表(独立的数据源)
+const categoryTypeList = ref<any[]>([]);
+
 // 经营板块对应的经营种类数据(根据UI图)
 const businessTypeMap: Record<string, any[]> = {
   美食: [
@@ -520,11 +542,12 @@ const getBusinessSectionData = async () => {
 const handleBusinessSectionChange = async (sectionId: string, init?: boolean) => {
   if (!sectionId) {
     businessTypeList.value = [];
+    formData.businessTypes = "";
     formData.businessTypesList = [];
     return;
   }
   try {
-    const res = await getBusinessSectionTypes({ parentId: sectionId });
+    const res = await getBusinessSectionTypes({ parentDictId: sectionId });
     console.log(res, "--data--datax");
 
     if (res && res.data) {
@@ -558,6 +581,90 @@ const handleBusinessSectionChange = async (sectionId: string, init?: boolean) =>
   }
 };
 
+// 监听经营板块变化,获取对应的分类
+const handleCategoryChange = async (sectionId: string, init?: boolean) => {
+  if (!sectionId) {
+    categoryTypeList.value = [];
+    formData.businessClassifyList = [];
+    return;
+  }
+  try {
+    const res = await getThirdLevelList({ parentDictId: sectionId });
+    console.log(res, "--category--data");
+
+    if (res && res.data) {
+      const dataAny = res.data as any;
+      // 处理不同的返回格式
+      if (Array.isArray(dataAny)) {
+        categoryTypeList.value = dataAny;
+      } else if (dataAny.data && Array.isArray(dataAny.data)) {
+        categoryTypeList.value = dataAny.data;
+      } else if (dataAny.list && Array.isArray(dataAny.list)) {
+        categoryTypeList.value = dataAny.list;
+      } else {
+        categoryTypeList.value = [];
+      }
+    } else {
+      categoryTypeList.value = [];
+    }
+    // 清空已选择的分类
+    // if (!init) {
+    //   formData.businessClassifyList = [];
+    // }
+  } catch (error: any) {
+    // 忽略请求取消错误(这是正常的,当有重复请求时会被取消)
+    if (error?.code === "ERR_CANCELED" || error?.name === "CanceledError") {
+      console.log("请求被取消(可能是重复请求)");
+      return;
+    }
+    console.error("获取分类失败:", error);
+    categoryTypeList.value = [];
+    formData.businessClassifyList = [];
+  }
+};
+
+// 根据经营种类ID获取对应的分类
+const handleCategoryChangeByType = async (typeId: string, init?: boolean) => {
+  if (!typeId) {
+    categoryTypeList.value = [];
+    formData.businessClassifyList = [];
+    return;
+  }
+  try {
+    const res = await getThirdLevelList({ parentDictId: typeId });
+    console.log(res, "--categoryByType--data");
+
+    if (res && res.data) {
+      const dataAny = res.data as any;
+      // 处理不同的返回格式
+      if (Array.isArray(dataAny)) {
+        categoryTypeList.value = dataAny;
+      } else if (dataAny.data && Array.isArray(dataAny.data)) {
+        categoryTypeList.value = dataAny.data;
+      } else if (dataAny.list && Array.isArray(dataAny.list)) {
+        categoryTypeList.value = dataAny.list;
+      } else {
+        categoryTypeList.value = [];
+      }
+    } else {
+      categoryTypeList.value = [];
+    }
+    // 清空已选择的分类(如果不是初始化)
+    if (!init) {
+      formData.businessClassifyList = [];
+    }
+  } catch (error: any) {
+    // 忽略请求取消错误(这是正常的,当有重复请求时会被取消)
+    if (error?.code === "ERR_CANCELED" || error?.name === "CanceledError") {
+      console.log("请求被取消(可能是重复请求)");
+      return;
+    }
+    console.error("根据经营种类获取分类失败:", error);
+    categoryTypeList.value = [];
+    formData.businessClassifyList = [];
+  }
+};
+
 // 经纬度查询(用户手动触发)
 // const handleLocationQuery = async () => {
 //   if (!formData.queryAddress) {
@@ -613,7 +720,9 @@ const handleSubmit = async () => {
         storePosition: formData.storePosition,
         storePositionLongitude: formData.storePositionLongitude,
         storePositionLatitude: formData.storePositionLatitude,
-        businessStatus: formData.businessStatus
+        businessStatus: formData.businessStatus,
+        businessTypes: formData.businessTypes ?? "",
+        businessClassifyList: formData.businessClassifyList ?? []
       };
 
       let result;
@@ -696,14 +805,29 @@ const getStoreDetailData = async () => {
         const sectionId = String(storeData.businessSection);
         // 直接调用 handleBusinessSectionChange,因为 isLoadingDetail 会阻止 watch 触发
         await handleBusinessSectionChange(sectionId);
+        // 调用 handleCategoryChange 获取分类数据
+        await handleCategoryChange(sectionId);
         // 设置 businessSection(此时 watch 不会触发,因为 isLoadingDetail 为 true)
         formData.businessSection = sectionId;
-        // 设置已选择的经营种类
+        // 设置已选择的经营种类(单选)
+        if (storeData.businessTypes) {
+          const typeId = String(storeData.businessTypes);
+          formData.businessTypes = typeId;
+          // 根据经营种类获取对应的分类
+          await handleCategoryChangeByType(typeId, true);
+        }
+        // 设置已选择的经营种类(多选)
         if (storeData.businessTypesList) {
           formData.businessTypesList = Array.isArray(storeData.businessTypesList)
             ? storeData.businessTypesList
             : [storeData.businessTypesList];
         }
+        // 设置已选择的分类
+        if (storeData.businessClassifyList) {
+          formData.businessClassifyList = Array.isArray(storeData.businessClassifyList)
+            ? storeData.businessClassifyList
+            : [storeData.businessClassifyList];
+        }
       }
     }
   } catch (error) {
@@ -724,6 +848,27 @@ watch(
     if (newValue) {
       console.log(newValue, "--newValue");
       handleBusinessSectionChange(newValue);
+      handleCategoryChange(newValue);
+    }
+  }
+);
+
+// 监听经营种类变化,获取对应的分类
+watch(
+  () => formData.businessTypes,
+  newValue => {
+    // 如果正在加载详情数据,不触发 watch(避免重复请求)
+    if (isLoadingDetail.value) {
+      return;
+    }
+    if (newValue) {
+      console.log(newValue, "--businessTypes--newValue");
+      // 根据经营种类的ID获取对应的分类
+      handleCategoryChangeByType(newValue);
+    } else {
+      // 如果清空了经营种类,清空分类
+      categoryTypeList.value = [];
+      formData.businessClassifyList = [];
     }
   }
 );
@@ -731,9 +876,10 @@ watch(
 onMounted(async () => {
   await getProvinceData();
   await getBusinessSectionData();
-  // 如果默认选中了经营板块,自动加载对应的经营种类
+  // 如果默认选中了经营板块,自动加载对应的经营种类和分类
   if (formData.businessSection) {
     await handleBusinessSectionChange(formData.businessSection, true);
+    await handleCategoryChange(formData.businessSection, true);
   }
   await getStoreDetailData();
 });

Некоторые файлы не были показаны из-за большого количества измененных файлов