Переглянути джерело

refactor(storeDecoration): 重构商铺装修模块的API和服务

- 替换旧版商铺用户管理API为新版API接口
- 更新商铺信息管理相关接口地址和参数结构
- 优化商铺详情获取逻辑并增加字段映射处理
- 完善地区选择器的行政区划代码处理
- 重构营业时间管理功能,支持批量新增和编辑
- 改进经纬度查询功能,增强地址解析准确性
- 更新表单字段绑定和验证规则以适配新数据结构
- 修复地区选择联动逻辑中的数据绑定问题
- 优化经营板块和经营种类的数据加载机制
- 调整门店基础信息表单的字段命名和数据类型
- 增强业务状态和门店面积的枚举值映射处理
- 改进组件卸载时的资源清理和状态重置逻辑
spy 3 тижнів тому
батько
коміт
0ddaee3fd8

+ 3 - 2
src/api/indexApi.ts

@@ -62,7 +62,6 @@ class RequestHttp {
     this.service.interceptors.response.use(
       (response: AxiosResponse & { config: CustomAxiosRequestConfig }) => {
         const { data, config } = response;
-
         const userStore = useUserStore();
         axiosCanceler.removePending(config);
         config.loading && tryHideFullScreenLoading();
@@ -88,9 +87,11 @@ class RequestHttp {
         if (error.message.indexOf("timeout") !== -1) ElMessage.error("请求超时!请您稍后重试");
         if (error.message.indexOf("Network Error") !== -1) ElMessage.error("网络错误!请您稍后重试");
         // 根据服务器响应的错误状态码,做不同的处理
-        if (response.data.message) {
+        if (response && response.data && response.data.message) {
+          console.log("这里1");
           ElMessage.error(response.data.message);
         } else {
+          console.log("这里");
           if (response) checkStatus(response.status);
         }
         // 服务器结果都没有返回(可能服务器错误可能客户端断网),断网处理:可以跳转到断网页面

+ 34 - 145
src/api/modules/storeDecoration.ts

@@ -1,174 +1,63 @@
 import { ResPage, StoreUser } from "@/api/interface/index";
 import { PORT_NONE } from "@/api/config/servicePort";
 import http from "@/api";
+import httpApi from "@/api/indexApi";
+
 /**
  * @name 商铺用户模块
  */
-// 获取商铺用户列表
-export const getStoreUserList = (params: StoreUser.ReqUserParams) => {
-  return http.get<ResPage<StoreUser.ResStoreUserList>>(PORT_NONE + `/store/user/getStoreUserList`, params);
-};
-
-// 新增商家端用户
-export const addStoreUser = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/user/addStoreUser`, params);
-};
-
-// 修改商家端用户
-export const editStoreUser = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/user/editStoreUser`, params);
-};
-
-// 重置商家端用户密码及支付密码
-export const resetStoreUserPassword = (params: { id: string }) => {
-  return http.put(PORT_NONE + `/store/user/resetStoreUserPassword`, params);
-};
-
-// 删除商家端用户
-export const deleteStoreUser = (params: { id: string }) => {
-  return http.delete(PORT_NONE + `/store/user/deleteStoreUser`, params);
-};
-
-// 切换商家端用户状态
-export const switchingStates = (params: { id: string }) => {
-  return http.put(PORT_NONE + `/store/user/switchingStates`, params);
-};
-
-// 获取商铺列表
-export const getStoreInfoList = (params: StoreUser.ReqUserParams) => {
-  return http.get<ResPage<StoreUser.ResStoreUserList>>(PORT_NONE + `/store/info/getStorePage`, params);
-};
 
 //获取商铺经营板块列表
 export const getBusinessSection = () => {
-  return http.get(`/storePlatformRenovation/getBusinessSection`);
+  return httpApi.get(`/alienStorePlatform/storePlatformRenovation/getBusinessSection`);
 };
 
 //获取商铺经营种类列表
-export const getBusinessSectionTypes = (params: { parentId: string }) => {
-  return http.get<ResPage<StoreUser.ResStoreUserList>>(PORT_NONE + `/store/info/getBusinessSectionTypes`, params);
-};
-
-//获取未绑定的商家端账号
-export const getUnboundAccountList = (params: { id: string }) => {
-  return http.get(PORT_NONE + `/store/info/getUnboundAccountList`, params);
-};
-
-//新增经营板块
-export const addBusinessSectionAndTypes = (params: {
-  businessSectionName: string;
-  businessTypeValue: string;
-  businessTypesList: [];
-}) => {
-  return http.post(PORT_NONE + `/store/info/addBusinessSectionAndTypes`, params);
-};
-
-//新增商铺信息
-export const saveStoreInfo = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/info/saveStoreInfo`, params);
-};
-
-//获取商铺明细信息
-export const getStoreDetail = (params: StoreUser.ReqUserParams) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/store/info/getStoreDetail`, params);
-};
-
-//新增商铺信息
-export const editStoreInfo = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/info/editStoreInfo`, params);
+export const getBusinessSectionTypes = params => {
+  return httpApi.get(`/alienStorePlatform/storePlatformRenovation/getBusinessSectionTypes`, params);
 };
 
-// 修改商铺用户
-// export const editStoreUser1 = (params: { id: string }) => {
-//   return http.post(PORT_NONE + `/store/info/editStoreInfo`, params);
-// };
-
-// 删除商铺信息
-export const deleteStoreInfo = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/info/deleteStoreInfo`, params);
+//所在地区
+export const getDistrict = (params?: any) => {
+  return httpApi.get(`/alienStore/gaode/getDistrict`, params);
 };
 
-//审批商户
-export const approveStoreInfo = (params: { id: string; approvalStatus: number; reason: string }) => {
-  return http.get(PORT_NONE + `/store/info/approveStoreInfo`, params);
+export const getStoreDetail = params => {
+  return httpApi.get(`/alienStorePlatform/storePlatformRenovation/getDecorationDetail`, params);
 };
 
-//审批商户续约
-export const updateContractImageStatus = (params: { id: string; approvalStatus: number }) => {
-  return http.post(PORT_NONE + `/store/info/updateContractImageStatus`, params);
-};
-//审批经营许可证变更
-export const updatefoodLicenceImageStatus = (params: { id: string; approvalStatus: number }) => {
-  return http.post(PORT_NONE + `/store/info/updatefoodLicenceImageStatus`, params);
+//保存店铺信息
+export const saveStoreInfo = (params: any) => {
+  return httpApi.post(`/alienStorePlatform/storePlatformInfo/saveOrUpdate`, params);
 };
 
-// 重置商户或者用户密码
-export const resetStoreUserPassWord = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/info/restPassword`, params);
+//编辑店铺信息
+export const editStoreInfo = (params: any) => {
+  return httpApi.post(`/alienStorePlatform/storePlatformInfo/saveOrUpdate`, params);
 };
-
-// 获取店铺状态
-export const getStoreAuditStatus = (params: { id: string }) => {
-  return http.post(PORT_NONE + `/store/info/getStoreAuditStatus`, params);
-};
-
-//商铺页面导出excel
-export const exportExcel = (params: {}) => {
-  return http.get(PORT_NONE + `/store/info/exportExcel`, params);
+// 入口图查询
+export const getEntranceImg = (data: any) => {
+  return httpApi.get(`/alienStore/img/getByStoreId?storeId=${data}&imgType=1`);
 };
-//商铺过期查询页面导出excel
-export const exportExcelExpirationTime = (params: {}) => {
-  return http.get(
-    PORT_NONE +
-      `/store/info/exportExcelExpirationTime
-`,
-    params
-  );
+//入口图保存
+export const saveEntranceImg = (params: any) => {
+  return httpApi.post(`/alienStore/img/saveOrUpdateImg`, params);
 };
-//商铺用户页面导出excel
-export const exportUserExcel = (params: {}) => {
-  return http.get(
-    PORT_NONE +
-      `/store/user/exportExcel
-`,
-    params
-  );
+// 门店头图查询
+export const getStoreHeadImg = (data: any, imgType: any) => {
+  return httpApi.get(`alienStore/img/getByStoreId?storeId=${data}&imgType=${imgType}`);
 };
-//根据详细信息获取经纬度名称
-export const getInputPrompt = (params: StoreUser.ReqUserParams) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/gaode/getInputPrompt`, params);
-};
-
-//获取行政区域信息
-export const getDistrict = (params: StoreUser.ReqUserParams) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/gaode/getDistrict`, params);
-};
-// 更改店铺抽成百分比
-export const updateStoreCommissionRate = (params: { id: string; commissionRate: any }) => {
-  return http.post(PORT_NONE + `/store/info/updateStoreCommissionRate`, params);
-};
-
-// 节假日列表
-export const getHolidayList = (params: any) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/coupon/getHolidayList`, params);
-};
-
-// 节假日列表
-export const saveHoliday = (params: any) => {
-  return http.post<StoreUser.ResStoreUserList>(PORT_NONE + `/coupon/saveHoliday`, params);
-};
-
-//删除节假日
-export const delHoliday = (params: any) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/coupon/delHoliday`, params);
+//门店头图保存
+export const saveStoreHeadImg = (params: any) => {
+  return httpApi.post(`/alienStore/img/saveOrUpdateImg`, params);
 };
 
-// 按年份删除节假日
-export const delHolidayByYear = (params: any) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/coupon/delHolidayByYear`, params);
+//批量新增或编辑营业时间
+export const addOrEditBusinessTime = (params: any) => {
+  return httpApi.post(`/alienStorePlatform//storePlatformBusinessInfo/saveOrUpdateList`, params);
 };
 
-//启用禁用节假日
-export const openCloseHoliday = (params: any) => {
-  return http.get<StoreUser.ResStoreUserList>(PORT_NONE + `/coupon/openCloseHoliday`, params);
+//获取营业时间列表
+export const getBusinessTimeList = (params: any) => {
+  return httpApi.get(`/alienStorePlatform/storePlatformBusinessInfo/getByStoreId`, params);
 };

+ 2 - 1
src/layouts/components/Header/components/Avatar.vue

@@ -32,6 +32,7 @@ import { useUserStore } from "@/stores/modules/user";
 import { ElMessageBox, ElMessage } from "element-plus";
 import InfoDialog from "./InfoDialog.vue";
 import PasswordDialog from "./PasswordDialog.vue";
+import { localClear } from "@/utils";
 
 const router = useRouter();
 const userStore = useUserStore();
@@ -48,7 +49,7 @@ const logout = () => {
 
     // 2.清除 Token
     userStore.setToken("");
-
+    localClear();
     // 3.重定向到登陆页
     router.replace(LOGIN_URL);
     ElMessage.success("退出登录成功!");

+ 2 - 0
src/utils/permission.ts

@@ -8,6 +8,8 @@ import { getUserByPhone, getDetail } from "@/api/modules/homeEntry";
  */
 export async function usePermission(tip?: string) {
   let type = true;
+  // todo
+  return type;
   if (!localGet("createdId") && !localGet("geeker-user").userInfo.storeId) {
     let params = {
       phone: localGet("iphone") || localGet("geeker-user").userInfo.phone

+ 211 - 127
src/views/storeDecoration/basicStoreInformation/index.vue

@@ -15,20 +15,20 @@
           </el-form-item>
 
           <!-- 门店电话 -->
-          <el-form-item label="门店电话" prop="storePhone">
-            <el-input v-model="formData.storePhone" placeholder="请输入门店电话" clearable maxlength="20" />
+          <el-form-item label="门店电话" prop="storeTel">
+            <el-input v-model="formData.storeTel" placeholder="请输入门店电话" clearable maxlength="20" />
           </el-form-item>
 
           <!-- 门店面积 -->
           <el-form-item label="门店面积" prop="storeArea">
             <el-radio-group v-model="formData.storeArea">
-              <el-radio value="小于20平米"> 小于20平米 </el-radio>
-              <el-radio value="20-50平米"> 20-50平米 </el-radio>
-              <el-radio value="50-100平米"> 50-100平米 </el-radio>
-              <el-radio value="100-300平米"> 100-300平米 </el-radio>
-              <el-radio value="300-500平米"> 300-500平米 </el-radio>
-              <el-radio value="500-1000平米"> 500-1000平米 </el-radio>
-              <el-radio value="大于1000平米"> 大于1000平米 </el-radio>
+              <el-radio :value="1"> 小于20平米 </el-radio>
+              <el-radio :value="2"> 20-50平米 </el-radio>
+              <el-radio :value="3"> 50-100平米 </el-radio>
+              <el-radio :value="4"> 100-300平米 </el-radio>
+              <el-radio :value="5"> 300-500平米 </el-radio>
+              <el-radio :value="6"> 500-1000平米 </el-radio>
+              <el-radio :value="7"> 大于1000平米 </el-radio>
             </el-radio-group>
           </el-form-item>
 
@@ -36,25 +36,25 @@
           <el-form-item label="营业状态" prop="businessStatus">
             <el-radio-group v-model="formData.businessStatus">
               <div class="radio-item">
-                <el-radio value="正常营业">
+                <el-radio :value="0">
                   <span class="radio-label">正常营业</span>
                 </el-radio>
                 <div class="radio-desc">门店正常开放,能够为顾客提供服务</div>
               </div>
               <div class="radio-item">
-                <el-radio value="暂停营业">
+                <el-radio :value="1">
                   <span class="radio-label">暂停营业</span>
                 </el-radio>
                 <div class="radio-desc">门店因节假日、装修等原因,短期内止营业,预计一段时问后可恢复营业</div>
               </div>
               <div class="radio-item">
-                <el-radio value="筹建中">
+                <el-radio :value="2">
                   <span class="radio-label">筹建中</span>
                 </el-radio>
                 <div class="radio-desc">门店正在筹备阶段,暂时不能提供服务,完成准备后可以证实为顾客提供服务</div>
               </div>
               <div class="radio-item">
-                <el-radio value="永久关门">
+                <el-radio :value="99">
                   <span class="radio-label">永久关门</span>
                 </el-radio>
                 <div class="radio-desc">门店已经关门、转让或搬迁,长时间没有回复营业的计划,无法提供服务</div>
@@ -66,7 +66,7 @@
           <el-form-item label="所在地区" required>
             <div class="region-selector">
               <el-select
-                v-model="formData.province"
+                v-model="formData.administrativeRegionProvinceAdcode"
                 placeholder="请选择省"
                 clearable
                 style="width: 33.33%"
@@ -80,21 +80,21 @@
                 />
               </el-select>
               <el-select
-                v-model="formData.city"
+                v-model="formData.administrativeRegionCityAdcode"
                 placeholder="请选择市"
                 clearable
                 style="width: 33.33%"
-                :disabled="!formData.province"
+                :disabled="!formData.administrativeRegionProvinceAdcode"
                 @change="handleCityChange"
               >
                 <el-option v-for="city in cityOptions" :key="city.adcode" :label="city.name" :value="city.adcode" />
               </el-select>
               <el-select
-                v-model="formData.district"
+                v-model="formData.administrativeRegionDistrictAdcode"
                 placeholder="请选择区"
                 clearable
                 style="width: 33.33%"
-                :disabled="!formData.city"
+                :disabled="!formData.administrativeRegionCityAdcode"
               >
                 <el-option
                   v-for="district in districtOptions"
@@ -134,8 +134,8 @@
           </el-form-item>
 
           <!-- 经纬度查询 -->
-          <el-form-item label="经纬度查询" prop="locationQuery">
-            <el-input v-model="formData.locationQuery" placeholder="请输入地址进行查询" clearable @blur="handleLocationQuery">
+          <el-form-item label="经纬度查询" prop="queryAddress">
+            <el-input v-model="formData.queryAddress" placeholder="请输入地址进行查询" clearable @blur="handleLocationQuery">
               <template #append>
                 <el-button :icon="Search" @click="handleLocationQuery"> 查询 </el-button>
               </template>
@@ -143,22 +143,22 @@
           </el-form-item>
 
           <!-- 经营板块 -->
-          <el-form-item label="经营板块" prop="businessSection">
-            <el-radio-group v-model="formData.businessSection">
-              <div v-for="section in businessSectionList" :key="section.id || section.value" class="businessSection-item">
-                <el-radio :value="section.id || section.value" :label="section.name || section.label">
-                  {{ section.name || section.label }}
+          <el-form-item label="经营板块" prop="">
+            <el-radio-group v-model="formData.businessSection" disabled>
+              <div v-for="section in businessSectionList" :key="section.dictId || section.value" class="businessSection-item">
+                <el-radio :value="String(section.dictId)" :label="section.dictDetail">
+                  {{ section.dictDetail }}
                 </el-radio>
               </div>
             </el-radio-group>
           </el-form-item>
 
           <!-- 经营种类 -->
-          <el-form-item label="经营种类" prop="businessTypes">
-            <el-checkbox-group v-model="formData.businessTypes" style="display: flex; flex-wrap: wrap; width: 100%">
+          <el-form-item label="经营种类" prop="">
+            <el-checkbox-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-checkbox :value="type.id || type.value" :label="type.name || type.label">
-                  {{ type.name || type.label }}
+                <el-checkbox :value="type.id || type.value" :label="type.dictDetail">
+                  {{ type.dictDetail }}
                 </el-checkbox>
               </div>
             </el-checkbox-group>
@@ -195,65 +195,68 @@
     </el-form>
   </div>
 </template>
-
 <script setup lang="ts">
-import { ref, reactive, onMounted, watch } from "vue";
+import { ref, reactive, onMounted, watch, nextTick } from "vue";
 import { ElMessage, ElNotification } from "element-plus";
 import type { FormInstance, FormRules } from "element-plus";
 import { Search, Lock } from "@element-plus/icons-vue";
 import {
   getBusinessSection,
   getBusinessSectionTypes,
-  getInputPrompt,
   getDistrict,
+  getStoreDetail,
   saveStoreInfo,
-  editStoreInfo,
-  getStoreDetail
+  editStoreInfo
 } from "@/api/modules/storeDecoration";
+import { getInputPrompt } from "@/api/modules/newLoginApi";
 import { useRoute } from "vue-router";
+import { localGet } from "@/utils";
 
 const route = useRoute();
 const formRef = ref<FormInstance>();
 const loading = ref(false);
+// 标记是否正在加载详情数据,用于防止触发 watch
+const isLoadingDetail = ref(false);
 
 // 表单数据
 const formData = reactive({
   id: "",
-  storeName: "重庆老火锅",
-  storeCapacity: 200,
-  storePhone: "13000010002",
-  storeArea: "50-100平米",
-  businessStatus: "正常营业",
-  province: "",
-  city: "",
-  district: "",
-  storeAddress: "中信丰悦大厦",
-  storeBlurb: "位于港湾广场地铁站直线500米",
-  locationQuery: "中信丰悦大厦",
-  businessSection: "美食",
-  businessTypes: ["小吃快餐", "火锅"] as string[],
-  expirationTime: "2025/06/11",
-  foodLicenseExpirationTime: "2025/06/11",
-  longitude: "",
-  latitude: ""
+  storeName: "",
+  storeCapacity: 0 as number,
+  storeTel: "",
+  storeArea: "",
+  businessStatus: "",
+  administrativeRegionProvinceAdcode: "",
+  administrativeRegionCityAdcode: "",
+  administrativeRegionDistrictAdcode: "",
+  storeAddress: "",
+  storeBlurb: "",
+  queryAddress: "",
+  businessSection: "",
+  businessTypes: [] as string[],
+  expirationTime: "",
+  foodLicenseExpirationTime: "",
+  storePositionLongitude: "",
+  storePositionLatitude: "",
+  isChain: 0
 });
 
 // 表单验证规则
 const rules = reactive<FormRules>({
   storeName: [{ required: true, message: "请输入店铺名称", trigger: "blur" }],
   storeCapacity: [{ required: true, message: "请输入容纳人数", trigger: "blur" }],
-  storePhone: [
+  storeTel: [
     { required: true, message: "请输入门店电话", trigger: "blur" },
     { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号码", trigger: "blur" }
   ],
   storeArea: [{ required: true, message: "请选择门店面积", trigger: "change" }],
   businessStatus: [{ required: true, message: "请选择营业状态", trigger: "change" }],
-  province: [{ required: true, message: "请选择省", trigger: "change" }],
-  city: [{ required: true, message: "请选择市", trigger: "change" }],
-  district: [{ required: true, message: "请选择区", trigger: "change" }],
+  administrativeRegionProvinceAdcode: [{ required: true, message: "请选择省", trigger: "change" }],
+  administrativeRegionCityAdcode: [{ required: true, message: "请选择市", trigger: "change" }],
+  administrativeRegionDistrictAdcode: [{ required: true, message: "请选择区", trigger: "change" }],
   storeAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
   storeBlurb: [{ required: true, message: "请输入门店简介", trigger: "blur" }],
-  locationQuery: [{ required: true, message: "请输入地址进行经纬度查询", trigger: "blur" }],
+  queryAddress: [{ required: true, message: "请输入地址进行经纬度查询", trigger: "blur" }],
   businessSection: [{ required: true, message: "请选择经营板块", trigger: "change" }],
   businessTypes: [{ required: true, message: "请选择经营种类", trigger: "change", type: "array" }]
 });
@@ -320,8 +323,8 @@ const getProvinceData = async () => {
 
 // 省份变化时获取城市数据
 const handleProvinceChange = async (provinceCode: string) => {
-  formData.city = "";
-  formData.district = "";
+  formData.administrativeRegionCityAdcode = "";
+  formData.administrativeRegionDistrictAdcode = "";
   cityOptions.value = [];
   districtOptions.value = [];
 
@@ -346,7 +349,7 @@ const handleProvinceChange = async (provinceCode: string) => {
 
 // 城市变化时获取区县数据
 const handleCityChange = async (cityCode: string) => {
-  formData.district = "";
+  formData.administrativeRegionDistrictAdcode = "";
   districtOptions.value = [];
 
   if (!cityCode) return;
@@ -367,12 +370,52 @@ const handleCityChange = async (cityCode: string) => {
     console.error("获取区县数据失败:", error);
   }
 };
+const businessMap = new Map();
+
+// 门店面积映射:字符串 -> 数字
+const storeAreaMap: Record<string, number> = {
+  小于20平米: 1,
+  "20-50平米": 2,
+  "50-100平米": 3,
+  "100-300平米": 4,
+  "300-500平米": 5,
+  "500-1000平米": 6,
+  大于1000平米: 7
+};
+
+// 门店面积反向映射:数字 -> 字符串
+const storeAreaReverseMap: Record<number, string> = {
+  1: "小于20平米",
+  2: "20-50平米",
+  3: "50-100平米",
+  4: "100-300平米",
+  5: "300-500平米",
+  6: "500-1000平米",
+  7: "大于1000平米"
+};
+
+// 营业状态映射:字符串 -> 数字
+const businessStatusMap: Record<string, number> = {
+  正常营业: 0,
+  暂停营业: 1,
+  筹建中: 2,
+  永久关门: 3
+};
+
+// 营业状态反向映射:数字 -> 字符串
+const businessStatusReverseMap: Record<number, string> = {
+  0: "正常营业",
+  1: "暂停营业",
+  2: "筹建中",
+  3: "永久关门"
+};
 
 // 获取经营板块列表(使用静态数据,也可以从API获取后合并)
 const getBusinessSectionData = async () => {
   try {
     // 如果API有数据,可以合并或替换静态数据
     const { data } = await getBusinessSection();
+    console.log(data, "---data--");
     if (data) {
       const dataAny = data as any;
       let apiData: any[] = [];
@@ -386,7 +429,10 @@ const getBusinessSectionData = async () => {
       }
       // 如果API返回了数据,可以选择使用API数据或合并
       // 这里保持使用静态数据,确保UI图的数据显示
-      // businessSectionList.value = apiData.length > 0 ? apiData : businessSectionList.value;
+      businessSectionList.value = apiData.length > 0 ? apiData : businessSectionList.value;
+      businessSectionList.value.forEach(item => {
+        businessMap.set(item.id, item);
+      });
     }
   } catch (error) {
     console.error("获取经营板块失败:", error);
@@ -401,26 +447,19 @@ const handleBusinessSectionChange = async (sectionId: string) => {
     formData.businessTypes = [];
     return;
   }
-
-  // 优先使用静态数据
-  if (businessTypeMap[sectionId] && businessTypeMap[sectionId].length > 0) {
-    businessTypeList.value = businessTypeMap[sectionId];
-    formData.businessTypes = [];
-    return;
-  }
-
-  // 如果静态数据中没有,尝试从API获取
   try {
-    const { data } = await getBusinessSectionTypes({ parentId: sectionId });
-    if (data) {
-      const dataAny = data as any;
+    const res = await getBusinessSectionTypes({ parentId: sectionId });
+    console.log(res, "--data--datax");
+
+    if (res && res.data) {
+      const dataAny = res.data as any;
       // 处理不同的返回格式
-      if (dataAny.list && Array.isArray(dataAny.list)) {
-        businessTypeList.value = dataAny.list;
-      } else if (Array.isArray(dataAny)) {
+      if (Array.isArray(dataAny)) {
         businessTypeList.value = dataAny;
       } else if (dataAny.data && Array.isArray(dataAny.data)) {
         businessTypeList.value = dataAny.data;
+      } else if (dataAny.list && Array.isArray(dataAny.list)) {
+        businessTypeList.value = dataAny.list;
       } else {
         businessTypeList.value = [];
       }
@@ -429,38 +468,53 @@ const handleBusinessSectionChange = async (sectionId: string) => {
     }
     // 清空已选择的经营种类
     formData.businessTypes = [];
-  } catch (error) {
+  } catch (error: any) {
+    // 忽略请求取消错误(这是正常的,当有重复请求时会被取消)
+    if (error?.code === "ERR_CANCELED" || error?.name === "CanceledError") {
+      console.log("请求被取消(可能是重复请求)");
+      return;
+    }
     console.error("获取经营种类失败:", error);
     businessTypeList.value = [];
+    formData.businessTypes = [];
   }
 };
 
-// 经纬度查询
-const handleLocationQuery = async () => {
-  if (!formData.locationQuery) {
-    ElMessage.warning("请输入地址进行查询");
-    return;
+// 经纬度查询(返回是否成功)
+const queryLocation = async (address?: string): Promise<boolean> => {
+  const queryAddr = address || formData.queryAddress;
+  if (!queryAddr) {
+    return false;
   }
   try {
-    const { data } = await getInputPrompt({ keywords: formData.locationQuery } as any);
-    const dataArray = Array.isArray(data) ? data : data ? [data] : [];
-    if (dataArray.length > 0) {
-      const location = dataArray[0];
-      if (location.location) {
-        const coords = location.location.split(",");
-        formData.longitude = coords[0] || "";
-        formData.latitude = coords[1] || "";
-      }
-      if (location.name) {
-        formData.storeAddress = location.name;
+    const { data }: any = await getInputPrompt({ addressName: queryAddr } as any);
+    if (data.tips && data.tips.length > 0) {
+      if (!data.tips[0].location) {
+        return false;
       }
-      ElMessage.success("查询成功");
-    } else {
-      ElMessage.warning("未找到相关地址信息");
+      let latlng = data.tips[0].location.split(",");
+      formData.storePositionLongitude = latlng[0];
+      formData.storePositionLatitude = latlng[1];
+      return true;
     }
+    return false;
   } catch (error) {
     console.error("经纬度查询失败:", error);
-    ElMessage.error("查询失败,请稍后重试");
+    return false;
+  }
+};
+
+// 经纬度查询(用户手动触发)
+const handleLocationQuery = async () => {
+  if (!formData.queryAddress) {
+    ElMessage.warning("请输入地址进行查询");
+    return;
+  }
+  const success = await queryLocation();
+  if (success) {
+    ElMessage.success("查询成功");
+  } else {
+    ElMessage.warning("未找到相关地址信息,请检查地址是否正确");
   }
 };
 
@@ -476,22 +530,34 @@ const handleSubmit = async () => {
 
     loading.value = true;
     try {
+      // 保存前先调用经纬度查询接口
+      if (formData.queryAddress) {
+        const locationQuerySuccess = await queryLocation();
+        if (!locationQuerySuccess) {
+          ElMessage.warning("经纬度查询失败,请检查地址是否正确,将继续保存其他信息");
+        }
+      }
+
+      // 映射门店面积为数字
+      const storeAreaNum = storeAreaMap[formData.storeArea] || 0;
+      // 映射营业状态为数字
+      const businessStatusNum = businessStatusMap[formData.businessStatus] ?? 0;
+
       const submitData = {
-        id: formData.id,
+        id: formData.id ? Number(formData.id) : undefined,
+        isChain: formData.isChain,
         storeName: formData.storeName,
-        storeCapacity: formData.storeCapacity,
-        storePhone: formData.storePhone,
-        storeArea: formData.storeArea,
-        businessStatus: formData.businessStatus,
-        province: formData.province || "",
-        city: formData.city || "",
-        district: formData.district || "",
+        storeCapacity: String(formData.storeCapacity || ""),
+        storeTel: formData.storeTel,
         storeAddress: formData.storeAddress,
-        storeBlurb: formData.storeBlurb,
-        businessSection: formData.businessSection,
-        businessTypes: formData.businessTypes,
-        longitude: formData.longitude,
-        latitude: formData.latitude
+        storeArea: formData.storeArea,
+        queryAddress: formData.queryAddress,
+        administrativeRegionProvinceAdcode: formData.administrativeRegionProvinceAdcode || "",
+        administrativeRegionCityAdcode: formData.administrativeRegionCityAdcode || "",
+        administrativeRegionDistrictAdcode: formData.administrativeRegionDistrictAdcode || "",
+        storePositionLongitude: formData.storePositionLongitude,
+        storePositionLatitude: formData.storePositionLatitude,
+        businessStatus: formData.businessStatus
       };
 
       let result;
@@ -525,45 +591,56 @@ const handleSubmit = async () => {
   });
 };
 
+const userInfo = localGet("geeker-user")?.userInfo || {};
 // 获取店铺详情(编辑时使用)
 const getStoreDetailData = async () => {
-  const id = route.query.id as string;
-  if (!id) return;
-
+  isLoadingDetail.value = true; // 标记开始加载详情
   try {
-    const { data } = await getStoreDetail({ id } as any);
+    const { data } = await getStoreDetail({ id: userInfo.id } as any);
     if (data) {
       const storeData = data as any;
       formData.id = storeData.id || "";
       formData.storeName = storeData.storeName || "";
-      formData.storeCapacity = storeData.storeCapacity || 0;
-      formData.storePhone = storeData.storePhone || "";
+      formData.storeCapacity = Number(storeData.storeCapacity) || 0;
+      formData.storeTel = storeData.storeTel || "";
+      // 将数字映射回字符串
       formData.storeArea = storeData.storeArea || "";
+      // 将数字映射回字符串
       formData.businessStatus = storeData.businessStatus || "";
       formData.storeAddress = storeData.storeAddress || "";
       formData.storeBlurb = storeData.storeBlurb || "";
       formData.expirationTime = storeData.expirationTime || "";
       formData.foodLicenseExpirationTime = storeData.foodLicenseExpirationTime || "";
-      formData.longitude = storeData.longitude || storeData.storePositionLongitude || "";
-      formData.latitude = storeData.latitude || storeData.storePositionLatitude || "";
+      formData.storePositionLongitude = storeData.storePositionLongitude || "";
+      formData.storePositionLatitude = storeData.storePositionLatitude || "";
+      formData.isChain = storeData.isChain ?? 0;
+      formData.queryAddress = storeData.queryAddress;
 
       // 设置地区
-      if (storeData.province) {
-        formData.province = storeData.province;
-        await handleProvinceChange(storeData.province);
-        if (storeData.city) {
-          formData.city = storeData.city;
-          await handleCityChange(storeData.city);
-          if (storeData.district) {
-            formData.district = storeData.district;
+      const provinceCode = storeData.administrativeRegionProvinceAdcode || "";
+      const cityCode = storeData.administrativeRegionCityAdcode || "";
+      const districtCode = storeData.administrativeRegionDistrictAdcode || "";
+
+      if (provinceCode) {
+        formData.administrativeRegionProvinceAdcode = provinceCode;
+        await handleProvinceChange(provinceCode);
+        if (cityCode) {
+          formData.administrativeRegionCityAdcode = cityCode;
+          await handleCityChange(cityCode);
+          if (districtCode) {
+            formData.administrativeRegionDistrictAdcode = districtCode;
           }
         }
       }
 
       // 设置经营板块和种类
       if (storeData.businessSection) {
-        formData.businessSection = storeData.businessSection;
-        await handleBusinessSectionChange(storeData.businessSection);
+        const sectionId = String(storeData.businessSection);
+        // 直接调用 handleBusinessSectionChange,因为 isLoadingDetail 会阻止 watch 触发
+        await handleBusinessSectionChange(sectionId);
+        // 设置 businessSection(此时 watch 不会触发,因为 isLoadingDetail 为 true)
+        formData.businessSection = sectionId;
+        // 设置已选择的经营种类
         if (storeData.businessTypes) {
           formData.businessTypes = Array.isArray(storeData.businessTypes) ? storeData.businessTypes : [storeData.businessTypes];
         }
@@ -571,6 +648,8 @@ const getStoreDetailData = async () => {
     }
   } catch (error) {
     console.error("获取店铺详情失败:", error);
+  } finally {
+    isLoadingDetail.value = false; // 标记加载完成
   }
 };
 
@@ -578,7 +657,12 @@ const getStoreDetailData = async () => {
 watch(
   () => formData.businessSection,
   newValue => {
+    // 如果正在加载详情数据,不触发 watch(避免重复请求)
+    if (isLoadingDetail.value) {
+      return;
+    }
     if (newValue) {
+      console.log(newValue, "--newValue");
       handleBusinessSectionChange(newValue);
     }
   }

+ 208 - 45
src/views/storeDecoration/businessHours/index.vue

@@ -135,9 +135,9 @@
 
 <script setup lang="ts">
 import { ref, reactive, computed, onMounted } from "vue";
-import { ElMessage } from "element-plus";
-// TODO: 导入营业时间相关的 API 接口
-// import { getBusinessHours, saveBusinessHours, deleteNormalHours, deleteSpecialHours, getHolidayList } from "@/api/modules/storeDecoration";
+import { ElMessage, ElNotification } from "element-plus";
+import { getBusinessTimeList, addOrEditBusinessTime } from "@/api/modules/storeDecoration";
+import { localGet } from "@/utils";
 
 // 周一到周日
 const weekDays = [
@@ -171,26 +171,24 @@ const holidays = ref([
 
 // 正常营业时间列表
 interface NormalHoursItem {
+  id?: number | null;
   days: number[];
   timeType: "custom" | "24hours";
   startTime?: string;
   endTime?: string;
 }
 
-// TODO: 页面初始化时从接口获取正常营业时间数据
-const normalHours = ref<NormalHoursItem[]>([
-  { days: [1, 2, 3, 4, 5, 6, 7], timeType: "custom", startTime: "07:00", endTime: "19:00" }
-]);
+const normalHours = ref<NormalHoursItem[]>([]);
 
 // 特殊营业时间列表
 interface SpecialHoursItem {
+  id?: number | null;
   holidays: string[];
   timeType: "custom" | "24hours";
   startTime?: string;
   endTime?: string;
 }
 
-// TODO: 页面初始化时从接口获取特殊营业时间数据
 const specialHours = ref<SpecialHoursItem[]>([]);
 
 // 正常营业时间对话框
@@ -282,16 +280,24 @@ const editNormalHours = (index: number) => {
   const item = normalHours.value[index];
   normalForm.selectedDays = [...item.days];
   normalForm.timeType = item.timeType;
-  normalForm.startTime = item.startTime || "";
-  normalForm.endTime = item.endTime || "";
+  // 如果是24小时模式,不设置时间;如果是自定义模式,设置时间
+  if (item.timeType === "custom") {
+    normalForm.startTime = item.startTime || "";
+    normalForm.endTime = item.endTime || "";
+  } else {
+    normalForm.startTime = "";
+    normalForm.endTime = "";
+  }
   normalDialogVisible.value = true;
 };
 
-// 删除正常营业时间
+// 删除正常营业时间(删除逻辑:不在保存数组里的就是删除了)
 const deleteNormalHours = (index: number) => {
-  // TODO: 调用删除正常营业时间接口 deleteNormalHours API
-  // const item = normalHours.value[index];
-  // await deleteNormalHours({ id: item.id });
+  // 禁止删除最后一条
+  if (normalHours.value.length <= 1) {
+    ElMessage.warning("至少存在一条营业时间");
+    return;
+  }
   normalHours.value.splice(index, 1);
   ElMessage.success("删除成功");
 };
@@ -319,11 +325,13 @@ const confirmNormalHours = () => {
   const newItem: NormalHoursItem = {
     days: [...normalForm.selectedDays],
     timeType: normalForm.timeType,
-    startTime: normalForm.timeType === "custom" ? normalForm.startTime : undefined,
-    endTime: normalForm.timeType === "custom" ? normalForm.endTime : undefined
+    startTime: normalForm.timeType === "custom" ? normalForm.startTime : "00:00",
+    endTime: normalForm.timeType === "custom" ? normalForm.endTime : "23:59"
   };
 
   if (normalEditIndex.value !== null) {
+    // 编辑时保留id
+    newItem.id = normalHours.value[normalEditIndex.value].id;
     normalHours.value[normalEditIndex.value] = newItem;
     ElMessage.success("编辑成功");
   } else {
@@ -348,16 +356,20 @@ const editSpecialHours = (index: number) => {
   const item = specialHours.value[index];
   specialForm.selectedHolidays = [...item.holidays];
   specialForm.timeType = item.timeType;
-  specialForm.startTime = item.startTime || "";
-  specialForm.endTime = item.endTime || "";
+  // 如果是24小时模式,不设置时间;如果是自定义模式,设置时间
+  if (item.timeType === "custom") {
+    specialForm.startTime = item.startTime || "";
+    specialForm.endTime = item.endTime || "";
+  } else {
+    specialForm.startTime = "";
+    specialForm.endTime = "";
+  }
   specialDialogVisible.value = true;
 };
 
-// 删除特殊营业时间
+// 删除特殊营业时间(删除逻辑:不在保存数组里的就是删除了)
 const deleteSpecialHours = (index: number) => {
-  // TODO: 调用删除特殊营业时间接口 deleteSpecialHours API
-  // const item = specialHours.value[index];
-  // await deleteSpecialHours({ id: item.id });
+  // 特殊营业时间可以全部删除,不需要限制
   specialHours.value.splice(index, 1);
   ElMessage.success("删除成功");
 };
@@ -385,11 +397,13 @@ const confirmSpecialHours = () => {
   const newItem: SpecialHoursItem = {
     holidays: [...specialForm.selectedHolidays],
     timeType: specialForm.timeType,
-    startTime: specialForm.timeType === "custom" ? specialForm.startTime : undefined,
-    endTime: specialForm.timeType === "custom" ? specialForm.endTime : undefined
+    startTime: specialForm.timeType === "custom" ? specialForm.startTime : "00:00",
+    endTime: specialForm.timeType === "custom" ? specialForm.endTime : "23:59"
   };
 
   if (specialEditIndex.value !== null) {
+    // 编辑时保留id
+    newItem.id = specialHours.value[specialEditIndex.value].id;
     specialHours.value[specialEditIndex.value] = newItem;
     ElMessage.success("编辑成功");
   } else {
@@ -401,33 +415,182 @@ const confirmSpecialHours = () => {
   resetSpecialForm();
 };
 
+// 将接口数据转换为页面显示格式
+const convertApiDataToDisplay = (apiData: any[]) => {
+  const normalList: NormalHoursItem[] = [];
+  const specialList: SpecialHoursItem[] = [];
+
+  apiData.forEach((item: any) => {
+    if (item.businessType === 1) {
+      // 正常营业时间
+      // 将businessDate字符串转换为days数组
+      const businessDate = item.businessDate || "";
+      const dayLabels = businessDate.split("、");
+      const days: number[] = [];
+      dayLabels.forEach((label: string) => {
+        const day = weekDays.find(d => d.label === label.trim());
+        if (day) {
+          days.push(day.value);
+        }
+      });
+
+      // 判断是否为24小时:startTime为00:00且endTime为23:59或02:00(跨天情况)
+      const is24Hours = item.startTime === "00:00" && (item.endTime === "23:59" || item.endTime === "02:00");
+
+      normalList.push({
+        id: item.id,
+        days: days,
+        timeType: is24Hours ? "24hours" : "custom",
+        startTime: is24Hours ? undefined : item.startTime,
+        endTime: is24Hours ? undefined : item.endTime
+      });
+    } else if (item.businessType === 2) {
+      // 特殊营业时间
+      // 将businessDate字符串转换为holidays数组
+      const businessDate = item.businessDate || "";
+      const holidayLabels = businessDate.split("、").map((h: string) => h.trim());
+
+      // 判断是否为24小时
+      const is24Hours = item.startTime === "00:00" && (item.endTime === "23:59" || item.endTime === "02:00");
+
+      specialList.push({
+        id: item.id,
+        holidays: holidayLabels,
+        timeType: is24Hours ? "24hours" : "custom",
+        startTime: is24Hours ? undefined : item.startTime,
+        endTime: is24Hours ? undefined : item.endTime
+      });
+    }
+  });
+
+  return { normalList, specialList };
+};
+
+// 获取营业时间数据
+const getBusinessTimeData = async () => {
+  try {
+    const userInfo: any = localGet("geeker-user")?.userInfo || {};
+    const storeId = userInfo.id || userInfo.storeId;
+    if (!storeId) {
+      console.warn("未找到店铺ID");
+      return;
+    }
+
+    const res: any = await getBusinessTimeList({ storeId: Number(storeId) });
+    if (res && (res.code === 200 || res.code === "200") && res.data) {
+      const dataList = Array.isArray(res.data) ? res.data : res.data.list || [];
+      const { normalList, specialList } = convertApiDataToDisplay(dataList);
+      normalHours.value = normalList;
+      specialHours.value = specialList;
+    }
+  } catch (error) {
+    console.error("获取营业时间失败:", error);
+  }
+};
+
 // 页面初始化时获取数据
 onMounted(async () => {
-  // TODO: 调用获取营业时间接口 getBusinessHours API,初始化 normalHours 和 specialHours
-  // const res = await getBusinessHours();
-  // if (res.data) {
-  //   normalHours.value = res.data.normalHours || [];
-  //   specialHours.value = res.data.specialHours || [];
-  // }
-  // TODO: 如果节假日列表需要从接口获取,调用 getHolidayList API
-  // const holidayRes = await getHolidayList({});
-  // if (holidayRes.data) {
-  //   holidays.value = holidayRes.data.map(item => ({ label: item.name, value: item.name }));
-  // }
+  await getBusinessTimeData();
 });
 
+// 将页面数据转换为接口格式
+const convertDisplayDataToApi = () => {
+  const apiDataList: any[] = [];
+  const userInfo: any = localGet("geeker-user")?.userInfo || {};
+  const storeId = userInfo.id || userInfo.storeId;
+
+  // 转换正常营业时间
+  normalHours.value.forEach(item => {
+    // 将days数组转换为businessDate字符串
+    const sortedDays = [...item.days].sort((a, b) => a - b);
+    const dayLabels = sortedDays.map(day => weekDays.find(d => d.value === day)?.label).filter(Boolean);
+    const businessDate = dayLabels.join("、");
+
+    // 处理24小时:设置为00:00到23:59
+    const startTime = item.timeType === "24hours" ? "00:00" : item.startTime || "00:00";
+    const endTime = item.timeType === "24hours" ? "23:59" : item.endTime || "23:59";
+
+    apiDataList.push({
+      // id: item.id || 0,
+      storeId: Number(storeId),
+      businessType: 1,
+      businessDate: businessDate,
+      startTime: startTime,
+      endTime: endTime,
+      deleteFlag: 0,
+      createdTime: "",
+      createdUserId: 0,
+      updatedTime: "",
+      updatedUserId: 0
+    });
+  });
+
+  // 转换特殊营业时间
+  specialHours.value.forEach(item => {
+    // 将holidays数组转换为businessDate字符串
+    const businessDate = item.holidays.join("、");
+
+    // 处理24小时:设置为00:00到23:59
+    const startTime = item.timeType === "24hours" ? "00:00" : item.startTime || "00:00";
+    const endTime = item.timeType === "24hours" ? "23:59" : item.endTime || "23:59";
+
+    apiDataList.push({
+      // id: item.id || 0,
+      storeId: Number(storeId),
+      businessType: 2,
+      businessDate: businessDate,
+      startTime: startTime,
+      endTime: endTime,
+      deleteFlag: 0,
+      createdTime: "",
+      createdUserId: 0,
+      updatedTime: "",
+      updatedUserId: 0
+    });
+  });
+
+  return apiDataList;
+};
+
 // 保存
 const handleSave = async () => {
-  // TODO: 调用保存营业时间接口 saveBusinessHours API
-  // 需要将 normalHours 和 specialHours 数据格式化为接口所需格式
-  // const params = {
-  //   normalHours: normalHours.value,
-  //   specialHours: specialHours.value
-  // };
-  // await saveBusinessHours(params);
-  console.log("正常营业时间:", normalHours.value);
-  console.log("特殊营业时间:", specialHours.value);
-  ElMessage.success("保存成功");
+  try {
+    // 保存前检查:至少需要有一条正常营业时间
+    if (normalHours.value.length === 0) {
+      ElMessage.warning("至少存在一条营业时间");
+      return;
+    }
+
+    const userInfo: any = localGet("geeker-user")?.userInfo || {};
+    const storeId = userInfo.id || userInfo.storeId;
+    if (!storeId) {
+      ElMessage.error("未找到店铺ID,请先完成店铺信息填写");
+      return;
+    }
+
+    // 转换为接口格式(包含所有正常营业时间和特殊营业时间)
+    // 不在这个数组里的数据会被删除
+    const apiDataList = convertDisplayDataToApi();
+
+    // 批量保存(一次性提交整个数组)
+    const result: any = await addOrEditBusinessTime(apiDataList);
+
+    if (result && (result.code === 200 || result.code === "200")) {
+      ElNotification({
+        title: "保存成功",
+        type: "success",
+        duration: 3000
+      });
+
+      // 保存成功后重新获取数据,更新id
+      await getBusinessTimeData();
+    } else {
+      ElMessage.error(result?.msg || "保存失败");
+    }
+  } catch (error: any) {
+    console.error("保存失败:", error);
+    ElMessage.error(error?.msg || "保存失败,请重试");
+  }
 };
 </script>
 

+ 72 - 18
src/views/storeDecoration/storeEntranceMap/index.vue

@@ -71,12 +71,12 @@
 
 <script setup lang="ts">
 import { ref, reactive, onMounted } from "vue";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElNotification } from "element-plus";
 import type { FormInstance, FormRules } from "element-plus";
 import UploadImg from "@/components/Upload/Img.vue";
-import { uploadImg } from "@/api/modules/upload";
-// TODO: 导入入口图相关的 API 接口
-// import { getEntranceMap, saveEntranceMap } from "@/api/modules/storeDecoration";
+import { uploadImg } from "@/api/modules/newLoginApi";
+import { getEntranceImg, saveEntranceImg } from "@/api/modules/storeDecoration";
+import { localGet } from "@/utils";
 
 const loading = ref(false);
 const formRef = ref<FormInstance>();
@@ -139,7 +139,18 @@ const customUploadApi = async (formData: FormData): Promise<any> => {
   }
 
   // 校验通过后调用实际上传接口
-  return uploadImg(formData);
+  const response: any = await uploadImg(formData);
+  // 处理返回格式:{ code, success, data: string[], msg }
+  // UploadImg组件期望的格式:{ data: { fileUrl: string } } 或 { data: string[] }
+  if (response && response.code === 200 && response.data && Array.isArray(response.data) && response.data.length > 0) {
+    // 返回组件期望的格式:组件会检查 data.fileUrl,如果没有则取 data[0]
+    return {
+      data: {
+        fileUrl: response.data[0] // 取数组第一个元素作为图片URL
+      }
+    };
+  }
+  throw new Error(response?.msg || "上传失败");
 };
 
 // 表单校验规则
@@ -168,13 +179,32 @@ const previewData = reactive({
   distance: "616m"
 });
 
+// 获取入口图数据
+const getEntranceImgData = async () => {
+  try {
+    const userInfo: any = localGet("geeker-user")?.userInfo || {};
+    const storeId = userInfo.id || userInfo.storeId;
+    if (!storeId) {
+      console.warn("未找到店铺ID");
+      return;
+    }
+    const res: any = await getEntranceImg(storeId);
+    if (res && (res.code === 200 || res.code === "200") && res.data) {
+      // 处理返回数据,取第一张图片
+      const dataAny = res.data as any;
+      const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
+      if (imgList.length > 0 && imgList[0].imgUrl) {
+        formData.entranceImage = imgList[0].imgUrl;
+      }
+    }
+  } catch (error) {
+    console.error("获取入口图失败:", error);
+  }
+};
+
 // 页面初始化时获取数据
 onMounted(async () => {
-  // TODO: 调用获取入口图接口 getEntranceMap API
-  // const res = await getEntranceMap();
-  // if (res.data && res.data.entranceImage) {
-  //   formData.entranceImage = res.data.entranceImage;
-  // }
+  await getEntranceImgData();
 });
 
 // 保存
@@ -194,18 +224,42 @@ const handleSave = async () => {
     return;
   }
 
+  // 获取店铺ID
+  const userInfo: any = localGet("geeker-user")?.userInfo || {};
+  const storeId = userInfo.id || userInfo.storeId;
+  if (!storeId) {
+    ElMessage.error("未找到店铺ID,请先完成店铺信息填写");
+    return;
+  }
+
   loading.value = true;
   try {
-    // TODO: 调用保存入口图接口 saveEntranceMap API
-    // const params = {
-    //   entranceImage: formData.entranceImage
-    // };
-    // await saveEntranceMap(params);
+    // 构建保存参数
+    const params = {
+      imgType: 1,
+      storeId: Number(storeId),
+      storeImgList: [
+        {
+          imgType: 1,
+          imgUrl: formData.entranceImage,
+          storeId: Number(storeId)
+        }
+      ]
+    };
 
-    ElMessage.success("保存成功");
-  } catch (error) {
-    ElMessage.error("保存失败,请重试");
+    const result: any = await saveEntranceImg(params);
+    if (result && (result.code === 200 || result.code === "200")) {
+      ElNotification({
+        title: "保存成功",
+        type: "success",
+        duration: 3000
+      });
+    } else {
+      ElMessage.error(result?.msg || "保存失败");
+    }
+  } catch (error: any) {
     console.error("保存失败:", error);
+    ElMessage.error(error?.msg || "保存失败,请重试");
   } finally {
     loading.value = false;
   }

+ 207 - 47
src/views/storeDecoration/storeHeadMap/index.vue

@@ -7,7 +7,7 @@
         <div class="preview-box" :class="{ active: mode === 'single' }" @click="mode = 'single'">
           <div class="preview-card">
             <div class="preview-image-large">
-              <img v-if="mode === 'single' && formData.singleImage" :src="formData.singleImage" alt="单图" />
+              <img v-if="formData.singleImage" :src="formData.singleImage" alt="单图" />
               <div v-else class="preview-placeholder">示例图</div>
               <div class="overlay-button">
                 <span>相册</span>
@@ -133,16 +133,16 @@
 
 <script setup lang="ts">
 import { ref, reactive, computed, onMounted, watch, nextTick } from "vue";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElNotification } from "element-plus";
 import type { FormInstance, FormRules } from "element-plus";
 import type { UploadUserFile } from "element-plus";
 import { ArrowRight } from "@element-plus/icons-vue";
 import Sortable from "sortablejs";
 import UploadImg from "@/components/Upload/Img.vue";
 import UploadImgs from "@/components/Upload/Imgs.vue";
-import { uploadImg } from "@/api/modules/upload";
-// TODO: 导入头图相关的 API 接口
-// import { getStoreHeadMap, saveStoreHeadMap } from "@/api/modules/storeDecoration";
+import { uploadImg } from "@/api/modules/newLoginApi";
+import { getStoreHeadImg, saveStoreHeadImg } from "@/api/modules/storeDecoration";
+import { localGet } from "@/utils";
 
 const loading = ref(false);
 const singleFormRef = ref<FormInstance>();
@@ -164,12 +164,9 @@ const previewData = reactive({
   reviews: 1853
 });
 
-// 显示的多图预览(最多显示3张)
+// 显示的多图预览(最多显示3张)- 始终显示多图数据,不依赖当前模式
 const displayImages = computed(() => {
-  if (mode.value === "multiple") {
-    return formData.multipleImages.slice(0, 3).map(item => item.url || "");
-  }
-  return [];
+  return formData.multipleImages.slice(0, 3).map(item => item.url || "");
 });
 
 // 单图模式:图片尺寸和比例校验函数(1:1,900*900)
@@ -260,7 +257,16 @@ const singleImageUploadApi = async (formData: FormData): Promise<any> => {
   }
 
   // 校验通过后调用实际上传接口
-  return uploadImg(formData);
+  const response: any = await uploadImg(formData);
+  // 处理返回格式:{ code, success, data: string[], msg }
+  if (response && response.code === 200 && response.data && Array.isArray(response.data) && response.data.length > 0) {
+    return {
+      data: {
+        fileUrl: response.data[0] // 取数组第一个元素作为图片URL
+      }
+    };
+  }
+  throw new Error(response?.msg || "上传失败");
 };
 
 // 多图模式:自定义上传API
@@ -275,7 +281,16 @@ const multipleImageUploadApi = async (formData: FormData): Promise<any> => {
   }
 
   // 校验通过后调用实际上传接口
-  return uploadImg(formData);
+  const response: any = await uploadImg(formData);
+  // 处理返回格式:{ code, success, data: string[], msg }
+  if (response && response.code === 200 && response.data && Array.isArray(response.data) && response.data.length > 0) {
+    return {
+      data: {
+        fileUrl: response.data[0] // 取数组第一个元素作为图片URL
+      }
+    };
+  }
+  throw new Error(response?.msg || "上传失败");
 };
 
 // 单图模式表单校验规则
@@ -311,19 +326,20 @@ const multipleRules = reactive<FormRules>({
   ]
 });
 
-// 监听模式切换,清空另一个模式的数据
+// 标记是否正在初始化,防止初始化时触发查询
+const isInitializing = ref(true);
+
+// 监听模式切换,查询对应模式的数据
 watch(
   () => mode.value,
-  newMode => {
-    if (newMode === "single") {
-      formData.multipleImages = [];
-    } else {
-      formData.singleImage = "";
-      // 切换到多图模式时,初始化拖拽排序
-      nextTick(() => {
-        initDragSort();
-      });
+  async (newMode, oldMode) => {
+    // 初始化时不触发查询(因为初始化时已经查询过了)
+    if (isInitializing.value) {
+      return;
     }
+
+    // 切换模式时,查询对应模式的数据
+    await loadHeadImgByMode(newMode);
   }
 );
 
@@ -362,22 +378,125 @@ const initDragSort = () => {
   });
 };
 
+// 根据模式查询对应的头图数据
+const loadHeadImgByMode = async (targetMode: "single" | "multiple") => {
+  try {
+    const userInfo: any = localGet("geeker-user")?.userInfo || {};
+    const storeId = userInfo.id || userInfo.storeId;
+    if (!storeId) {
+      console.warn("未找到店铺ID");
+      return;
+    }
+
+    const imgType = targetMode === "single" ? 20 : 21;
+    const res: any = await getStoreHeadImg(storeId, imgType);
+
+    if (res && (res.code === 200 || res.code === "200") && res.data) {
+      const dataAny = res.data as any;
+      const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
+
+      if (targetMode === "single") {
+        // 单图模式
+        if (imgList.length > 0 && imgList[0].imgUrl) {
+          formData.singleImage = imgList[0].imgUrl;
+        } else {
+          formData.singleImage = "";
+        }
+      } else {
+        // 多图模式
+        if (imgList.length > 0) {
+          formData.multipleImages = imgList.map((item: any, index: number) => ({
+            uid: item.id || index,
+            name: `image-${index + 1}`,
+            url: item.imgUrl,
+            status: "success"
+          }));
+          // 初始化拖拽排序
+          nextTick(() => {
+            initDragSort();
+          });
+        } else {
+          formData.multipleImages = [];
+        }
+      }
+    } else {
+      // 如果没有数据,清空对应模式的数据
+      if (targetMode === "single") {
+        formData.singleImage = "";
+      } else {
+        formData.multipleImages = [];
+      }
+    }
+  } catch (error) {
+    console.error(`获取${targetMode === "single" ? "单图" : "多图"}模式头图失败:`, error);
+    // 查询失败时清空数据
+    if (targetMode === "single") {
+      formData.singleImage = "";
+    } else {
+      formData.multipleImages = [];
+    }
+  }
+};
+
+// 获取头图数据(初始化时同时加载单图和多图数据,用于示例图展示)
+const getStoreHeadImgData = async () => {
+  try {
+    const userInfo: any = localGet("geeker-user")?.userInfo || {};
+    const storeId = userInfo.id || userInfo.storeId;
+    if (!storeId) {
+      console.warn("未找到店铺ID");
+      return;
+    }
+
+    // 同时查询单图模式(imgType: 20)和多图模式(imgType: 21)
+    const [singleRes, multipleRes] = await Promise.all([getStoreHeadImg(storeId, 20), getStoreHeadImg(storeId, 21)]);
+
+    // 处理单图数据
+    const singleResAny: any = singleRes;
+    if (singleResAny && (singleResAny.code === 200 || singleResAny.code === "200") && singleResAny.data) {
+      const dataAny = singleResAny.data as any;
+      const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
+      if (imgList.length > 0 && imgList[0].imgUrl) {
+        formData.singleImage = imgList[0].imgUrl;
+      }
+    }
+
+    // 处理多图数据
+    const multipleResAny: any = multipleRes;
+    if (multipleResAny && (multipleResAny.code === 200 || multipleResAny.code === "200") && multipleResAny.data) {
+      const dataAny = multipleResAny.data as any;
+      const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
+      if (imgList.length > 0) {
+        formData.multipleImages = imgList.map((item: any, index: number) => ({
+          uid: item.id || index,
+          name: `image-${index + 1}`,
+          url: item.imgUrl,
+          status: "success"
+        }));
+      }
+    }
+
+    // 根据数据情况设置默认模式:优先单图,如果没有单图则使用多图
+    if (formData.singleImage) {
+      mode.value = "single";
+    } else if (formData.multipleImages.length > 0) {
+      mode.value = "multiple";
+      // 初始化拖拽排序
+      nextTick(() => {
+        initDragSort();
+      });
+    }
+  } catch (error) {
+    console.error("获取头图失败:", error);
+  }
+};
+
 // 页面初始化时获取数据
 onMounted(async () => {
-  // TODO: 调用获取头图接口 getStoreHeadMap API
-  // const res = await getStoreHeadMap();
-  // if (res.data) {
-  //   mode.value = res.data.mode || 'single';
-  //   if (res.data.mode === 'single') {
-  //     formData.singleImage = res.data.singleImage || '';
-  //   } else {
-  //     formData.multipleImages = res.data.multipleImages || [];
-  //     // 初始化拖拽排序
-  //     nextTick(() => {
-  //       initDragSort();
-  //     });
-  //   }
-  // }
+  await getStoreHeadImgData();
+
+  // 标记初始化完成
+  isInitializing.value = false;
 
   // 如果默认是多图模式,初始化拖拽排序
   if (mode.value === "multiple") {
@@ -407,20 +526,61 @@ const handleSave = async () => {
     }
   }
 
+  // 获取店铺ID
+  const userInfo: any = localGet("geeker-user")?.userInfo || {};
+  const storeId = userInfo.id || userInfo.storeId;
+  if (!storeId) {
+    ElMessage.error("未找到店铺ID,请先完成店铺信息填写");
+    return;
+  }
+
   loading.value = true;
   try {
-    // TODO: 调用保存头图接口 saveStoreHeadMap API
-    // const params = {
-    //   mode: mode.value,
-    //   singleImage: mode.value === 'single' ? formData.singleImage : '',
-    //   multipleImages: mode.value === 'multiple' ? formData.multipleImages.map(item => item.url) : []
-    // };
-    // await saveStoreHeadMap(params);
-
-    ElMessage.success("保存成功");
-  } catch (error) {
-    ElMessage.error("保存失败,请重试");
+    const imgType = mode.value === "single" ? 20 : 21;
+    let storeImgList: any[] = [];
+
+    if (mode.value === "single") {
+      // 单图模式
+      if (formData.singleImage) {
+        storeImgList = [
+          {
+            imgType: 20,
+            imgUrl: formData.singleImage,
+            imgSort: 1,
+            storeId: Number(storeId)
+          }
+        ];
+      }
+    } else {
+      // 多图模式
+      storeImgList = formData.multipleImages.map((item, index) => ({
+        imgType: 21,
+        imgUrl: item.url || "",
+        imgSort: index + 1,
+        storeId: Number(storeId)
+      }));
+    }
+
+    const params = {
+      imgMode: mode.value === "single" ? 0 : 1,
+      imgType: imgType,
+      storeId: Number(storeId),
+      storeImgList: storeImgList
+    };
+
+    const result: any = await saveStoreHeadImg(params);
+    if (result && (result.code === 200 || result.code === "200")) {
+      ElNotification({
+        title: "保存成功",
+        type: "success",
+        duration: 3000
+      });
+    } else {
+      ElMessage.error(result?.msg || "保存失败");
+    }
+  } catch (error: any) {
     console.error("保存失败:", error);
+    ElMessage.error(error?.msg || "保存失败,请重试");
   } finally {
     loading.value = false;
   }