zhuli 1 неделя назад
Родитель
Сommit
d31d074967

+ 33 - 0
src/api/modules/businessInfo.ts

@@ -0,0 +1,33 @@
+import httpLogin from "@/api/indexApi";
+
+/**
+ * @name 商家信息
+ */
+
+// 营业执照上传
+export const getUpload = (params: any) => {
+  return httpLogin.post(`alienStore/payment/wechatPartner/v3/merchant/media/upload`, params);
+};
+
+export const getOcrRequestByBase64 = (params: any) => {
+  return httpLogin.post(`alienStore/ali/ocrRequestByBase64`, params);
+};
+
+/** POST,storeId 走 URL 查询参数,请求体为 JSON */
+export const applyment = (data: Record<string, unknown> | object, storeId: string | number) => {
+  return httpLogin.post(`alienStore/payment/wechatPartner/v3/applyment4sub/applyment`, data, {
+    params: { storeId },
+    headers: { "Content-Type": "application/json;charset=UTF-8" }
+  });
+};
+
+/** GET,storeId 为路径参数 */
+export const applymentExamine = (storeId: string | number) => {
+  const id = encodeURIComponent(String(storeId).trim());
+  return httpLogin.get(`alienStore/payment/wechatPartner/applyment/store/${id}`);
+};
+
+export const getPaymentApplyment = (applymentId: string | number) => {
+  const id = encodeURIComponent(String(applymentId).trim());
+  return httpLogin.get(`alienStore/payment/wechatPartner/v3/applyment4sub/applyment/applyment_id/${id}`);
+};

BIN
src/assets/images/yyzz.jpg


+ 3422 - 0
src/assets/json/city.json

@@ -0,0 +1,3422 @@
+{
+    "cityList": [
+        {
+            "letter": "A",
+            "list": [
+                {
+                    "name": "阿克苏市",
+                    "adCode": "652901",
+                    "cityCode": "0997"
+                },
+                {
+                    "name": "阿拉尔市",
+                    "adCode": "659002",
+                    "cityCode": "1997"
+                },
+                {
+                    "name": "阿拉山口市",
+                    "adCode": "652702",
+                    "cityCode": "0909"
+                },
+                {
+                    "name": "阿勒泰市",
+                    "adCode": "654301",
+                    "cityCode": "0906"
+                },
+                {
+                    "name": "阿图什市",
+                    "adCode": "653001",
+                    "cityCode": "0908"
+                },
+                {
+                    "name": "安达市",
+                    "adCode": "231281",
+                    "cityCode": "0455"
+                },
+                {
+                    "name": "安国市",
+                    "adCode": "130683",
+                    "cityCode": "0312"
+                },
+                {
+                    "name": "安康市",
+                    "adCode": "610900",
+                    "cityCode": "0915"
+                },
+                {
+                    "name": "安陆市",
+                    "adCode": "420982",
+                    "cityCode": "0712"
+                },
+                {
+                    "name": "安宁市",
+                    "adCode": "530181",
+                    "cityCode": "0871"
+                },
+                {
+                    "name": "安庆市",
+                    "adCode": "340800",
+                    "cityCode": "0556"
+                },
+                {
+                    "name": "安丘市",
+                    "adCode": "370784",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "安顺市",
+                    "adCode": "520400",
+                    "cityCode": "0853"
+                },
+                {
+                    "name": "安阳市",
+                    "adCode": "410500",
+                    "cityCode": "0372"
+                },
+                {
+                    "name": "鞍山市",
+                    "adCode": "210300",
+                    "cityCode": "0412"
+                }
+            ]
+        },
+        {
+            "letter": "B",
+            "list": [
+                {
+                    "name": "巴彦淖尔市",
+                    "adCode": "150800",
+                    "cityCode": "0478"
+                },
+                {
+                    "name": "巴中市",
+                    "adCode": "511900",
+                    "cityCode": "0827"
+                },
+                {
+                    "name": "霸州市",
+                    "adCode": "131081",
+                    "cityCode": "0316"
+                },
+                {
+                    "name": "白城市",
+                    "adCode": "220800",
+                    "cityCode": "0436"
+                },
+                {
+                    "name": "白山市",
+                    "adCode": "220600",
+                    "cityCode": "0439"
+                },
+                {
+                    "name": "白银市",
+                    "adCode": "620400",
+                    "cityCode": "0943"
+                },
+                {
+                    "name": "百色市",
+                    "adCode": "451000",
+                    "cityCode": "0776"
+                },
+                {
+                    "name": "蚌埠市",
+                    "adCode": "340300",
+                    "cityCode": "0552"
+                },
+                {
+                    "name": "包头市",
+                    "adCode": "150200",
+                    "cityCode": "0472"
+                },
+                {
+                    "name": "宝鸡市",
+                    "adCode": "610300",
+                    "cityCode": "0917"
+                },
+                {
+                    "name": "保定市",
+                    "adCode": "130600",
+                    "cityCode": "0312"
+                },
+                {
+                    "name": "保山市",
+                    "adCode": "530500",
+                    "cityCode": "0875"
+                },
+                {
+                    "name": "北安市",
+                    "adCode": "231181",
+                    "cityCode": "0456"
+                },
+                {
+                    "name": "北海市",
+                    "adCode": "450500",
+                    "cityCode": "0779"
+                },
+                {
+                    "name": "北京市",
+                    "adCode": "110000",
+                    "cityCode": "010",
+                    "type": "hot"
+                },
+                {
+                    "name": "北流市",
+                    "adCode": "450981",
+                    "cityCode": "0775"
+                },
+                {
+                    "name": "北票市",
+                    "adCode": "211381",
+                    "cityCode": "0421"
+                },
+                {
+                    "name": "北屯市",
+                    "adCode": "659005",
+                    "cityCode": "1906"
+                },
+                {
+                    "name": "北镇市",
+                    "adCode": "210782",
+                    "cityCode": "0416"
+                },
+                {
+                    "name": "本溪市",
+                    "adCode": "210500",
+                    "cityCode": "0414"
+                },
+                {
+                    "name": "毕节市",
+                    "adCode": "520500",
+                    "cityCode": "0857"
+                },
+                {
+                    "name": "滨州市",
+                    "adCode": "371600",
+                    "cityCode": "0543"
+                },
+                {
+                    "name": "泊头市",
+                    "adCode": "130981",
+                    "cityCode": "0317"
+                },
+                {
+                    "name": "亳州市",
+                    "adCode": "341600",
+                    "cityCode": "0558"
+                },
+                {
+                    "name": "博乐市",
+                    "adCode": "652701",
+                    "cityCode": "0909"
+                }
+            ]
+        },
+        {
+            "letter": "C",
+            "list": [
+                {
+                    "name": "沧州市",
+                    "adCode": "130900",
+                    "cityCode": "0317"
+                },
+                {
+                    "name": "岑溪市",
+                    "adCode": "450481",
+                    "cityCode": "0774"
+                },
+                {
+                    "name": "昌都市",
+                    "adCode": "540300",
+                    "cityCode": "0895"
+                },
+                {
+                    "name": "昌吉市",
+                    "adCode": "652301",
+                    "cityCode": "0994"
+                },
+                {
+                    "name": "昌邑市",
+                    "adCode": "370786",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "常德市",
+                    "adCode": "430700",
+                    "cityCode": "0736"
+                },
+                {
+                    "name": "常宁市",
+                    "adCode": "430482",
+                    "cityCode": "0734"
+                },
+                {
+                    "name": "常熟市",
+                    "adCode": "320581",
+                    "cityCode": "0512"
+                },
+                {
+                    "name": "常州市",
+                    "adCode": "320400",
+                    "cityCode": "0519"
+                },
+                {
+                    "name": "巢湖市",
+                    "adCode": "340181",
+                    "cityCode": "0551"
+                },
+                {
+                    "name": "朝阳市",
+                    "adCode": "211300",
+                    "cityCode": "0421"
+                },
+                {
+                    "name": "潮州市",
+                    "adCode": "445100",
+                    "cityCode": "0768"
+                },
+                {
+                    "name": "郴州市",
+                    "adCode": "431000",
+                    "cityCode": "0735"
+                },
+                {
+                    "name": "成都市",
+                    "adCode": "510100",
+                    "cityCode": "028",
+                    "type": "hot"
+                },
+                {
+                    "name": "承德市",
+                    "adCode": "130800",
+                    "cityCode": "0314"
+                },
+                {
+                    "name": "池州市",
+                    "adCode": "341700",
+                    "cityCode": "0566"
+                },
+                {
+                    "name": "赤壁市",
+                    "adCode": "421281",
+                    "cityCode": "0715"
+                },
+                {
+                    "name": "赤峰市",
+                    "adCode": "150400",
+                    "cityCode": "0476"
+                },
+                {
+                    "name": "赤水市",
+                    "adCode": "520381",
+                    "cityCode": "0852"
+                },
+                {
+                    "name": "崇州市",
+                    "adCode": "510184",
+                    "cityCode": "028"
+                },
+                {
+                    "name": "崇左市",
+                    "adCode": "451400",
+                    "cityCode": "1771"
+                },
+                {
+                    "name": "滁州市",
+                    "adCode": "341100",
+                    "cityCode": "0550"
+                },
+                {
+                    "name": "楚雄市",
+                    "adCode": "532301",
+                    "cityCode": "0878"
+                },
+                {
+                    "name": "慈溪市",
+                    "adCode": "330282",
+                    "cityCode": "0574"
+                },
+                {
+                    "name": "长春市",
+                    "adCode": "220100",
+                    "cityCode": "0431",
+                    "type": "hot"
+                },
+                {
+                    "name": "长葛市",
+                    "adCode": "411082",
+                    "cityCode": "0374"
+                },
+                {
+                    "name": "长乐市",
+                    "adCode": "350182",
+                    "cityCode": "0591"
+                },
+                {
+                    "name": "长沙市",
+                    "adCode": "430100",
+                    "cityCode": "0731",
+                    "type": "hot"
+                },
+                {
+                    "name": "长治市",
+                    "adCode": "140400",
+                    "cityCode": "0355"
+                },
+                {
+                    "name": "重庆市",
+                    "adCode": "500000",
+                    "cityCode": "023",
+                    "type": "hot"
+                }
+            ]
+        },
+        {
+            "letter": "D",
+            "list": [
+                {
+                    "name": "达州市",
+                    "adCode": "511700",
+                    "cityCode": "0818"
+                },
+                {
+                    "name": "大安市",
+                    "adCode": "220882",
+                    "cityCode": "0436"
+                },
+                {
+                    "name": "大理市",
+                    "adCode": "532901",
+                    "cityCode": "0872"
+                },
+                {
+                    "name": "大连市",
+                    "adCode": "210200",
+                    "cityCode": "0411",
+                    "type": "hot"
+                },
+                {
+                    "name": "大庆市",
+                    "adCode": "230600",
+                    "cityCode": "0459"
+                },
+                {
+                    "name": "大石桥市",
+                    "adCode": "210882",
+                    "cityCode": "0417"
+                },
+                {
+                    "name": "大同市",
+                    "adCode": "140200",
+                    "cityCode": "0352"
+                },
+                {
+                    "name": "大冶市",
+                    "adCode": "420281",
+                    "cityCode": "0714"
+                },
+                {
+                    "name": "丹东市",
+                    "adCode": "210600",
+                    "cityCode": "0415"
+                },
+                {
+                    "name": "丹江口市",
+                    "adCode": "420381",
+                    "cityCode": "0719"
+                },
+                {
+                    "name": "丹阳市",
+                    "adCode": "321181",
+                    "cityCode": "0511"
+                },
+                {
+                    "name": "儋州市",
+                    "adCode": "460400",
+                    "cityCode": "0805"
+                },
+                {
+                    "name": "当阳市",
+                    "adCode": "420582",
+                    "cityCode": "0717"
+                },
+                {
+                    "name": "德惠市",
+                    "adCode": "220183",
+                    "cityCode": "0431"
+                },
+                {
+                    "name": "德令哈市",
+                    "adCode": "632802",
+                    "cityCode": "0977"
+                },
+                {
+                    "name": "德兴市",
+                    "adCode": "361181",
+                    "cityCode": "0793"
+                },
+                {
+                    "name": "德阳市",
+                    "adCode": "510600",
+                    "cityCode": "0838"
+                },
+                {
+                    "name": "德州市",
+                    "adCode": "371400",
+                    "cityCode": "0534"
+                },
+                {
+                    "name": "灯塔市",
+                    "adCode": "211081",
+                    "cityCode": "0419"
+                },
+                {
+                    "name": "登封市",
+                    "adCode": "410185",
+                    "cityCode": "0371"
+                },
+                {
+                    "name": "邓州市",
+                    "adCode": "411381",
+                    "cityCode": "0377"
+                },
+                {
+                    "name": "定西市",
+                    "adCode": "621100",
+                    "cityCode": "0932"
+                },
+                {
+                    "name": "定州市",
+                    "adCode": "130682",
+                    "cityCode": "0312"
+                },
+                {
+                    "name": "东方市",
+                    "adCode": "469007",
+                    "cityCode": "0807"
+                },
+                {
+                    "name": "东港市",
+                    "adCode": "210681",
+                    "cityCode": "0415"
+                },
+                {
+                    "name": "东莞市",
+                    "adCode": "441900",
+                    "cityCode": "0769"
+                },
+                {
+                    "name": "东宁市",
+                    "adCode": "231086",
+                    "cityCode": "0453"
+                },
+                {
+                    "name": "东台市",
+                    "adCode": "320981",
+                    "cityCode": "0515"
+                },
+                {
+                    "name": "东兴市",
+                    "adCode": "450681",
+                    "cityCode": "0770"
+                },
+                {
+                    "name": "东阳市",
+                    "adCode": "330783",
+                    "cityCode": "0579"
+                },
+                {
+                    "name": "东营市",
+                    "adCode": "370500",
+                    "cityCode": "0546"
+                },
+                {
+                    "name": "都江堰市",
+                    "adCode": "510181",
+                    "cityCode": "028"
+                },
+                {
+                    "name": "都匀市",
+                    "adCode": "522701",
+                    "cityCode": "0854"
+                },
+                {
+                    "name": "敦化市",
+                    "adCode": "222403",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "敦煌市",
+                    "adCode": "620982",
+                    "cityCode": "0937"
+                }
+            ]
+        },
+        {
+            "letter": "E",
+            "list": [
+                {
+                    "name": "峨眉山市",
+                    "adCode": "511181",
+                    "cityCode": "0833"
+                },
+                {
+                    "name": "额尔古纳市",
+                    "adCode": "150784",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "鄂尔多斯市",
+                    "adCode": "150600",
+                    "cityCode": "0477"
+                },
+                {
+                    "name": "鄂州市",
+                    "adCode": "420700",
+                    "cityCode": "0711"
+                },
+                {
+                    "name": "恩平市",
+                    "adCode": "440785",
+                    "cityCode": "0750"
+                },
+                {
+                    "name": "恩施市",
+                    "adCode": "422801",
+                    "cityCode": "0718"
+                },
+                {
+                    "name": "二连浩特市",
+                    "adCode": "152501",
+                    "cityCode": "0479"
+                }
+            ]
+        },
+        {
+            "letter": "F",
+            "list": [
+                {
+                    "name": "防城港市",
+                    "adCode": "450600",
+                    "cityCode": "0770"
+                },
+                {
+                    "name": "肥城市",
+                    "adCode": "370983",
+                    "cityCode": "0538"
+                },
+                {
+                    "name": "汾阳市",
+                    "adCode": "141182",
+                    "cityCode": "0358"
+                },
+                {
+                    "name": "丰城市",
+                    "adCode": "360981",
+                    "cityCode": "0795"
+                },
+                {
+                    "name": "丰镇市",
+                    "adCode": "150981",
+                    "cityCode": "0474"
+                },
+                {
+                    "name": "凤城市",
+                    "adCode": "210682",
+                    "cityCode": "0415"
+                },
+                {
+                    "name": "佛山市",
+                    "adCode": "440600",
+                    "cityCode": "0757",
+                    "type": "hot"
+                },
+                {
+                    "name": "扶余市",
+                    "adCode": "220781",
+                    "cityCode": "0438"
+                },
+                {
+                    "name": "福安市",
+                    "adCode": "350981",
+                    "cityCode": "0593"
+                },
+                {
+                    "name": "福鼎市",
+                    "adCode": "350982",
+                    "cityCode": "0593"
+                },
+                {
+                    "name": "福清市",
+                    "adCode": "350181",
+                    "cityCode": "0591"
+                },
+                {
+                    "name": "福泉市",
+                    "adCode": "522702",
+                    "cityCode": "0854"
+                },
+                {
+                    "name": "福州市",
+                    "adCode": "350100",
+                    "cityCode": "0591"
+                },
+                {
+                    "name": "抚顺市",
+                    "adCode": "210400",
+                    "cityCode": "0413"
+                },
+                {
+                    "name": "抚远市",
+                    "adCode": "230883",
+                    "cityCode": "0454"
+                },
+                {
+                    "name": "抚州市",
+                    "adCode": "361000",
+                    "cityCode": "0794"
+                },
+                {
+                    "name": "阜康市",
+                    "adCode": "652302",
+                    "cityCode": "0994"
+                },
+                {
+                    "name": "阜新市",
+                    "adCode": "210900",
+                    "cityCode": "0418"
+                },
+                {
+                    "name": "阜阳市",
+                    "adCode": "341200",
+                    "cityCode": "1558"
+                },
+                {
+                    "name": "富锦市",
+                    "adCode": "230882",
+                    "cityCode": "0454"
+                }
+            ]
+        },
+        {
+            "letter": "G",
+            "list": [
+                {
+                    "name": "盖州市",
+                    "adCode": "210881",
+                    "cityCode": "0417"
+                },
+                {
+                    "name": "赣州市",
+                    "adCode": "360700",
+                    "cityCode": "0797"
+                },
+                {
+                    "name": "高安市",
+                    "adCode": "360983",
+                    "cityCode": "0795"
+                },
+                {
+                    "name": "高碑店市",
+                    "adCode": "130684",
+                    "cityCode": "0312"
+                },
+                {
+                    "name": "高密市",
+                    "adCode": "370785",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "高平市",
+                    "adCode": "140581",
+                    "cityCode": "0356"
+                },
+                {
+                    "name": "高邮市",
+                    "adCode": "321084",
+                    "cityCode": "0514"
+                },
+                {
+                    "name": "高州市",
+                    "adCode": "440981",
+                    "cityCode": "0668"
+                },
+                {
+                    "name": "格尔木市",
+                    "adCode": "632801",
+                    "cityCode": "0977"
+                },
+                {
+                    "name": "个旧市",
+                    "adCode": "532501",
+                    "cityCode": "0873"
+                },
+                {
+                    "name": "根河市",
+                    "adCode": "150785",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "公主岭市",
+                    "adCode": "220381",
+                    "cityCode": "0434"
+                },
+                {
+                    "name": "巩义市",
+                    "adCode": "410181",
+                    "cityCode": "0371"
+                },
+                {
+                    "name": "共青城市",
+                    "adCode": "360482",
+                    "cityCode": "0792"
+                },
+                {
+                    "name": "古交市",
+                    "adCode": "140181",
+                    "cityCode": "0351"
+                },
+                {
+                    "name": "固原市",
+                    "adCode": "640400",
+                    "cityCode": "0954"
+                },
+                {
+                    "name": "广安市",
+                    "adCode": "511600",
+                    "cityCode": "0826"
+                },
+                {
+                    "name": "广汉市",
+                    "adCode": "510681",
+                    "cityCode": "0838"
+                },
+                {
+                    "name": "广水市",
+                    "adCode": "421381",
+                    "cityCode": "0722"
+                },
+                {
+                    "name": "广元市",
+                    "adCode": "510800",
+                    "cityCode": "0839"
+                },
+                {
+                    "name": "广州市",
+                    "adCode": "440100",
+                    "cityCode": "020",
+                    "type": "hot"
+                },
+                {
+                    "name": "贵港市",
+                    "adCode": "450800",
+                    "cityCode": "1755"
+                },
+                {
+                    "name": "贵溪市",
+                    "adCode": "360681",
+                    "cityCode": "0701"
+                },
+                {
+                    "name": "贵阳市",
+                    "adCode": "520100",
+                    "cityCode": "0851",
+                    "type": "hot"
+                },
+                {
+                    "name": "桂林市",
+                    "adCode": "450300",
+                    "cityCode": "0773"
+                },
+                {
+                    "name": "桂平市",
+                    "adCode": "450881",
+                    "cityCode": "1755"
+                }
+            ]
+        },
+        {
+            "letter": "H",
+            "list": [
+                {
+                    "name": "哈尔滨市",
+                    "adCode": "230100",
+                    "cityCode": "0451"
+                },
+                {
+                    "name": "哈密市",
+                    "adCode": "650500",
+                    "cityCode": "0902"
+                },
+                {
+                    "name": "海城市",
+                    "adCode": "210381",
+                    "cityCode": "0412"
+                },
+                {
+                    "name": "海东市",
+                    "adCode": "630200",
+                    "cityCode": "0972"
+                },
+                {
+                    "name": "海口市",
+                    "adCode": "460100",
+                    "cityCode": "0898",
+                    "type": "hot"
+                },
+                {
+                    "name": "海林市",
+                    "adCode": "231083",
+                    "cityCode": "0453"
+                },
+                {
+                    "name": "海伦市",
+                    "adCode": "231283",
+                    "cityCode": "0455"
+                },
+                {
+                    "name": "海门市",
+                    "adCode": "320684",
+                    "cityCode": "0513"
+                },
+                {
+                    "name": "海宁市",
+                    "adCode": "330481",
+                    "cityCode": "0573"
+                },
+                {
+                    "name": "海阳市",
+                    "adCode": "370687",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "邯郸市",
+                    "adCode": "130400",
+                    "cityCode": "0310"
+                },
+                {
+                    "name": "韩城市",
+                    "adCode": "610581",
+                    "cityCode": "0913"
+                },
+                {
+                    "name": "汉川市",
+                    "adCode": "420984",
+                    "cityCode": "0712"
+                },
+                {
+                    "name": "汉中市",
+                    "adCode": "610700",
+                    "cityCode": "0916"
+                },
+                {
+                    "name": "杭州市",
+                    "adCode": "330100",
+                    "cityCode": "0571",
+                    "type": "hot"
+                },
+                {
+                    "name": "合肥市",
+                    "adCode": "340100",
+                    "cityCode": "0551",
+                    "type": "hot"
+                },
+                {
+                    "name": "合山市",
+                    "adCode": "451381",
+                    "cityCode": "1772"
+                },
+                {
+                    "name": "合作市",
+                    "adCode": "623001",
+                    "cityCode": "0941"
+                },
+                {
+                    "name": "和龙市",
+                    "adCode": "222406",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "和田市",
+                    "adCode": "653201",
+                    "cityCode": "0903"
+                },
+                {
+                    "name": "河池市",
+                    "adCode": "451200",
+                    "cityCode": "0778"
+                },
+                {
+                    "name": "河间市",
+                    "adCode": "130984",
+                    "cityCode": "0317"
+                },
+                {
+                    "name": "河津市",
+                    "adCode": "140882",
+                    "cityCode": "0359"
+                },
+                {
+                    "name": "河源市",
+                    "adCode": "441600",
+                    "cityCode": "0762"
+                },
+                {
+                    "name": "菏泽市",
+                    "adCode": "371700",
+                    "cityCode": "0530"
+                },
+                {
+                    "name": "贺州市",
+                    "adCode": "451100",
+                    "cityCode": "1774"
+                },
+                {
+                    "name": "鹤壁市",
+                    "adCode": "410600",
+                    "cityCode": "0392"
+                },
+                {
+                    "name": "鹤岗市",
+                    "adCode": "230400",
+                    "cityCode": "0468"
+                },
+                {
+                    "name": "鹤山市",
+                    "adCode": "440784",
+                    "cityCode": "0750"
+                },
+                {
+                    "name": "黑河市",
+                    "adCode": "231100",
+                    "cityCode": "0456"
+                },
+                {
+                    "name": "衡水市",
+                    "adCode": "131100",
+                    "cityCode": "0318"
+                },
+                {
+                    "name": "衡阳市",
+                    "adCode": "430400",
+                    "cityCode": "0734"
+                },
+                {
+                    "name": "洪湖市",
+                    "adCode": "421083",
+                    "cityCode": "0716"
+                },
+                {
+                    "name": "洪江市",
+                    "adCode": "431281",
+                    "cityCode": "0745"
+                },
+                {
+                    "name": "侯马市",
+                    "adCode": "141081",
+                    "cityCode": "0357"
+                },
+                {
+                    "name": "呼和浩特市",
+                    "adCode": "150100",
+                    "cityCode": "0471"
+                },
+                {
+                    "name": "呼伦贝尔市",
+                    "adCode": "150700",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "葫芦岛市",
+                    "adCode": "211400",
+                    "cityCode": "0429"
+                },
+                {
+                    "name": "湖州市",
+                    "adCode": "330500",
+                    "cityCode": "0572"
+                },
+                {
+                    "name": "虎林市",
+                    "adCode": "230381",
+                    "cityCode": "0467"
+                },
+                {
+                    "name": "华阴市",
+                    "adCode": "610582",
+                    "cityCode": "0913"
+                },
+                {
+                    "name": "华蓥市",
+                    "adCode": "511681",
+                    "cityCode": "0826"
+                },
+                {
+                    "name": "化州市",
+                    "adCode": "440982",
+                    "cityCode": "0668"
+                },
+                {
+                    "name": "桦甸市",
+                    "adCode": "220282",
+                    "cityCode": "0432"
+                },
+                {
+                    "name": "怀化市",
+                    "adCode": "431200",
+                    "cityCode": "0745"
+                },
+                {
+                    "name": "淮安市",
+                    "adCode": "320800",
+                    "cityCode": "0517"
+                },
+                {
+                    "name": "淮北市",
+                    "adCode": "340600",
+                    "cityCode": "0561"
+                },
+                {
+                    "name": "淮南市",
+                    "adCode": "340400",
+                    "cityCode": "0554"
+                },
+                {
+                    "name": "黄冈市",
+                    "adCode": "421100",
+                    "cityCode": "0713"
+                },
+                {
+                    "name": "黄骅市",
+                    "adCode": "130983",
+                    "cityCode": "0317"
+                },
+                {
+                    "name": "黄山市",
+                    "adCode": "341000",
+                    "cityCode": "0559"
+                },
+                {
+                    "name": "黄石市",
+                    "adCode": "420200",
+                    "cityCode": "0714"
+                },
+                {
+                    "name": "珲春市",
+                    "adCode": "222404",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "辉县市",
+                    "adCode": "410782",
+                    "cityCode": "0373"
+                },
+                {
+                    "name": "惠州市",
+                    "adCode": "441300",
+                    "cityCode": "0752"
+                },
+                {
+                    "name": "霍尔果斯市",
+                    "adCode": "654004",
+                    "cityCode": "0999"
+                },
+                {
+                    "name": "霍林郭勒市",
+                    "adCode": "150581",
+                    "cityCode": "0475"
+                },
+                {
+                    "name": "霍州市",
+                    "adCode": "141082",
+                    "cityCode": "0357"
+                }
+            ]
+        },
+        {
+            "letter": "J",
+            "list": [
+                {
+                    "name": "鸡西市",
+                    "adCode": "230300",
+                    "cityCode": "0467"
+                },
+                {
+                    "name": "吉安市",
+                    "adCode": "360800",
+                    "cityCode": "0796"
+                },
+                {
+                    "name": "吉林市",
+                    "adCode": "220200",
+                    "cityCode": "0432"
+                },
+                {
+                    "name": "吉首市",
+                    "adCode": "433101",
+                    "cityCode": "0743"
+                },
+                {
+                    "name": "即墨市",
+                    "adCode": "370282",
+                    "cityCode": "0532"
+                },
+                {
+                    "name": "集安市",
+                    "adCode": "220582",
+                    "cityCode": "0435"
+                },
+                {
+                    "name": "济南市",
+                    "adCode": "370100",
+                    "cityCode": "0531"
+                },
+                {
+                    "name": "济宁市",
+                    "adCode": "370800",
+                    "cityCode": "0537"
+                },
+                {
+                    "name": "济源市",
+                    "adCode": "419001",
+                    "cityCode": "1391"
+                },
+                {
+                    "name": "佳木斯市",
+                    "adCode": "230800",
+                    "cityCode": "0454"
+                },
+                {
+                    "name": "嘉兴市",
+                    "adCode": "330400",
+                    "cityCode": "0573"
+                },
+                {
+                    "name": "嘉峪关市",
+                    "adCode": "620200",
+                    "cityCode": "1937"
+                },
+                {
+                    "name": "简阳市",
+                    "adCode": "510180",
+                    "cityCode": "028"
+                },
+                {
+                    "name": "建德市",
+                    "adCode": "330182",
+                    "cityCode": "0571"
+                },
+                {
+                    "name": "建瓯市",
+                    "adCode": "350783",
+                    "cityCode": "0599"
+                },
+                {
+                    "name": "江门市",
+                    "adCode": "440700",
+                    "cityCode": "0750"
+                },
+                {
+                    "name": "江山市",
+                    "adCode": "330881",
+                    "cityCode": "0570"
+                },
+                {
+                    "name": "江阴市",
+                    "adCode": "320281",
+                    "cityCode": "0510"
+                },
+                {
+                    "name": "江油市",
+                    "adCode": "510781",
+                    "cityCode": "0816"
+                },
+                {
+                    "name": "胶州市",
+                    "adCode": "370281",
+                    "cityCode": "0532"
+                },
+                {
+                    "name": "蛟河市",
+                    "adCode": "220281",
+                    "cityCode": "0432"
+                },
+                {
+                    "name": "焦作市",
+                    "adCode": "410800",
+                    "cityCode": "0391"
+                },
+                {
+                    "name": "揭阳市",
+                    "adCode": "445200",
+                    "cityCode": "0663"
+                },
+                {
+                    "name": "介休市",
+                    "adCode": "140781",
+                    "cityCode": "0354"
+                },
+                {
+                    "name": "界首市",
+                    "adCode": "341282",
+                    "cityCode": "1558"
+                },
+                {
+                    "name": "金昌市",
+                    "adCode": "620300",
+                    "cityCode": "0935"
+                },
+                {
+                    "name": "金华市",
+                    "adCode": "330700",
+                    "cityCode": "0579"
+                },
+                {
+                    "name": "津市市",
+                    "adCode": "430781",
+                    "cityCode": "0736"
+                },
+                {
+                    "name": "锦州市",
+                    "adCode": "210700",
+                    "cityCode": "0416"
+                },
+                {
+                    "name": "晋城市",
+                    "adCode": "140500",
+                    "cityCode": "0356"
+                },
+                {
+                    "name": "晋江市",
+                    "adCode": "350582",
+                    "cityCode": "0595"
+                },
+                {
+                    "name": "晋中市",
+                    "adCode": "140700",
+                    "cityCode": "0354"
+                },
+                {
+                    "name": "晋州市",
+                    "adCode": "130183",
+                    "cityCode": "0311"
+                },
+                {
+                    "name": "荆门市",
+                    "adCode": "420800",
+                    "cityCode": "0724"
+                },
+                {
+                    "name": "荆州市",
+                    "adCode": "421000",
+                    "cityCode": "0716"
+                },
+                {
+                    "name": "井冈山市",
+                    "adCode": "360881",
+                    "cityCode": "0796"
+                },
+                {
+                    "name": "景德镇市",
+                    "adCode": "360200",
+                    "cityCode": "0798"
+                },
+                {
+                    "name": "景洪市",
+                    "adCode": "532801",
+                    "cityCode": "0691"
+                },
+                {
+                    "name": "靖江市",
+                    "adCode": "321282",
+                    "cityCode": "0523"
+                },
+                {
+                    "name": "靖西市",
+                    "adCode": "451081",
+                    "cityCode": "0776"
+                },
+                {
+                    "name": "九江市",
+                    "adCode": "360400",
+                    "cityCode": "0792"
+                },
+                {
+                    "name": "酒泉市",
+                    "adCode": "620900",
+                    "cityCode": "0937"
+                },
+                {
+                    "name": "句容市",
+                    "adCode": "321183",
+                    "cityCode": "0511"
+                }
+            ]
+        },
+        {
+            "letter": "K",
+            "list": [
+                {
+                    "name": "喀什市",
+                    "adCode": "653101",
+                    "cityCode": "0998"
+                },
+                {
+                    "name": "开封市",
+                    "adCode": "410200",
+                    "cityCode": "0378"
+                },
+                {
+                    "name": "开平市",
+                    "adCode": "440783",
+                    "cityCode": "0750"
+                },
+                {
+                    "name": "开原市",
+                    "adCode": "211282",
+                    "cityCode": "0410"
+                },
+                {
+                    "name": "开远市",
+                    "adCode": "532502",
+                    "cityCode": "0873"
+                },
+                {
+                    "name": "凯里市",
+                    "adCode": "522601",
+                    "cityCode": "0855"
+                },
+                {
+                    "name": "康定市",
+                    "adCode": "513301",
+                    "cityCode": "0836"
+                },
+                {
+                    "name": "可克达拉市",
+                    "adCode": "659008",
+                    "cityCode": "1999"
+                },
+                {
+                    "name": "克拉玛依市",
+                    "adCode": "650200",
+                    "cityCode": "0990"
+                },
+                {
+                    "name": "库尔勒市",
+                    "adCode": "652801",
+                    "cityCode": "0996"
+                },
+                {
+                    "name": "奎屯市",
+                    "adCode": "654003",
+                    "cityCode": "0999"
+                },
+                {
+                    "name": "昆明市",
+                    "adCode": "530100",
+                    "cityCode": "0871",
+                    "type": "hot"
+                },
+                {
+                    "name": "昆山市",
+                    "adCode": "320583",
+                    "cityCode": "0512"
+                },
+                {
+                    "name": "昆玉市",
+                    "adCode": "659009",
+                    "cityCode": "1903"
+                }
+            ]
+        },
+        {
+            "letter": "L",
+            "list": [
+                {
+                    "name": "拉萨市",
+                    "adCode": "540100",
+                    "cityCode": "0891"
+                },
+                {
+                    "name": "来宾市",
+                    "adCode": "451300",
+                    "cityCode": "1772"
+                },
+                {
+                    "name": "莱芜市",
+                    "adCode": "371200",
+                    "cityCode": "0634"
+                },
+                {
+                    "name": "莱西市",
+                    "adCode": "370285",
+                    "cityCode": "0532"
+                },
+                {
+                    "name": "莱阳市",
+                    "adCode": "370682",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "莱州市",
+                    "adCode": "370683",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "兰溪市",
+                    "adCode": "330781",
+                    "cityCode": "0579"
+                },
+                {
+                    "name": "兰州市",
+                    "adCode": "620100",
+                    "cityCode": "0931"
+                },
+                {
+                    "name": "阆中市",
+                    "adCode": "511381",
+                    "cityCode": "0817"
+                },
+                {
+                    "name": "廊坊市",
+                    "adCode": "131000",
+                    "cityCode": "0316"
+                },
+                {
+                    "name": "老河口市",
+                    "adCode": "420682",
+                    "cityCode": "0710"
+                },
+                {
+                    "name": "乐昌市",
+                    "adCode": "440281",
+                    "cityCode": "0751"
+                },
+                {
+                    "name": "乐陵市",
+                    "adCode": "371481",
+                    "cityCode": "0534"
+                },
+                {
+                    "name": "乐平市",
+                    "adCode": "360281",
+                    "cityCode": "0798"
+                },
+                {
+                    "name": "乐清市",
+                    "adCode": "330382",
+                    "cityCode": "0577"
+                },
+                {
+                    "name": "乐山市",
+                    "adCode": "511100",
+                    "cityCode": "0833"
+                },
+                {
+                    "name": "雷州市",
+                    "adCode": "440882",
+                    "cityCode": "0759"
+                },
+                {
+                    "name": "耒阳市",
+                    "adCode": "430481",
+                    "cityCode": "0734"
+                },
+                {
+                    "name": "冷水江市",
+                    "adCode": "431381",
+                    "cityCode": "0738"
+                },
+                {
+                    "name": "醴陵市",
+                    "adCode": "430281",
+                    "cityCode": "0733"
+                },
+                {
+                    "name": "丽江市",
+                    "adCode": "530700",
+                    "cityCode": "0888"
+                },
+                {
+                    "name": "丽水市",
+                    "adCode": "331100",
+                    "cityCode": "0578"
+                },
+                {
+                    "name": "利川市",
+                    "adCode": "422802",
+                    "cityCode": "0718"
+                },
+                {
+                    "name": "溧阳市",
+                    "adCode": "320481",
+                    "cityCode": "0519"
+                },
+                {
+                    "name": "连云港市",
+                    "adCode": "320700",
+                    "cityCode": "0518"
+                },
+                {
+                    "name": "连州市",
+                    "adCode": "441882",
+                    "cityCode": "0763"
+                },
+                {
+                    "name": "涟源市",
+                    "adCode": "431382",
+                    "cityCode": "0738"
+                },
+                {
+                    "name": "廉江市",
+                    "adCode": "440881",
+                    "cityCode": "0759"
+                },
+                {
+                    "name": "辽阳市",
+                    "adCode": "211000",
+                    "cityCode": "0419"
+                },
+                {
+                    "name": "辽源市",
+                    "adCode": "220400",
+                    "cityCode": "0437"
+                },
+                {
+                    "name": "聊城市",
+                    "adCode": "371500",
+                    "cityCode": "0635"
+                },
+                {
+                    "name": "林芝市",
+                    "adCode": "540400",
+                    "cityCode": "0894"
+                },
+                {
+                    "name": "林州市",
+                    "adCode": "410581",
+                    "cityCode": "0372"
+                },
+                {
+                    "name": "临安市",
+                    "adCode": "330185",
+                    "cityCode": "0571"
+                },
+                {
+                    "name": "临沧市",
+                    "adCode": "530900",
+                    "cityCode": "0883"
+                },
+                {
+                    "name": "临汾市",
+                    "adCode": "141000",
+                    "cityCode": "0357"
+                },
+                {
+                    "name": "临海市",
+                    "adCode": "331082",
+                    "cityCode": "0576"
+                },
+                {
+                    "name": "临江市",
+                    "adCode": "220681",
+                    "cityCode": "0439"
+                },
+                {
+                    "name": "临清市",
+                    "adCode": "371581",
+                    "cityCode": "0635"
+                },
+                {
+                    "name": "临夏市",
+                    "adCode": "622901",
+                    "cityCode": "0930"
+                },
+                {
+                    "name": "临湘市",
+                    "adCode": "430682",
+                    "cityCode": "0730"
+                },
+                {
+                    "name": "临沂市",
+                    "adCode": "371300",
+                    "cityCode": "0539"
+                },
+                {
+                    "name": "灵宝市",
+                    "adCode": "411282",
+                    "cityCode": "0398"
+                },
+                {
+                    "name": "灵武市",
+                    "adCode": "640181",
+                    "cityCode": "0951"
+                },
+                {
+                    "name": "凌海市",
+                    "adCode": "210781",
+                    "cityCode": "0416"
+                },
+                {
+                    "name": "凌源市",
+                    "adCode": "211382",
+                    "cityCode": "0421"
+                },
+                {
+                    "name": "浏阳市",
+                    "adCode": "430181",
+                    "cityCode": "0731"
+                },
+                {
+                    "name": "柳州市",
+                    "adCode": "450200",
+                    "cityCode": "0772"
+                },
+                {
+                    "name": "六安市",
+                    "adCode": "341500",
+                    "cityCode": "0564"
+                },
+                {
+                    "name": "六盘水市",
+                    "adCode": "520200",
+                    "cityCode": "0858"
+                },
+                {
+                    "name": "龙海市",
+                    "adCode": "350681",
+                    "cityCode": "0596"
+                },
+                {
+                    "name": "龙井市",
+                    "adCode": "222405",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "龙口市",
+                    "adCode": "370681",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "龙泉市",
+                    "adCode": "331181",
+                    "cityCode": "0578"
+                },
+                {
+                    "name": "龙岩市",
+                    "adCode": "350800",
+                    "cityCode": "0597"
+                },
+                {
+                    "name": "陇南市",
+                    "adCode": "621200",
+                    "cityCode": "2935"
+                },
+                {
+                    "name": "娄底市",
+                    "adCode": "431300",
+                    "cityCode": "0738"
+                },
+                {
+                    "name": "庐山市",
+                    "adCode": "360427",
+                    "cityCode": "0792"
+                },
+                {
+                    "name": "泸水市",
+                    "adCode": "533301",
+                    "cityCode": "0886"
+                },
+                {
+                    "name": "泸州市",
+                    "adCode": "510500",
+                    "cityCode": "0830"
+                },
+                {
+                    "name": "陆丰市",
+                    "adCode": "441581",
+                    "cityCode": "0660"
+                },
+                {
+                    "name": "潞城市",
+                    "adCode": "140481",
+                    "cityCode": "0355"
+                },
+                {
+                    "name": "罗定市",
+                    "adCode": "445381",
+                    "cityCode": "0766"
+                },
+                {
+                    "name": "洛阳市",
+                    "adCode": "410300",
+                    "cityCode": "0379"
+                },
+                {
+                    "name": "漯河市",
+                    "adCode": "411100",
+                    "cityCode": "0395"
+                },
+                {
+                    "name": "吕梁市",
+                    "adCode": "141100",
+                    "cityCode": "0358"
+                }
+            ]
+        },
+        {
+            "letter": "M",
+            "list": [
+                {
+                    "name": "麻城市",
+                    "adCode": "421181",
+                    "cityCode": "0713"
+                },
+                {
+                    "name": "马鞍山市",
+                    "adCode": "340500",
+                    "cityCode": "0555"
+                },
+                {
+                    "name": "马尔康市",
+                    "adCode": "513201",
+                    "cityCode": "0837"
+                },
+                {
+                    "name": "满洲里市",
+                    "adCode": "150781",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "芒市",
+                    "adCode": "533103",
+                    "cityCode": "0692"
+                },
+                {
+                    "name": "茂名市",
+                    "adCode": "440900",
+                    "cityCode": "0668"
+                },
+                {
+                    "name": "眉山市",
+                    "adCode": "511400",
+                    "cityCode": "1833"
+                },
+                {
+                    "name": "梅河口市",
+                    "adCode": "220581",
+                    "cityCode": "0435"
+                },
+                {
+                    "name": "梅州市",
+                    "adCode": "441400",
+                    "cityCode": "0753"
+                },
+                {
+                    "name": "蒙自市",
+                    "adCode": "532503",
+                    "cityCode": "0873"
+                },
+                {
+                    "name": "孟州市",
+                    "adCode": "410883",
+                    "cityCode": "0391"
+                },
+                {
+                    "name": "弥勒市",
+                    "adCode": "532504",
+                    "cityCode": "0873"
+                },
+                {
+                    "name": "汨罗市",
+                    "adCode": "430681",
+                    "cityCode": "0730"
+                },
+                {
+                    "name": "密山市",
+                    "adCode": "230382",
+                    "cityCode": "0467"
+                },
+                {
+                    "name": "绵阳市",
+                    "adCode": "510700",
+                    "cityCode": "0816"
+                },
+                {
+                    "name": "绵竹市",
+                    "adCode": "510683",
+                    "cityCode": "0838"
+                },
+                {
+                    "name": "明光市",
+                    "adCode": "341182",
+                    "cityCode": "0550"
+                },
+                {
+                    "name": "牡丹江市",
+                    "adCode": "231000",
+                    "cityCode": "0453"
+                },
+                {
+                    "name": "穆棱市",
+                    "adCode": "231085",
+                    "cityCode": "0453"
+                }
+            ]
+        },
+        {
+            "letter": "N",
+            "list": [
+                {
+                    "name": "南安市",
+                    "adCode": "350583",
+                    "cityCode": "0595"
+                },
+                {
+                    "name": "南昌市",
+                    "adCode": "360100",
+                    "cityCode": "0791"
+                },
+                {
+                    "name": "南充市",
+                    "adCode": "511300",
+                    "cityCode": "0817"
+                },
+                {
+                    "name": "南宫市",
+                    "adCode": "130581",
+                    "cityCode": "0319"
+                },
+                {
+                    "name": "南京市",
+                    "adCode": "320100",
+                    "cityCode": "025",
+                    "type": "hot"
+                },
+                {
+                    "name": "南宁市",
+                    "adCode": "450100",
+                    "cityCode": "0771"
+                },
+                {
+                    "name": "南平市",
+                    "adCode": "350700",
+                    "cityCode": "0599"
+                },
+                {
+                    "name": "南通市",
+                    "adCode": "320600",
+                    "cityCode": "0513"
+                },
+                {
+                    "name": "南雄市",
+                    "adCode": "440282",
+                    "cityCode": "0751"
+                },
+                {
+                    "name": "南阳市",
+                    "adCode": "411300",
+                    "cityCode": "0377"
+                },
+                {
+                    "name": "讷河市",
+                    "adCode": "230281",
+                    "cityCode": "0452"
+                },
+                {
+                    "name": "内江市",
+                    "adCode": "511000",
+                    "cityCode": "1832"
+                },
+                {
+                    "name": "宁安市",
+                    "adCode": "231084",
+                    "cityCode": "0453"
+                },
+                {
+                    "name": "宁波市",
+                    "adCode": "330200",
+                    "cityCode": "0574"
+                },
+                {
+                    "name": "宁德市",
+                    "adCode": "350900",
+                    "cityCode": "0593"
+                },
+                {
+                    "name": "宁国市",
+                    "adCode": "341881",
+                    "cityCode": "0563"
+                }
+            ]
+        },
+        {
+            "letter": "P",
+            "list": [
+                {
+                    "name": "攀枝花市",
+                    "adCode": "510400",
+                    "cityCode": "0812"
+                },
+                {
+                    "name": "盘锦市",
+                    "adCode": "211100",
+                    "cityCode": "0427"
+                },
+                {
+                    "name": "磐石市",
+                    "adCode": "220284",
+                    "cityCode": "0432"
+                },
+                {
+                    "name": "彭州市",
+                    "adCode": "510182",
+                    "cityCode": "028"
+                },
+                {
+                    "name": "蓬莱市",
+                    "adCode": "370684",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "邳州市",
+                    "adCode": "320382",
+                    "cityCode": "0516"
+                },
+                {
+                    "name": "平顶山市",
+                    "adCode": "410400",
+                    "cityCode": "0375"
+                },
+                {
+                    "name": "平度市",
+                    "adCode": "370283",
+                    "cityCode": "0532"
+                },
+                {
+                    "name": "平湖市",
+                    "adCode": "330482",
+                    "cityCode": "0573"
+                },
+                {
+                    "name": "平凉市",
+                    "adCode": "620800",
+                    "cityCode": "0933"
+                },
+                {
+                    "name": "凭祥市",
+                    "adCode": "451481",
+                    "cityCode": "1771"
+                },
+                {
+                    "name": "萍乡市",
+                    "adCode": "360300",
+                    "cityCode": "0799"
+                },
+                {
+                    "name": "莆田市",
+                    "adCode": "350300",
+                    "cityCode": "0594"
+                },
+                {
+                    "name": "濮阳市",
+                    "adCode": "410900",
+                    "cityCode": "0393"
+                },
+                {
+                    "name": "普洱市",
+                    "adCode": "530800",
+                    "cityCode": "0879"
+                },
+                {
+                    "name": "普宁市",
+                    "adCode": "445281",
+                    "cityCode": "0663"
+                }
+            ]
+        },
+        {
+            "letter": "Q",
+            "list": [
+                {
+                    "name": "七台河市",
+                    "adCode": "230900",
+                    "cityCode": "0464"
+                },
+                {
+                    "name": "栖霞市",
+                    "adCode": "370686",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "齐齐哈尔市",
+                    "adCode": "230200",
+                    "cityCode": "0452"
+                },
+                {
+                    "name": "启东市",
+                    "adCode": "320681",
+                    "cityCode": "0513"
+                },
+                {
+                    "name": "迁安市",
+                    "adCode": "130283",
+                    "cityCode": "0315"
+                },
+                {
+                    "name": "潜江市",
+                    "adCode": "429005",
+                    "cityCode": "2728"
+                },
+                {
+                    "name": "钦州市",
+                    "adCode": "450700",
+                    "cityCode": "0777"
+                },
+                {
+                    "name": "秦皇岛市",
+                    "adCode": "130300",
+                    "cityCode": "0335"
+                },
+                {
+                    "name": "沁阳市",
+                    "adCode": "410882",
+                    "cityCode": "0391"
+                },
+                {
+                    "name": "青岛市",
+                    "adCode": "370200",
+                    "cityCode": "0532",
+                    "type": "hot"
+                },
+                {
+                    "name": "青铜峡市",
+                    "adCode": "640381",
+                    "cityCode": "0953"
+                },
+                {
+                    "name": "青州市",
+                    "adCode": "370781",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "清远市",
+                    "adCode": "441800",
+                    "cityCode": "0763"
+                },
+                {
+                    "name": "清镇市",
+                    "adCode": "520181",
+                    "cityCode": "0851"
+                },
+                {
+                    "name": "庆阳市",
+                    "adCode": "621000",
+                    "cityCode": "0934"
+                },
+                {
+                    "name": "邛崃市",
+                    "adCode": "510183",
+                    "cityCode": "028"
+                },
+                {
+                    "name": "琼海市",
+                    "adCode": "469002",
+                    "cityCode": "1894"
+                },
+                {
+                    "name": "衢州市",
+                    "adCode": "330800",
+                    "cityCode": "0570"
+                },
+                {
+                    "name": "曲阜市",
+                    "adCode": "370881",
+                    "cityCode": "0537"
+                },
+                {
+                    "name": "曲靖市",
+                    "adCode": "530300",
+                    "cityCode": "0874"
+                },
+                {
+                    "name": "泉州市",
+                    "adCode": "350500",
+                    "cityCode": "0595"
+                }
+            ]
+        },
+        {
+            "letter": "R",
+            "list": [
+                {
+                    "name": "仁怀市",
+                    "adCode": "520382",
+                    "cityCode": "0852"
+                },
+                {
+                    "name": "任丘市",
+                    "adCode": "130982",
+                    "cityCode": "0317"
+                },
+                {
+                    "name": "日喀则市",
+                    "adCode": "540200",
+                    "cityCode": "0892"
+                },
+                {
+                    "name": "日照市",
+                    "adCode": "371100",
+                    "cityCode": "0633"
+                },
+                {
+                    "name": "荣成市",
+                    "adCode": "371082",
+                    "cityCode": "0631"
+                },
+                {
+                    "name": "如皋市",
+                    "adCode": "320682",
+                    "cityCode": "0513"
+                },
+                {
+                    "name": "汝州市",
+                    "adCode": "410482",
+                    "cityCode": "0375"
+                },
+                {
+                    "name": "乳山市",
+                    "adCode": "371083",
+                    "cityCode": "0631"
+                },
+                {
+                    "name": "瑞安市",
+                    "adCode": "330381",
+                    "cityCode": "0577"
+                },
+                {
+                    "name": "瑞昌市",
+                    "adCode": "360481",
+                    "cityCode": "0792"
+                },
+                {
+                    "name": "瑞金市",
+                    "adCode": "360781",
+                    "cityCode": "0797"
+                },
+                {
+                    "name": "瑞丽市",
+                    "adCode": "533102",
+                    "cityCode": "0692"
+                }
+            ]
+        },
+        {
+            "letter": "S",
+            "list": [
+                {
+                    "name": "三河市",
+                    "adCode": "131082",
+                    "cityCode": "0316"
+                },
+                {
+                    "name": "三门峡市",
+                    "adCode": "411200",
+                    "cityCode": "0398"
+                },
+                {
+                    "name": "三明市",
+                    "adCode": "350400",
+                    "cityCode": "0598"
+                },
+                {
+                    "name": "三沙市",
+                    "adCode": "460300",
+                    "cityCode": "2898"
+                },
+                {
+                    "name": "三亚市",
+                    "adCode": "460200",
+                    "cityCode": "0899"
+                },
+                {
+                    "name": "沙河市",
+                    "adCode": "130582",
+                    "cityCode": "0319"
+                },
+                {
+                    "name": "厦门市",
+                    "adCode": "350200",
+                    "cityCode": "0592",
+                    "type": "hot"
+                },
+                {
+                    "name": "山南市",
+                    "adCode": "540500",
+                    "cityCode": "0893"
+                },
+                {
+                    "name": "汕头市",
+                    "adCode": "440500",
+                    "cityCode": "0754"
+                },
+                {
+                    "name": "汕尾市",
+                    "adCode": "441500",
+                    "cityCode": "0660"
+                },
+                {
+                    "name": "商洛市",
+                    "adCode": "611000",
+                    "cityCode": "0914"
+                },
+                {
+                    "name": "商丘市",
+                    "adCode": "411400",
+                    "cityCode": "0370"
+                },
+                {
+                    "name": "上海市",
+                    "adCode": "310000",
+                    "cityCode": "021",
+                    "type": "hot"
+                },
+                {
+                    "name": "上饶市",
+                    "adCode": "361100",
+                    "cityCode": "0793"
+                },
+                {
+                    "name": "尚志市",
+                    "adCode": "230183",
+                    "cityCode": "0451"
+                },
+                {
+                    "name": "韶关市",
+                    "adCode": "440200",
+                    "cityCode": "0751"
+                },
+                {
+                    "name": "韶山市",
+                    "adCode": "430382",
+                    "cityCode": "0732"
+                },
+                {
+                    "name": "邵武市",
+                    "adCode": "350781",
+                    "cityCode": "0599"
+                },
+                {
+                    "name": "邵阳市",
+                    "adCode": "430500",
+                    "cityCode": "0739"
+                },
+                {
+                    "name": "绍兴市",
+                    "adCode": "330600",
+                    "cityCode": "0575"
+                },
+                {
+                    "name": "深圳市",
+                    "adCode": "440300",
+                    "cityCode": "0755",
+                    "type": "hot"
+                },
+                {
+                    "name": "深州市",
+                    "adCode": "131182",
+                    "cityCode": "0318"
+                },
+                {
+                    "name": "什邡市",
+                    "adCode": "510682",
+                    "cityCode": "0838"
+                },
+                {
+                    "name": "沈阳市",
+                    "adCode": "210100",
+                    "cityCode": "024"
+                },
+                {
+                    "name": "嵊州市",
+                    "adCode": "330683",
+                    "cityCode": "0575"
+                },
+                {
+                    "name": "十堰市",
+                    "adCode": "420300",
+                    "cityCode": "0719"
+                },
+                {
+                    "name": "石河子市",
+                    "adCode": "659001",
+                    "cityCode": "0993"
+                },
+                {
+                    "name": "石家庄市",
+                    "adCode": "130100",
+                    "cityCode": "0311"
+                },
+                {
+                    "name": "石狮市",
+                    "adCode": "350581",
+                    "cityCode": "0595"
+                },
+                {
+                    "name": "石首市",
+                    "adCode": "421081",
+                    "cityCode": "0716"
+                },
+                {
+                    "name": "石嘴山市",
+                    "adCode": "640200",
+                    "cityCode": "0952"
+                },
+                {
+                    "name": "寿光市",
+                    "adCode": "370783",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "舒兰市",
+                    "adCode": "220283",
+                    "cityCode": "0432"
+                },
+                {
+                    "name": "双河市",
+                    "adCode": "659007",
+                    "cityCode": "1909"
+                },
+                {
+                    "name": "双辽市",
+                    "adCode": "220382",
+                    "cityCode": "0434"
+                },
+                {
+                    "name": "双鸭山市",
+                    "adCode": "230500",
+                    "cityCode": "0469"
+                },
+                {
+                    "name": "朔州市",
+                    "adCode": "140600",
+                    "cityCode": "0349"
+                },
+                {
+                    "name": "四会市",
+                    "adCode": "441284",
+                    "cityCode": "0758"
+                },
+                {
+                    "name": "四平市",
+                    "adCode": "220300",
+                    "cityCode": "0434"
+                },
+                {
+                    "name": "松原市",
+                    "adCode": "220700",
+                    "cityCode": "0438"
+                },
+                {
+                    "name": "松滋市",
+                    "adCode": "421087",
+                    "cityCode": "0716"
+                },
+                {
+                    "name": "苏州市",
+                    "adCode": "320500",
+                    "cityCode": "0512"
+                },
+                {
+                    "name": "绥芬河市",
+                    "adCode": "231081",
+                    "cityCode": "0453"
+                },
+                {
+                    "name": "绥化市",
+                    "adCode": "231200",
+                    "cityCode": "0455"
+                },
+                {
+                    "name": "随州市",
+                    "adCode": "421300",
+                    "cityCode": "0722"
+                },
+                {
+                    "name": "遂宁市",
+                    "adCode": "510900",
+                    "cityCode": "0825"
+                }
+            ]
+        },
+        {
+            "letter": "T",
+            "list": [
+                {
+                    "name": "塔城市",
+                    "adCode": "654201",
+                    "cityCode": "0901"
+                },
+                {
+                    "name": "台山市",
+                    "adCode": "440781",
+                    "cityCode": "0750"
+                },
+                {
+                    "name": "台州市",
+                    "adCode": "331000",
+                    "cityCode": "0576"
+                },
+                {
+                    "name": "太仓市",
+                    "adCode": "320585",
+                    "cityCode": "0512"
+                },
+                {
+                    "name": "太原市",
+                    "adCode": "140100",
+                    "cityCode": "0351"
+                },
+                {
+                    "name": "泰安市",
+                    "adCode": "370900",
+                    "cityCode": "0538"
+                },
+                {
+                    "name": "泰兴市",
+                    "adCode": "321283",
+                    "cityCode": "0523"
+                },
+                {
+                    "name": "泰州市",
+                    "adCode": "321200",
+                    "cityCode": "0523"
+                },
+                {
+                    "name": "唐山市",
+                    "adCode": "130200",
+                    "cityCode": "0315"
+                },
+                {
+                    "name": "洮南市",
+                    "adCode": "220881",
+                    "cityCode": "0436"
+                },
+                {
+                    "name": "腾冲市",
+                    "adCode": "530581",
+                    "cityCode": "0875"
+                },
+                {
+                    "name": "滕州市",
+                    "adCode": "370481",
+                    "cityCode": "0632"
+                },
+                {
+                    "name": "天津市",
+                    "adCode": "120000",
+                    "cityCode": "022",
+                    "type": "hot"
+                },
+                {
+                    "name": "天门市",
+                    "adCode": "429006",
+                    "cityCode": "1728"
+                },
+                {
+                    "name": "天水市",
+                    "adCode": "620500",
+                    "cityCode": "0938"
+                },
+                {
+                    "name": "天长市",
+                    "adCode": "341181",
+                    "cityCode": "0550"
+                },
+                {
+                    "name": "调兵山市",
+                    "adCode": "211281",
+                    "cityCode": "0410"
+                },
+                {
+                    "name": "铁力市",
+                    "adCode": "230781",
+                    "cityCode": "0458"
+                },
+                {
+                    "name": "铁岭市",
+                    "adCode": "211200",
+                    "cityCode": "0410"
+                },
+                {
+                    "name": "铁门关市",
+                    "adCode": "659006",
+                    "cityCode": "1996"
+                },
+                {
+                    "name": "通化市",
+                    "adCode": "220500",
+                    "cityCode": "0435"
+                },
+                {
+                    "name": "通辽市",
+                    "adCode": "150500",
+                    "cityCode": "0475"
+                },
+                {
+                    "name": "同江市",
+                    "adCode": "230881",
+                    "cityCode": "0454"
+                },
+                {
+                    "name": "桐城市",
+                    "adCode": "340881",
+                    "cityCode": "0556"
+                },
+                {
+                    "name": "桐乡市",
+                    "adCode": "330483",
+                    "cityCode": "0573"
+                },
+                {
+                    "name": "铜川市",
+                    "adCode": "610200",
+                    "cityCode": "0919"
+                },
+                {
+                    "name": "铜陵市",
+                    "adCode": "340700",
+                    "cityCode": "0562"
+                },
+                {
+                    "name": "铜仁市",
+                    "adCode": "520600",
+                    "cityCode": "0856"
+                },
+                {
+                    "name": "图们市",
+                    "adCode": "222402",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "图木舒克市",
+                    "adCode": "659003",
+                    "cityCode": "1998"
+                },
+                {
+                    "name": "吐鲁番市",
+                    "adCode": "650400",
+                    "cityCode": "0995"
+                }
+            ]
+        },
+        {
+            "letter": "W",
+            "list": [
+                {
+                    "name": "瓦房店市",
+                    "adCode": "210281",
+                    "cityCode": "0411"
+                },
+                {
+                    "name": "万宁市",
+                    "adCode": "469006",
+                    "cityCode": "1898"
+                },
+                {
+                    "name": "万源市",
+                    "adCode": "511781",
+                    "cityCode": "0818"
+                },
+                {
+                    "name": "威海市",
+                    "adCode": "371000",
+                    "cityCode": "0631"
+                },
+                {
+                    "name": "潍坊市",
+                    "adCode": "370700",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "卫辉市",
+                    "adCode": "410781",
+                    "cityCode": "0373"
+                },
+                {
+                    "name": "渭南市",
+                    "adCode": "610500",
+                    "cityCode": "0913"
+                },
+                {
+                    "name": "温岭市",
+                    "adCode": "331081",
+                    "cityCode": "0576"
+                },
+                {
+                    "name": "温州市",
+                    "adCode": "330300",
+                    "cityCode": "0577"
+                },
+                {
+                    "name": "文昌市",
+                    "adCode": "469005",
+                    "cityCode": "1893"
+                },
+                {
+                    "name": "文山市",
+                    "adCode": "532601",
+                    "cityCode": "0876"
+                },
+                {
+                    "name": "乌海市",
+                    "adCode": "150300",
+                    "cityCode": "0473"
+                },
+                {
+                    "name": "乌兰察布市",
+                    "adCode": "150900",
+                    "cityCode": "0474"
+                },
+                {
+                    "name": "乌兰浩特市",
+                    "adCode": "152201",
+                    "cityCode": "0482"
+                },
+                {
+                    "name": "乌鲁木齐市",
+                    "adCode": "650100",
+                    "cityCode": "0991",
+                    "type": "hot"
+                },
+                {
+                    "name": "乌苏市",
+                    "adCode": "654202",
+                    "cityCode": "0901"
+                },
+                {
+                    "name": "无锡市",
+                    "adCode": "320200",
+                    "cityCode": "0510"
+                },
+                {
+                    "name": "芜湖市",
+                    "adCode": "340200",
+                    "cityCode": "0553"
+                },
+                {
+                    "name": "吴川市",
+                    "adCode": "440883",
+                    "cityCode": "0759"
+                },
+                {
+                    "name": "吴忠市",
+                    "adCode": "640300",
+                    "cityCode": "0953"
+                },
+                {
+                    "name": "梧州市",
+                    "adCode": "450400",
+                    "cityCode": "0774"
+                },
+                {
+                    "name": "五常市",
+                    "adCode": "230184",
+                    "cityCode": "0451"
+                },
+                {
+                    "name": "五大连池市",
+                    "adCode": "231182",
+                    "cityCode": "0456"
+                },
+                {
+                    "name": "五家渠市",
+                    "adCode": "659004",
+                    "cityCode": "1994"
+                },
+                {
+                    "name": "五指山市",
+                    "adCode": "469001",
+                    "cityCode": "1897"
+                },
+                {
+                    "name": "武安市",
+                    "adCode": "130481",
+                    "cityCode": "0310"
+                },
+                {
+                    "name": "武冈市",
+                    "adCode": "430581",
+                    "cityCode": "0739"
+                },
+                {
+                    "name": "武汉市",
+                    "adCode": "420100",
+                    "cityCode": "027",
+                    "type": "hot"
+                },
+                {
+                    "name": "武威市",
+                    "adCode": "620600",
+                    "cityCode": "1935"
+                },
+                {
+                    "name": "武穴市",
+                    "adCode": "421182",
+                    "cityCode": "0713"
+                },
+                {
+                    "name": "武夷山市",
+                    "adCode": "350782",
+                    "cityCode": "0599"
+                },
+                {
+                    "name": "舞钢市",
+                    "adCode": "410481",
+                    "cityCode": "0375"
+                }
+            ]
+        },
+        {
+            "letter": "X",
+            "list": [
+                {
+                    "name": "西安市",
+                    "adCode": "610100",
+                    "cityCode": "029",
+                    "type": "hot"
+                },
+                {
+                    "name": "西昌市",
+                    "adCode": "513401",
+                    "cityCode": "0834"
+                },
+                {
+                    "name": "西宁市",
+                    "adCode": "630100",
+                    "cityCode": "0971"
+                },
+                {
+                    "name": "锡林浩特市",
+                    "adCode": "152502",
+                    "cityCode": "0479"
+                },
+                {
+                    "name": "仙桃市",
+                    "adCode": "429004",
+                    "cityCode": "0728"
+                },
+                {
+                    "name": "咸宁市",
+                    "adCode": "421200",
+                    "cityCode": "0715"
+                },
+                {
+                    "name": "咸阳市",
+                    "adCode": "610400",
+                    "cityCode": "0910"
+                },
+                {
+                    "name": "香格里拉市",
+                    "adCode": "533401",
+                    "cityCode": "0887"
+                },
+                {
+                    "name": "湘潭市",
+                    "adCode": "430300",
+                    "cityCode": "0732"
+                },
+                {
+                    "name": "湘乡市",
+                    "adCode": "430381",
+                    "cityCode": "0732"
+                },
+                {
+                    "name": "襄阳市",
+                    "adCode": "420600",
+                    "cityCode": "0710"
+                },
+                {
+                    "name": "项城市",
+                    "adCode": "411681",
+                    "cityCode": "0394"
+                },
+                {
+                    "name": "孝感市",
+                    "adCode": "420900",
+                    "cityCode": "0712"
+                },
+                {
+                    "name": "孝义市",
+                    "adCode": "141181",
+                    "cityCode": "0358"
+                },
+                {
+                    "name": "辛集市",
+                    "adCode": "130181",
+                    "cityCode": "0311"
+                },
+                {
+                    "name": "忻州市",
+                    "adCode": "140900",
+                    "cityCode": "0350"
+                },
+                {
+                    "name": "新乐市",
+                    "adCode": "130184",
+                    "cityCode": "0311"
+                },
+                {
+                    "name": "新密市",
+                    "adCode": "410183",
+                    "cityCode": "0371"
+                },
+                {
+                    "name": "新民市",
+                    "adCode": "210181",
+                    "cityCode": "024"
+                },
+                {
+                    "name": "新泰市",
+                    "adCode": "370982",
+                    "cityCode": "0538"
+                },
+                {
+                    "name": "新乡市",
+                    "adCode": "410700",
+                    "cityCode": "0373"
+                },
+                {
+                    "name": "新沂市",
+                    "adCode": "320381",
+                    "cityCode": "0516"
+                },
+                {
+                    "name": "新余市",
+                    "adCode": "360500",
+                    "cityCode": "0790"
+                },
+                {
+                    "name": "新郑市",
+                    "adCode": "410184",
+                    "cityCode": "0371"
+                },
+                {
+                    "name": "信阳市",
+                    "adCode": "411500",
+                    "cityCode": "0376"
+                },
+                {
+                    "name": "信宜市",
+                    "adCode": "440983",
+                    "cityCode": "0668"
+                },
+                {
+                    "name": "邢台市",
+                    "adCode": "130500",
+                    "cityCode": "0319"
+                },
+                {
+                    "name": "兴城市",
+                    "adCode": "211481",
+                    "cityCode": "0429"
+                },
+                {
+                    "name": "兴化市",
+                    "adCode": "321281",
+                    "cityCode": "0523"
+                },
+                {
+                    "name": "兴宁市",
+                    "adCode": "441481",
+                    "cityCode": "0753"
+                },
+                {
+                    "name": "兴平市",
+                    "adCode": "610481",
+                    "cityCode": "0910"
+                },
+                {
+                    "name": "兴义市",
+                    "adCode": "522301",
+                    "cityCode": "0859"
+                },
+                {
+                    "name": "宿迁市",
+                    "adCode": "321300",
+                    "cityCode": "0527"
+                },
+                {
+                    "name": "宿州市",
+                    "adCode": "341300",
+                    "cityCode": "0557"
+                },
+                {
+                    "name": "徐州市",
+                    "adCode": "320300",
+                    "cityCode": "0516"
+                },
+                {
+                    "name": "许昌市",
+                    "adCode": "411000",
+                    "cityCode": "0374"
+                },
+                {
+                    "name": "宣城市",
+                    "adCode": "341800",
+                    "cityCode": "0563"
+                },
+                {
+                    "name": "宣威市",
+                    "adCode": "530381",
+                    "cityCode": "0874"
+                }
+            ]
+        },
+        {
+            "letter": "Y",
+            "list": [
+                {
+                    "name": "牙克石市",
+                    "adCode": "150782",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "雅安市",
+                    "adCode": "511800",
+                    "cityCode": "0835"
+                },
+                {
+                    "name": "烟台市",
+                    "adCode": "370600",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "延安市",
+                    "adCode": "610600",
+                    "cityCode": "0911"
+                },
+                {
+                    "name": "延吉市",
+                    "adCode": "222401",
+                    "cityCode": "1433"
+                },
+                {
+                    "name": "盐城市",
+                    "adCode": "320900",
+                    "cityCode": "0515"
+                },
+                {
+                    "name": "偃师市",
+                    "adCode": "410381",
+                    "cityCode": "0379"
+                },
+                {
+                    "name": "扬中市",
+                    "adCode": "321182",
+                    "cityCode": "0511"
+                },
+                {
+                    "name": "扬州市",
+                    "adCode": "321000",
+                    "cityCode": "0514"
+                },
+                {
+                    "name": "阳春市",
+                    "adCode": "441781",
+                    "cityCode": "0662"
+                },
+                {
+                    "name": "阳江市",
+                    "adCode": "441700",
+                    "cityCode": "0662"
+                },
+                {
+                    "name": "阳泉市",
+                    "adCode": "140300",
+                    "cityCode": "0353"
+                },
+                {
+                    "name": "伊春市",
+                    "adCode": "230700",
+                    "cityCode": "0458"
+                },
+                {
+                    "name": "伊宁市",
+                    "adCode": "654002",
+                    "cityCode": "0999"
+                },
+                {
+                    "name": "仪征市",
+                    "adCode": "321081",
+                    "cityCode": "0514"
+                },
+                {
+                    "name": "宜宾市",
+                    "adCode": "511500",
+                    "cityCode": "0831"
+                },
+                {
+                    "name": "宜昌市",
+                    "adCode": "420500",
+                    "cityCode": "0717"
+                },
+                {
+                    "name": "宜城市",
+                    "adCode": "420684",
+                    "cityCode": "0710"
+                },
+                {
+                    "name": "宜春市",
+                    "adCode": "360900",
+                    "cityCode": "0795"
+                },
+                {
+                    "name": "宜都市",
+                    "adCode": "420581",
+                    "cityCode": "0717"
+                },
+                {
+                    "name": "宜兴市",
+                    "adCode": "320282",
+                    "cityCode": "0510"
+                },
+                {
+                    "name": "宜州市",
+                    "adCode": "451281",
+                    "cityCode": "0778"
+                },
+                {
+                    "name": "义马市",
+                    "adCode": "411281",
+                    "cityCode": "0398"
+                },
+                {
+                    "name": "义乌市",
+                    "adCode": "330782",
+                    "cityCode": "0579"
+                },
+                {
+                    "name": "益阳市",
+                    "adCode": "430900",
+                    "cityCode": "0737"
+                },
+                {
+                    "name": "银川市",
+                    "adCode": "640100",
+                    "cityCode": "0951"
+                },
+                {
+                    "name": "英德市",
+                    "adCode": "441881",
+                    "cityCode": "0763"
+                },
+                {
+                    "name": "鹰潭市",
+                    "adCode": "360600",
+                    "cityCode": "0701"
+                },
+                {
+                    "name": "荥阳市",
+                    "adCode": "410182",
+                    "cityCode": "0371"
+                },
+                {
+                    "name": "营口市",
+                    "adCode": "210800",
+                    "cityCode": "0417"
+                },
+                {
+                    "name": "应城市",
+                    "adCode": "420981",
+                    "cityCode": "0712"
+                },
+                {
+                    "name": "永安市",
+                    "adCode": "350481",
+                    "cityCode": "0598"
+                },
+                {
+                    "name": "永城市",
+                    "adCode": "411481",
+                    "cityCode": "0370"
+                },
+                {
+                    "name": "永济市",
+                    "adCode": "140881",
+                    "cityCode": "0359"
+                },
+                {
+                    "name": "永康市",
+                    "adCode": "330784",
+                    "cityCode": "0579"
+                },
+                {
+                    "name": "永州市",
+                    "adCode": "431100",
+                    "cityCode": "0746"
+                },
+                {
+                    "name": "余姚市",
+                    "adCode": "330281",
+                    "cityCode": "0574"
+                },
+                {
+                    "name": "榆林市",
+                    "adCode": "610800",
+                    "cityCode": "0912"
+                },
+                {
+                    "name": "榆树市",
+                    "adCode": "220182",
+                    "cityCode": "0431"
+                },
+                {
+                    "name": "禹城市",
+                    "adCode": "371482",
+                    "cityCode": "0534"
+                },
+                {
+                    "name": "禹州市",
+                    "adCode": "411081",
+                    "cityCode": "0374"
+                },
+                {
+                    "name": "玉林市",
+                    "adCode": "450900",
+                    "cityCode": "0775"
+                },
+                {
+                    "name": "玉门市",
+                    "adCode": "620981",
+                    "cityCode": "0937"
+                },
+                {
+                    "name": "玉树市",
+                    "adCode": "632701",
+                    "cityCode": "0976"
+                },
+                {
+                    "name": "玉溪市",
+                    "adCode": "530400",
+                    "cityCode": "0877"
+                },
+                {
+                    "name": "沅江市",
+                    "adCode": "430981",
+                    "cityCode": "0737"
+                },
+                {
+                    "name": "原平市",
+                    "adCode": "140981",
+                    "cityCode": "0350"
+                },
+                {
+                    "name": "岳阳市",
+                    "adCode": "430600",
+                    "cityCode": "0730"
+                },
+                {
+                    "name": "云浮市",
+                    "adCode": "445300",
+                    "cityCode": "0766"
+                },
+                {
+                    "name": "运城市",
+                    "adCode": "140800",
+                    "cityCode": "0359"
+                }
+            ]
+        },
+        {
+            "letter": "Z",
+            "list": [
+                {
+                    "name": "枣阳市",
+                    "adCode": "420683",
+                    "cityCode": "0710"
+                },
+                {
+                    "name": "枣庄市",
+                    "adCode": "370400",
+                    "cityCode": "0632"
+                },
+                {
+                    "name": "扎兰屯市",
+                    "adCode": "150783",
+                    "cityCode": "0470"
+                },
+                {
+                    "name": "湛江市",
+                    "adCode": "440800",
+                    "cityCode": "0759"
+                },
+                {
+                    "name": "张家港市",
+                    "adCode": "320582",
+                    "cityCode": "0512"
+                },
+                {
+                    "name": "张家界市",
+                    "adCode": "430800",
+                    "cityCode": "0744"
+                },
+                {
+                    "name": "张家口市",
+                    "adCode": "130700",
+                    "cityCode": "0313"
+                },
+                {
+                    "name": "张掖市",
+                    "adCode": "620700",
+                    "cityCode": "0936"
+                },
+                {
+                    "name": "漳平市",
+                    "adCode": "350881",
+                    "cityCode": "0597"
+                },
+                {
+                    "name": "漳州市",
+                    "adCode": "350600",
+                    "cityCode": "0596"
+                },
+                {
+                    "name": "樟树市",
+                    "adCode": "360982",
+                    "cityCode": "0795"
+                },
+                {
+                    "name": "招远市",
+                    "adCode": "370685",
+                    "cityCode": "0535"
+                },
+                {
+                    "name": "昭通市",
+                    "adCode": "530600",
+                    "cityCode": "0870"
+                },
+                {
+                    "name": "肇东市",
+                    "adCode": "231282",
+                    "cityCode": "0455"
+                },
+                {
+                    "name": "肇庆市",
+                    "adCode": "441200",
+                    "cityCode": "0758"
+                },
+                {
+                    "name": "镇江市",
+                    "adCode": "321100",
+                    "cityCode": "0511"
+                },
+                {
+                    "name": "郑州市",
+                    "adCode": "410100",
+                    "cityCode": "0371",
+                    "type": "hot"
+                },
+                {
+                    "name": "枝江市",
+                    "adCode": "420583",
+                    "cityCode": "0717"
+                },
+                {
+                    "name": "中山市",
+                    "adCode": "442000",
+                    "cityCode": "0760"
+                },
+                {
+                    "name": "中卫市",
+                    "adCode": "640500",
+                    "cityCode": "1953"
+                },
+                {
+                    "name": "钟祥市",
+                    "adCode": "420881",
+                    "cityCode": "0724"
+                },
+                {
+                    "name": "舟山市",
+                    "adCode": "330900",
+                    "cityCode": "0580"
+                },
+                {
+                    "name": "周口市",
+                    "adCode": "411600",
+                    "cityCode": "0394"
+                },
+                {
+                    "name": "珠海市",
+                    "adCode": "440400",
+                    "cityCode": "0756"
+                },
+                {
+                    "name": "株洲市",
+                    "adCode": "430200",
+                    "cityCode": "0733"
+                },
+                {
+                    "name": "诸城市",
+                    "adCode": "370782",
+                    "cityCode": "0536"
+                },
+                {
+                    "name": "诸暨市",
+                    "adCode": "330681",
+                    "cityCode": "0575"
+                },
+                {
+                    "name": "驻马店市",
+                    "adCode": "411700",
+                    "cityCode": "0396"
+                },
+                {
+                    "name": "庄河市",
+                    "adCode": "210283",
+                    "cityCode": "0411"
+                },
+                {
+                    "name": "涿州市",
+                    "adCode": "130681",
+                    "cityCode": "0312"
+                },
+                {
+                    "name": "资兴市",
+                    "adCode": "431081",
+                    "cityCode": "0735"
+                },
+                {
+                    "name": "资阳市",
+                    "adCode": "512000",
+                    "cityCode": "0832"
+                },
+                {
+                    "name": "淄博市",
+                    "adCode": "370300",
+                    "cityCode": "0533"
+                },
+                {
+                    "name": "自贡市",
+                    "adCode": "510300",
+                    "cityCode": "0813"
+                },
+                {
+                    "name": "邹城市",
+                    "adCode": "370883",
+                    "cityCode": "0537"
+                },
+                {
+                    "name": "遵化市",
+                    "adCode": "130281",
+                    "cityCode": "0315"
+                },
+                {
+                    "name": "遵义市",
+                    "adCode": "520300",
+                    "cityCode": "0852"
+                }
+            ]
+        }
+    ]
+}

+ 493 - 0
src/views/businessInfo/accountInfo.vue

@@ -0,0 +1,493 @@
+<template>
+  <div class="account-info-page">
+    <h1 class="page-title">结算账户</h1>
+
+    <section class="form-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        结算账户
+      </h2>
+
+      <el-form
+        ref="formRef"
+        class="account-form"
+        :model="form"
+        :rules="rules"
+        label-width="120px"
+        require-asterisk-position="right"
+        label-position="right"
+      >
+        <el-form-item label="账户户名" prop="accountName">
+          <el-input v-model="form.accountName" placeholder="请输入账户户名" clearable maxlength="64" style="max-width: 480px" />
+        </el-form-item>
+
+        <el-form-item label="账户类型" prop="accountType">
+          <el-radio-group v-model="form.accountType" class="account-type-radio">
+            <el-radio :value="BANK_ACCOUNT_TYPE_CORPORATE"> 对公账户 </el-radio>
+            <el-radio :value="BANK_ACCOUNT_TYPE_PERSONAL"> 个人储蓄卡 </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="银行账号" prop="bankAccountNo">
+          <div class="field-stack">
+            <el-input
+              v-model="form.bankAccountNo"
+              placeholder="请输入开户银行账号"
+              clearable
+              maxlength="32"
+              style="max-width: 480px"
+            />
+            <p class="field-tip">
+              {{ bankAccountTip }}
+            </p>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="开户银行" prop="bankCode">
+          <div class="field-stack">
+            <el-popover
+              v-model:visible="bankPickerVisible"
+              placement="bottom-start"
+              :width="580"
+              trigger="click"
+              popper-class="bank-picker-popper"
+            >
+              <template #reference>
+                <el-input
+                  readonly
+                  :model-value="selectedBankLabel"
+                  placeholder="请选择开户银行"
+                  style="max-width: 480px"
+                  class="bank-trigger-input"
+                  :class="{ 'is-focus-like': bankPickerVisible }"
+                >
+                  <template #suffix>
+                    <el-icon class="el-select__caret">
+                      <ArrowDown />
+                    </el-icon>
+                  </template>
+                </el-input>
+              </template>
+              <div class="bank-picker" @click.stop>
+                <el-radio-group v-model="bankTab" size="small" class="bank-tab-group">
+                  <el-radio-button value="common"> 常用银行 </el-radio-button>
+                  <el-radio-button value="A-F"> ABCDEF </el-radio-button>
+                  <el-radio-button value="G-L"> GHJKL </el-radio-button>
+                  <el-radio-button value="M-P"> MNOP </el-radio-button>
+                  <el-radio-button value="Q-U"> QRSTU </el-radio-button>
+                  <el-radio-button value="V-Z"> VWXYZ </el-radio-button>
+                </el-radio-group>
+                <div class="bank-grid-wrap">
+                  <div class="bank-grid">
+                    <button
+                      v-for="b in filteredBanks"
+                      :key="b.code"
+                      type="button"
+                      class="bank-cell"
+                      :class="{ 'is-active': form.bankCode === b.code }"
+                      @click="selectBank(b)"
+                    >
+                      <span class="bank-logo" :style="{ background: b.color }">{{ b.logoText }}</span>
+                      <span class="bank-name">{{ b.shortName }}</span>
+                    </button>
+                  </div>
+                </div>
+              </div>
+            </el-popover>
+          </div>
+        </el-form-item>
+      </el-form>
+    </section>
+
+    <div class="footer-actions">
+      <el-button @click="onBack"> 返回 </el-button>
+      <el-button type="primary" class="btn-next" :loading="submitLoading" @click="onSubmit"> 下一步 </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+import { ArrowDown } from "@element-plus/icons-vue";
+import { localGet, localSet } from "@/utils/index";
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+
+const BANK_ACCOUNT_TYPE_CORPORATE = "BANK_ACCOUNT_TYPE_CORPORATE" as const;
+const BANK_ACCOUNT_TYPE_PERSONAL = "BANK_ACCOUNT_TYPE_PERSONAL" as const;
+
+const formRef = ref<FormInstance>();
+const submitLoading = ref(false);
+const bankPickerVisible = ref(false);
+const bankTab = ref("common");
+const route = useRoute();
+const router = useRouter();
+
+export interface BankItem {
+  code: string;
+  shortName: string;
+  tabKey: "common" | "A-F" | "G-L" | "M-P" | "Q-U" | "V-Z";
+  logoText: string;
+  color: string;
+}
+
+/** 演示数据:常用 + 按首字母分组(与示意图「标签 + 网格」一致) */
+const BANK_LIST: BankItem[] = [
+  { code: "ICBC", shortName: "工商银行", tabKey: "common", logoText: "工", color: "#c62828" },
+  { code: "ABC", shortName: "农业银行", tabKey: "common", logoText: "农", color: "#2e7d32" },
+  { code: "BOC", shortName: "中国银行", tabKey: "common", logoText: "中", color: "#b71c1c" },
+  { code: "CCB", shortName: "建设银行", tabKey: "common", logoText: "建", color: "#1565c0" },
+  { code: "COMM", shortName: "交通银行", tabKey: "common", logoText: "交", color: "#283593" },
+  { code: "PSBC", shortName: "邮储银行", tabKey: "common", logoText: "邮", color: "#00695c" },
+  { code: "CMB", shortName: "招商银行", tabKey: "common", logoText: "招", color: "#c62828" },
+  { code: "SPDB", shortName: "浦发银行", tabKey: "common", logoText: "浦", color: "#0d47a1" },
+  { code: "CIB", shortName: "兴业银行", tabKey: "common", logoText: "兴", color: "#1565c0" },
+  { code: "CMBC", shortName: "民生银行", tabKey: "common", logoText: "民", color: "#4e342e" },
+  { code: "HXB", shortName: "华夏银行", tabKey: "G-L", logoText: "华", color: "#d84315" },
+  { code: "GDB", shortName: "广发银行", tabKey: "G-L", logoText: "广", color: "#c62828" },
+  { code: "PAB", shortName: "平安银行", tabKey: "M-P", logoText: "平", color: "#f57f17" },
+  { code: "CITIC", shortName: "中信银行", tabKey: "M-P", logoText: "信", color: "#c62828" },
+  { code: "CEB", shortName: "光大银行", tabKey: "G-L", logoText: "光", color: "#6a1b9a" },
+  { code: "BOSH", shortName: "上海银行", tabKey: "G-L", logoText: "上", color: "#283593" },
+  { code: "BRCB", shortName: "北京银行", tabKey: "A-F", logoText: "京", color: "#c62828" },
+  { code: "NJCB", shortName: "南京银行", tabKey: "M-P", logoText: "宁", color: "#c62828" },
+  { code: "HZCB", shortName: "杭州银行", tabKey: "G-L", logoText: "杭", color: "#1565c0" },
+  { code: "ASB", shortName: "鞍山银行", tabKey: "A-F", logoText: "鞍", color: "#37474f" },
+  { code: "BSB", shortName: "包商银行", tabKey: "A-F", logoText: "包", color: "#455a64" },
+  { code: "QDCCB", shortName: "青岛银行", tabKey: "M-P", logoText: "青", color: "#0d47a1" },
+  { code: "WFCB", shortName: "潍坊银行", tabKey: "V-Z", logoText: "潍", color: "#1565c0" },
+  { code: "WZCB", shortName: "温州银行", tabKey: "V-Z", logoText: "温", color: "#c62828" },
+  { code: "XMBANK", shortName: "厦门银行", tabKey: "Q-U", logoText: "厦", color: "#00695c" },
+  { code: "YTBANK", shortName: "烟台银行", tabKey: "V-Z", logoText: "烟", color: "#37474f" },
+  { code: "ZZBANK", shortName: "郑州银行", tabKey: "V-Z", logoText: "郑", color: "#c62828" }
+];
+
+const form = reactive({
+  accountName: "",
+  accountType: "BANK_ACCOUNT_TYPE_CORPORATE" as "BANK_ACCOUNT_TYPE_CORPORATE" | "BANK_ACCOUNT_TYPE_PERSONAL",
+  bankAccountNo: "",
+  bankCode: ""
+});
+
+const selectedBankLabel = computed(() => {
+  if (!form.bankCode) return "";
+  const b = BANK_LIST.find(x => x.code === form.bankCode);
+  return b ? b.shortName : "";
+});
+
+const bankAccountTip = computed(() => {
+  if (form.accountType === "BANK_ACCOUNT_TYPE_CORPORATE") {
+    return "请务必填写与账户户名一致的对公银行账户。";
+  }
+  return "请务必填写与账户户名一致的个人储蓄卡账号。";
+});
+
+const tabToKey = computed<BankItem["tabKey"] | "common">(() => {
+  const m: Record<string, BankItem["tabKey"] | "common"> = {
+    common: "common",
+    "A-F": "A-F",
+    "G-L": "G-L",
+    "M-P": "M-P",
+    "Q-U": "Q-U",
+    "V-Z": "V-Z"
+  };
+  return m[bankTab.value] ?? "common";
+});
+
+const filteredBanks = computed(() => {
+  const k = tabToKey.value;
+  if (k === "common") return BANK_LIST.filter(b => b.tabKey === "common");
+  return BANK_LIST.filter(b => b.tabKey === k);
+});
+
+const rules: FormRules = {
+  accountName: [{ required: true, message: "请输入账户户名", trigger: "blur" }],
+  accountType: [{ required: true, message: "请选择账户类型", trigger: "change" }],
+  bankAccountNo: [
+    { required: true, message: "请输入银行账号", trigger: "blur" },
+    { pattern: /^[\d\s-]{8,40}$/, message: "请输入有效的银行账号", trigger: "blur" }
+  ],
+  bankCode: [{ required: true, message: "请选择开户银行", trigger: "change" }]
+};
+
+function selectBank(b: BankItem) {
+  form.bankCode = b.code;
+  bankPickerVisible.value = false;
+  formRef.value?.validateField("bankCode").catch(() => {});
+}
+
+function onBack() {
+  router.push({ path: "/businessInfo/industryQualifications", query: { ...route.query } });
+}
+
+function onSaveDraft() {
+  ElMessage.success("草稿已保存(可对接接口)");
+}
+
+/** 账户户名:subject_info.business_license_info.merchant_name */
+function readMerchantNameFromSubjectInfo(): string {
+  const raw = localGet(BUSINESS_DATA_CACHE_KEY) as Record<string, unknown> | null | undefined;
+  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return "";
+  const si = raw.subject_info as Record<string, unknown> | undefined;
+  if (!si || typeof si !== "object" || Array.isArray(si)) return "";
+  const bli = si.business_license_info as Record<string, unknown> | undefined;
+  if (!bli || typeof bli !== "object" || Array.isArray(bli)) return "";
+  return String(bli.merchant_name ?? "").trim();
+}
+
+function resolveBankCodeFromAccountBank(accountBank: string): string {
+  const s = accountBank.trim();
+  if (!s) return "";
+  const byCode = BANK_LIST.find(b => b.code === s);
+  if (byCode) return byCode.code;
+  const byShort = BANK_LIST.find(b => b.shortName === s);
+  if (byShort) return byShort.code;
+  return "";
+}
+
+/** 从缓存 bank_account_info 反显;无户名时用 subject_info 营业执照商户名 */
+function hydrateAccountFormFromBusinessDataCache() {
+  const raw = localGet(BUSINESS_DATA_CACHE_KEY) as Record<string, unknown> | null | undefined;
+  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
+    const m = readMerchantNameFromSubjectInfo();
+    if (m) form.accountName = m;
+    return;
+  }
+  const ba = raw.bank_account_info as Record<string, unknown> | undefined;
+  if (!ba || typeof ba !== "object" || Array.isArray(ba)) {
+    const m = readMerchantNameFromSubjectInfo();
+    if (m) form.accountName = m;
+    return;
+  }
+
+  const accName = String(ba.account_name ?? "").trim();
+  form.accountName = accName || readMerchantNameFromSubjectInfo();
+
+  const t = String(ba.bank_account_type ?? "").trim();
+  if (t === BANK_ACCOUNT_TYPE_CORPORATE || t === BANK_ACCOUNT_TYPE_PERSONAL) {
+    form.accountType = t;
+  }
+
+  form.bankAccountNo = String(ba.account_number ?? "").trim();
+
+  const bankLabel = String(ba.account_bank ?? "").trim();
+  form.bankCode = resolveBankCodeFromAccountBank(bankLabel);
+}
+
+onMounted(() => {
+  hydrateAccountFormFromBusinessDataCache();
+  nextTick(() => formRef.value?.clearValidate());
+});
+
+function mergeBankAccountIntoBusinessDataCache() {
+  const prev = localGet(BUSINESS_DATA_CACHE_KEY);
+  const base = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...(prev as Record<string, unknown>) } : {};
+  const prevBa =
+    base.bank_account_info && typeof base.bank_account_info === "object" && !Array.isArray(base.bank_account_info)
+      ? { ...(base.bank_account_info as Record<string, unknown>) }
+      : {};
+
+  const accountBankName = selectedBankLabel.value || String(form.bankCode || "").trim();
+
+  base.bank_account_info = {
+    ...prevBa,
+    bank_account_type: form.accountType,
+    account_bank: accountBankName,
+    account_number: String(form.bankAccountNo || "")
+      .replace(/\s+/g, "")
+      .trim(),
+    account_name: String(form.accountName || "").trim()
+  };
+  localSet(BUSINESS_DATA_CACHE_KEY, base);
+}
+
+async function onSubmit() {
+  if (!formRef.value) return;
+  submitLoading.value = true;
+  try {
+    await formRef.value.validate();
+    mergeBankAccountIntoBusinessDataCache();
+    await router.push({
+      path: "/businessInfo/adminInfo",
+      query: { ...route.query }
+    });
+  } catch {
+    ElMessage.warning("请完善必填信息");
+  } finally {
+    submitLoading.value = false;
+  }
+}
+
+watch(
+  () => form.accountType,
+  () => {
+    formRef.value?.validateField("bankAccountNo").catch(() => {});
+  }
+);
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.account-info-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 40px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 24px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.form-block {
+  margin-bottom: 24px;
+}
+.section-head {
+  display: flex;
+  align-items: center;
+  margin: 0 0 20px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.account-form {
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+}
+.field-stack {
+  width: 100%;
+}
+.field-tip {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.account-type-radio {
+  :deep(.el-radio__input.is-checked .el-radio__inner) {
+    background: $wechat-green;
+    border-color: $wechat-green;
+  }
+  :deep(.el-radio__input.is-checked + .el-radio__label) {
+    color: #303133;
+  }
+}
+.bank-trigger-input {
+  cursor: pointer;
+  &.is-focus-like {
+    :deep(.el-input__wrapper) {
+      box-shadow: 0 0 0 1px $wechat-green inset;
+    }
+  }
+}
+.footer-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+  margin-top: 16px;
+  border-top: 1px solid #ebeef5;
+}
+.footer-center {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+}
+.btn-next {
+  min-width: 100px;
+  background: $wechat-green;
+  border-color: $wechat-green;
+  &:hover {
+    background: #06ad56;
+    border-color: #06ad56;
+  }
+}
+</style>
+
+<style lang="scss">
+$wechat-green: #07c160;
+.bank-picker-popper {
+  padding: 0 !important;
+}
+.bank-picker {
+  .bank-tab-group {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 6px;
+    padding: 8px 4px 4px;
+    :deep(.el-radio-button__inner) {
+      padding: 6px 10px;
+      font-size: 12px;
+    }
+    :deep(.el-radio-button.is-active .el-radio-button__inner) {
+      color: #ffffff;
+      background: $wechat-green;
+      border-color: $wechat-green;
+      box-shadow: -1px 0 0 0 $wechat-green;
+    }
+  }
+  .bank-grid-wrap {
+    max-height: 280px;
+    padding: 8px 4px 12px;
+    overflow: auto;
+  }
+  .bank-grid {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    gap: 8px 12px;
+  }
+  .bank-cell {
+    display: flex;
+    gap: 8px;
+    align-items: center;
+    padding: 8px 10px;
+    margin: 0;
+    text-align: left;
+    cursor: pointer;
+    background: #ffffff;
+    border: 1px solid transparent;
+    border-radius: 6px;
+    transition: background 0.15s;
+    &:hover {
+      background: #f5f7fa;
+    }
+    &.is-active {
+      background: #e8f5e9;
+      border-color: $wechat-green;
+    }
+  }
+  .bank-logo {
+    display: inline-flex;
+    flex-shrink: 0;
+    align-items: center;
+    justify-content: center;
+    width: 28px;
+    height: 28px;
+    font-size: 12px;
+    font-weight: 600;
+    color: #ffffff;
+    border-radius: 4px;
+  }
+  .bank-name {
+    font-size: 13px;
+    line-height: 1.3;
+    color: #303133;
+  }
+}
+</style>

+ 422 - 0
src/views/businessInfo/adminInfo.vue

@@ -0,0 +1,422 @@
+<template>
+  <div class="admin-info-page">
+    <h1 class="page-title">超级管理员</h1>
+
+    <section class="form-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        超级管理员信息
+      </h2>
+      <p class="section-intro">
+        超级管理员将接收开户信息及完成签约,并可进行商户号日常重要管理及资金操作。请确定超级管理员为商户法定代表人或经办人。
+      </p>
+
+      <el-form
+        ref="formRef"
+        class="admin-form"
+        :model="form"
+        :rules="rules"
+        label-width="140px"
+        require-asterisk-position="right"
+        label-position="right"
+      >
+        <el-form-item label="超管身份" prop="managerIdentity">
+          <el-radio-group v-model="form.managerIdentity" class="identity-radio">
+            <el-radio value="LEGAL"> 法定代表人/经营者 </el-radio>
+            <el-radio value="SUPER"> 经办人 </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item label="超管姓名" prop="managerName">
+          <el-input v-model="form.managerName" placeholder="请输入超管姓名" clearable style="max-width: 420px" />
+        </el-form-item>
+
+        <el-form-item label="超管资料类型" prop="managerDocType">
+          <el-select v-model="form.managerDocType" placeholder="请选择" clearable style="max-width: 420px">
+            <el-option label="身份证" value="IDENTIFICATION_TYPE_IDCARD" />
+            <el-option label="护照" value="IDENTIFICATION_TYPE_OVERSEA_PASSPORT" />
+            <el-option label="香港居民来往内地通行证" value="IDENTIFICATION_TYPE_HONGKONG_PASSPORT" />
+            <el-option label="台湾居民来往大陆通行证" value="IDENTIFICATION_TYPE_TAIWAN_PASSPORT" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="证件号码" prop="managerDocNo">
+          <el-input v-model="form.managerDocNo" placeholder="请输入证件号码" clearable style="max-width: 420px" />
+        </el-form-item>
+
+        <el-form-item label="手机号码" prop="mobile">
+          <div class="field-stack">
+            <el-input v-model="form.mobile" placeholder="请输入手机号" clearable maxlength="11" style="max-width: 420px" />
+            <p class="field-tip">用于接收微信支付的重要管理信息及日常操作验证码,超管签约时可自助修改手机号,并进行短信验证</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="邮箱" prop="email">
+          <div class="field-stack">
+            <el-input v-model="form.email" placeholder="请输入邮箱" clearable style="max-width: 420px" />
+            <p class="field-tip">用于接收微信支付的开户邮件及日常业务通知</p>
+          </div>
+        </el-form-item>
+      </el-form>
+    </section>
+
+    <div class="footer-actions">
+      <el-button @click="onBack"> 返回 </el-button>
+      <el-button type="danger" class="btn-next" :loading="submitLoading" @click="onSubmit"> 提交 </el-button>
+    </div>
+
+    <el-dialog
+      v-model="signDialogVisible"
+      title="签约链接"
+      width="480px"
+      align-center
+      destroy-on-close
+      @closed="onSignDialogClosed"
+    >
+      <div class="sign-dialog">
+        <div v-if="signQrImageUrl && !signQrError" class="sign-dialog__qr-wrap">
+          <img class="sign-dialog__qr" :src="signQrImageUrl" alt="签约二维码" @error="signQrError = true" />
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, nextTick, onMounted, reactive, ref } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+import { localGet, localSet } from "@/utils/index";
+import { applyment, getPaymentApplyment } from "@/api/modules/businessInfo";
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+const GEEKER_USER_KEY = "geeker-user";
+
+function resolveApplymentStoreId(): string | number | null {
+  const geeker = localGet(GEEKER_USER_KEY) as { userInfo?: { storeId?: string | number | null } } | null | undefined;
+  const sid = geeker?.userInfo?.storeId ?? localGet("createdId");
+  if (sid === undefined || sid === null || sid === "") return null;
+  return sid;
+}
+
+const formRef = ref<FormInstance>();
+const submitLoading = ref(false);
+const signDialogVisible = ref(false);
+const signUrlText = ref("");
+const signQrError = ref(false);
+const route = useRoute();
+const router = useRouter();
+
+const signQrImageUrl = computed(() => {
+  const u = signUrlText.value.trim();
+  if (!/^https?:\/\//i.test(u)) return "";
+  return `https://api.qrserver.com/v1/create-qr-code/?size=280x280&data=${encodeURIComponent(u)}`;
+});
+
+function pickApplymentIdFromApplymentResponse(res: unknown): string {
+  const r = res as Record<string, unknown> | null | undefined;
+  const top = r?.data !== undefined ? r.data : r;
+  if (!top || typeof top !== "object" || Array.isArray(top)) return "";
+  const t = top as Record<string, unknown>;
+  const inner =
+    t.data !== undefined && t.data !== null && typeof t.data === "object" && !Array.isArray(t.data)
+      ? (t.data as Record<string, unknown>)
+      : t;
+  const id = inner.applyment_id ?? inner.applymentId;
+  return String(id ?? "").trim();
+}
+
+function pickSignUrlFromPaymentApplymentResponse(res: unknown): string {
+  const r = res as Record<string, unknown> | null | undefined;
+  const top = r?.data !== undefined ? r.data : r;
+  if (!top || typeof top !== "object" || Array.isArray(top)) return "";
+  const t = top as Record<string, unknown>;
+  const inner =
+    t.data !== undefined && t.data !== null && typeof t.data === "object" && !Array.isArray(t.data)
+      ? (t.data as Record<string, unknown>)
+      : t;
+  const url = inner.sign_url ?? inner.signUrl;
+  return String(url ?? "").trim();
+}
+
+function onSignDialogClosed() {
+  signUrlText.value = "";
+  signQrError.value = false;
+}
+
+async function copySignUrl() {
+  const u = signUrlText.value.trim();
+  if (!u) return;
+  try {
+    await navigator.clipboard.writeText(u);
+    ElMessage.success("链接已复制");
+  } catch {
+    ElMessage.warning("复制失败,请手动选中复制");
+  }
+}
+
+const form = reactive({
+  managerIdentity: "LEGAL" as "SUPER" | "LEGAL",
+  managerName: "",
+  managerDocType: "",
+  managerDocNo: "",
+  mobile: "",
+  email: ""
+});
+
+const rules: FormRules = {
+  managerIdentity: [{ required: true, message: "请选择超管身份", trigger: "change" }],
+  managerName: [{ required: true, message: "请输入超管姓名", trigger: "blur" }],
+  managerDocType: [{ required: true, message: "请选择超管资料类型", trigger: "change" }],
+  managerDocNo: [{ required: true, message: "请输入证件号码", trigger: "blur" }],
+  mobile: [
+    { required: true, message: "请输入手机号", trigger: "blur" },
+    { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号", trigger: "blur" }
+  ],
+  email: [
+    { required: true, message: "请输入邮箱", trigger: "blur" },
+    { type: "email", message: "请输入正确的邮箱格式", trigger: ["blur", "change"] }
+  ]
+};
+
+function openMobileGuide() {
+  ElMessage.info("超管修改手机号指引(可对接文档)");
+}
+
+function onBack() {
+  router.push({ path: "/businessInfo/accountInfo", query: { ...route.query } });
+}
+
+function onSaveDraft() {
+  ElMessage.success("草稿已保存(可对接接口)");
+}
+
+/** 与 mergeContactInfoIntoBusinessDataCache 字段互逆 */
+function hydrateAdminFormFromContactInfoCache() {
+  const raw = localGet(BUSINESS_DATA_CACHE_KEY) as Record<string, unknown> | null | undefined;
+  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
+  const ci = raw.contact_info as Record<string, unknown> | undefined;
+  if (!ci || typeof ci !== "object" || Array.isArray(ci)) return;
+
+  const ct = String(ci.contact_type ?? "").trim();
+  if (ct === "LEGAL" || ct === "SUPER") {
+    form.managerIdentity = ct;
+  }
+
+  form.managerName = String(ci.contact_name ?? "").trim();
+  form.managerDocType = String(ci.contact_id_doc_type ?? "").trim();
+  form.managerDocNo = String(ci.contact_id_number ?? "").trim();
+  form.mobile = String(ci.mobile_phone ?? "").trim();
+  form.email = String(ci.contact_email ?? "").trim();
+}
+
+onMounted(() => {
+  hydrateAdminFormFromContactInfoCache();
+  nextTick(() => formRef.value?.clearValidate());
+});
+
+function mergeContactInfoIntoBusinessDataCache() {
+  const prev = localGet(BUSINESS_DATA_CACHE_KEY);
+  const base = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...(prev as Record<string, unknown>) } : {};
+  const prevCi =
+    base.contact_info && typeof base.contact_info === "object" && !Array.isArray(base.contact_info)
+      ? { ...(base.contact_info as Record<string, unknown>) }
+      : {};
+
+  base.contact_info = {
+    ...prevCi,
+    contact_type: form.managerIdentity,
+    contact_name: String(form.managerName || "").trim(),
+    contact_id_doc_type: String(form.managerDocType || "").trim(),
+    contact_id_number: String(form.managerDocNo || "").trim(),
+    mobile_phone: String(form.mobile || "").trim(),
+    contact_email: String(form.email || "").trim()
+  };
+  localSet(BUSINESS_DATA_CACHE_KEY, base);
+}
+
+async function onSubmit() {
+  if (!formRef.value) return;
+  try {
+    await formRef.value.validate();
+  } catch {
+    ElMessage.warning("请完善必填信息");
+    return;
+  }
+
+  submitLoading.value = true;
+  try {
+    mergeContactInfoIntoBusinessDataCache();
+    const businessData = localGet(BUSINESS_DATA_CACHE_KEY);
+    if (!businessData || typeof businessData !== "object" || Array.isArray(businessData)) {
+      ElMessage.warning("未找到进件数据,请重新填写");
+      return;
+    }
+    const storeIdRaw = resolveApplymentStoreId();
+    if (storeIdRaw === null) {
+      ElMessage.warning("未获取到门店 storeId,请重新登录");
+      return;
+    }
+    const n = Number(storeIdRaw);
+    const storeId = Number.isNaN(n) ? storeIdRaw : n;
+    const payload = { ...(businessData as Record<string, unknown>) };
+    const res: unknown = await applyment(payload, storeId);
+    const r = res as Record<string, unknown> | undefined;
+    if (r?.code === 200 || r?.code === "200") {
+      const applymentId = pickApplymentIdFromApplymentResponse(res);
+      if (applymentId) {
+        try {
+          const detailRes: unknown = await getPaymentApplyment(applymentId);
+          const dr = detailRes as Record<string, unknown> | undefined;
+          const nested = dr?.data as Record<string, unknown> | undefined;
+          const dCode = dr?.code ?? nested?.code;
+          if (dCode === 200 || dCode === "200") {
+            const signUrl = pickSignUrlFromPaymentApplymentResponse(detailRes);
+            if (/^https?:\/\//i.test(signUrl)) {
+              signUrlText.value = signUrl;
+              signQrError.value = false;
+              signDialogVisible.value = true;
+            }
+          }
+        } catch (e) {
+          console.warn("[adminInfo] getPaymentApplyment", e);
+        }
+      }
+      ElMessage.success((r?.msg as string) || "提交成功");
+    } else {
+      ElMessage.warning((r?.msg as string) || "提交失败,请稍后重试");
+    }
+  } catch {
+    ElMessage.error("提交失败,请稍后重试");
+  } finally {
+    submitLoading.value = false;
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.admin-info-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 40px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 24px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.form-block {
+  margin-bottom: 24px;
+}
+.section-head {
+  display: flex;
+  align-items: center;
+  margin: 0 0 12px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.section-intro {
+  margin: 0 0 20px;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.admin-form {
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+}
+.identity-radio {
+  :deep(.el-radio__input.is-checked .el-radio__inner) {
+    background: $wechat-green;
+    border-color: $wechat-green;
+  }
+  :deep(.el-radio__input.is-checked + .el-radio__label) {
+    color: #303133;
+  }
+}
+.tip-icon {
+  margin-left: 4px;
+  color: #c0c4cc;
+}
+.field-stack {
+  width: 100%;
+}
+.field-tip {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.footer-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+  margin-top: 16px;
+  border-top: 1px solid #ebeef5;
+}
+.footer-center {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+}
+.btn-next {
+  min-width: 100px;
+  background: $wechat-green;
+  border-color: $wechat-green;
+  &:hover {
+    background: #06ad56;
+    border-color: #06ad56;
+  }
+}
+.sign-dialog {
+  padding: 0 4px 8px;
+}
+.sign-dialog__qr-wrap {
+  display: flex;
+  justify-content: center;
+  margin-bottom: 16px;
+}
+.sign-dialog__qr {
+  width: 240px;
+  height: 240px;
+  object-fit: contain;
+  background: #fafafa;
+}
+.sign-dialog__fail {
+  margin: 0 0 12px;
+  font-size: 13px;
+  line-height: 1.6;
+  color: #909399;
+}
+.sign-dialog__hint {
+  margin: 0 0 12px;
+  font-size: 14px;
+  color: #606266;
+  text-align: center;
+}
+.sign-dialog__url {
+  margin-bottom: 16px;
+}
+.sign-dialog__actions {
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 154 - 0
src/views/businessInfo/createApply.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="create-apply-page">
+    <div class="page-header">
+      <h1 class="page-title">选择主体类型</h1>
+    </div>
+
+    <div class="card-grid">
+      <div v-for="item in entityTypeList" :key="item.key" class="entity-card">
+        <h3 class="card-title">
+          {{ item.title }}
+        </h3>
+        <p class="card-desc">
+          {{ item.desc }}
+        </p>
+        <el-button class="btn-select" @click="onSelectEntity(item)"> 选择 </el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import { localSet } from "@/utils/index";
+
+const router = useRouter();
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+
+type EntityTypeKey = "individual" | "enterprise" | "publicInstitution" | "socialOrganization" | "government" | "type";
+
+interface EntityTypeItem {
+  key: EntityTypeKey;
+  title: string;
+  desc: string;
+  type: "SUPER" | "LEGAL";
+}
+
+const entityTypeList: EntityTypeItem[] = [
+  {
+    key: "individual",
+    type: "SUPER",
+    title: "个体工商户",
+    desc: "营业执照上的主体类型一般为个体户、个体工商户、个体经营"
+  },
+  {
+    key: "enterprise",
+    title: "企业",
+    type: "LEGAL",
+    desc: "营业执照上的主体类型一般为有限公司、有限责任公司"
+  }
+];
+
+function openEntityGuide() {
+  ElMessage.info("主体指引说明可在此接入文档或弹窗");
+}
+
+function onSelectEntity(item: EntityTypeItem) {
+  const businessData = {
+    entityType: item.key,
+    contact_type: item.type
+  };
+  localSet(BUSINESS_DATA_CACHE_KEY, businessData);
+  router.push({
+    path: "/businessInfo/dataEntry",
+    query: { entityType: item.key }
+  });
+}
+</script>
+
+<style scoped lang="scss">
+.create-apply-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 48px;
+  background: #ffffff;
+}
+.page-header {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  align-items: center;
+  justify-content: space-between;
+  margin: 0 auto 28px;
+}
+.page-title {
+  margin: 0;
+  font-size: 22px;
+  font-weight: 600;
+  color: #303133;
+  letter-spacing: 0.02em;
+}
+.guide-link {
+  font-size: 14px;
+}
+.card-grid {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 20px;
+  margin: 0 auto;
+}
+
+@media (width <= 1100px) {
+  .card-grid {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
+
+@media (width <= 640px) {
+  .card-grid {
+    grid-template-columns: 1fr;
+  }
+}
+.entity-card {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: flex-start;
+  min-height: 220px;
+  padding: 24px 20px 20px;
+  text-align: center;
+  background: #ffffff;
+  border: 1px solid #e4e7ed;
+  border-radius: 8px;
+  box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
+}
+.card-title {
+  margin: 0 0 12px;
+  font-size: 16px;
+  font-weight: 600;
+  line-height: 1.4;
+  color: #303133;
+}
+.card-desc {
+  flex: 1;
+  margin: 0 0 20px;
+  font-size: 13px;
+  line-height: 1.65;
+  color: #909399;
+}
+.btn-select {
+  min-width: 120px;
+  height: 34px;
+  padding: 0 20px;
+  font-size: 14px;
+  color: #ffffff !important;
+  background: #00c05b !important;
+  border: none !important;
+  border-radius: 4px;
+  &:hover {
+    background: #00a850 !important;
+  }
+}
+</style>

+ 353 - 0
src/views/businessInfo/dataEntry.vue

@@ -0,0 +1,353 @@
+<template>
+  <div class="data-entry-page">
+    <h1 class="page-main-title">资料填写</h1>
+
+    <!-- 申请单信息 -->
+    <section class="content-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        申请单信息
+      </h2>
+      <div class="app-info-row">
+        <div class="app-info-item">
+          <span class="label">已选主体类型</span>
+          <span class="value">{{ entityTypeLabel }}</span>
+        </div>
+        <div class="app-info-item">
+          <span class="label">创建时间</span>
+          <span class="value mono">{{ applicationMeta.createdAt }}</span>
+        </div>
+        <div class="app-info-item">
+          <span class="label">申请单编号</span>
+          <span class="value mono">{{ applicationMeta.applicationNo }}</span>
+        </div>
+      </div>
+    </section>
+
+    <!-- 必填信息 -->
+    <section class="content-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        必填信息
+      </h2>
+      <ul class="step-list" role="list">
+        <li v-for="step in requiredSteps" :key="step.key" class="step-item">
+          <div class="step-indicator" :class="{ 'is-current': step.active }" aria-hidden="true">
+            <span v-if="step.active" class="dot-inner" />
+          </div>
+          <div class="step-main">
+            <div class="step-title-row">
+              <span class="step-title">{{ step.title }}</span>
+              <el-link v-if="step.showAction" type="info" :underline="false" class="step-action" @click="onGoFill(step.key)">
+                去填写 &gt;
+              </el-link>
+            </div>
+            <p class="step-desc">
+              {{ step.desc }}
+            </p>
+          </div>
+        </li>
+      </ul>
+    </section>
+
+    <!-- 选填信息 -->
+    <section class="content-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        选填信息
+      </h2>
+      <div class="optional-block">
+        <div class="optional-title">补充材料</div>
+        <p class="optional-desc">根据实际审核情况,额外要求商家提供指定的补充资料</p>
+      </div>
+    </section>
+
+    <!-- 协议 -->
+    <div class="agreement-block">
+      <el-checkbox v-model="agreementChecked" class="agreement-checkbox">
+        <span class="agreement-text">
+          商户自愿申请微信支付商户号,以上申请单资料由商户整理并委托本机构代为填写;最终提交资料以商户确认信息为准。
+        </span>
+      </el-checkbox>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, reactive, ref } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+
+/** 与 createApply 主体类型 key 对齐,便于路由 query 传入 */
+export type EntityTypeKey = "individual" | "enterprise" | "publicInstitution" | "socialOrganization" | "government";
+
+const ENTITY_LABEL: Record<EntityTypeKey, string> = {
+  individual: "个体工商户",
+  enterprise: "企业",
+  publicInstitution: "事业单位",
+  socialOrganization: "社会组织",
+  government: "政府机关"
+};
+
+const props = withDefaults(
+  defineProps<{
+    /** 路由或父组件传入的主体类型 */
+    entityType?: EntityTypeKey | string;
+  }>(),
+  {
+    entityType: undefined
+  }
+);
+
+const route = useRoute();
+const router = useRouter();
+
+const entityTypeLabel = computed(() => {
+  const k = (props.entityType ?? route.query.entityType ?? "individual") as EntityTypeKey;
+  return ENTITY_LABEL[k] ?? "个体工商户";
+});
+
+const applicationMeta = reactive({
+  createdAt: "2026-03-30 16:59:12",
+  applicationNo: "2000002773599273"
+});
+
+interface RequiredStep {
+  key: string;
+  title: string;
+  desc: string;
+  active: boolean;
+  showAction: boolean;
+}
+
+const requiredSteps = ref<RequiredStep[]>([
+  {
+    key: "entity",
+    title: "主体信息",
+    desc: "请填写商家的营业执照/登记证书、经营者/法人的证件等信息",
+    active: true,
+    showAction: true
+  },
+  {
+    key: "business",
+    title: "经营信息",
+    desc: "请填写商家的经营业务信息、售卖商品/提供服务场景信息",
+    active: false,
+    showAction: false
+  },
+  {
+    key: "industry",
+    title: "行业资质",
+    desc: "请填写商家所属行业、特殊资质等信息",
+    active: false,
+    showAction: false
+  },
+  {
+    key: "settlement",
+    title: "结算账户",
+    desc: "请填写商家提现收款的银行账户信息",
+    active: false,
+    showAction: false
+  },
+  {
+    key: "admin",
+    title: "超级管理员",
+    desc: "请填写商家的超级管理员信息,超级管理员需在开户后进行签约,并接收日常重要管理信息和进行资金操作,请确定其为商户法定代表人或负责人",
+    active: false,
+    showAction: false
+  }
+]);
+
+const agreementChecked = ref(true);
+
+function onModifyEntityType() {
+  ElMessage.info("可跳转选择主体类型页或打开弹窗");
+}
+
+function onGoFill(stepKey: string) {
+  if (stepKey === "entity") {
+    router.push({
+      path: "/businessInfo/subjectInfo",
+      query: { ...route.query }
+    });
+    return;
+  }
+  ElMessage.info(`进入填写:${stepKey}(可接路由)`);
+}
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.data-entry-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 48px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-main-title {
+  margin: 0 0 28px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.content-block {
+  padding-bottom: 28px;
+  margin-bottom: 32px;
+  border-bottom: 1px solid #ebeef5;
+  &:last-of-type {
+    padding-bottom: 0;
+    margin-bottom: 24px;
+    border-bottom: none;
+  }
+}
+.section-head {
+  display: flex;
+  align-items: center;
+  margin: 0 0 16px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.app-info-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px 32px;
+  align-items: baseline;
+  font-size: 14px;
+  line-height: 1.6;
+  color: #606266;
+}
+.app-info-item {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px 8px;
+  align-items: center;
+}
+.app-info-item .label {
+  color: #909399;
+}
+.app-info-item .value {
+  color: #303133;
+}
+.app-info-item .value.mono {
+  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+  font-size: 13px;
+}
+.modify-link {
+  margin-left: 4px;
+  font-size: 14px;
+}
+.step-list {
+  padding: 0;
+  margin: 0;
+  list-style: none;
+}
+.step-item {
+  display: flex;
+  gap: 12px;
+  padding: 16px 0;
+  border-bottom: 1px solid #f0f2f5;
+  &:last-child {
+    padding-bottom: 0;
+    border-bottom: none;
+  }
+}
+.step-indicator {
+  flex-shrink: 0;
+  width: 14px;
+  height: 14px;
+  margin-top: 4px;
+  border: 2px solid #dcdfe6;
+  border-radius: 50%;
+  &.is-current {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: $wechat-green;
+    border-color: $wechat-green;
+  }
+}
+.dot-inner {
+  width: 5px;
+  height: 5px;
+  background: #ffffff;
+  border-radius: 50%;
+}
+.step-main {
+  flex: 1;
+  min-width: 0;
+}
+.step-title-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px 16px;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 6px;
+}
+.step-title {
+  font-size: 15px;
+  font-weight: 600;
+  color: #303133;
+}
+.step-desc {
+  margin: 0;
+  font-size: 13px;
+  line-height: 1.65;
+  color: #909399;
+}
+.step-action {
+  flex-shrink: 0;
+  font-size: 13px;
+  color: #909399 !important;
+  &:hover {
+    color: #606266 !important;
+  }
+}
+.optional-block {
+  padding: 4px 0 0;
+}
+.optional-title {
+  margin-bottom: 8px;
+  font-size: 15px;
+  font-weight: 600;
+  color: #303133;
+}
+.optional-desc {
+  margin: 0;
+  font-size: 13px;
+  line-height: 1.65;
+  color: #909399;
+}
+.agreement-block {
+  padding-top: 8px;
+}
+.agreement-checkbox {
+  align-items: flex-start;
+  :deep(.el-checkbox__label) {
+    line-height: 1.65;
+    white-space: normal;
+  }
+  :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
+    background-color: $wechat-green;
+    border-color: $wechat-green;
+  }
+  :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
+    color: #606266;
+  }
+}
+.agreement-text {
+  font-size: 13px;
+  color: #606266;
+}
+</style>

+ 257 - 0
src/views/businessInfo/industryQualifications.vue

@@ -0,0 +1,257 @@
+<template>
+  <div class="industry-qual-page">
+    <h1 class="page-title">行业资质</h1>
+
+    <section class="form-block">
+      <h2 class="section-head">
+        <span class="section-bar" aria-hidden="true" />
+        行业资质
+        <span class="section-intro">请填写商家的所属行业、特殊资质等信息</span>
+      </h2>
+
+      <el-form
+        ref="formRef"
+        class="industry-form"
+        :model="form"
+        :rules="rules"
+        label-width="160px"
+        require-asterisk-position="right"
+        label-position="right"
+      >
+        <el-form-item label="所属行业" prop="industry">
+          <el-select
+            v-model="form.industry"
+            placeholder="请选择"
+            filterable
+            clearable
+            style="max-width: 480px"
+            @change="onIndustryChange"
+          >
+            <el-option v-for="o in industryOptions" :key="o.value" :label="o.label" :value="o.value" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="结算费率">
+          <span class="settlement-rate-text">{{ settlementRateText }}</span>
+        </el-form-item>
+
+        <!-- <el-form-item label="优惠费率活动(选填)" prop="discountActivity">
+          <div class="field-stack">
+            <el-select
+              v-model="form.discountActivity"
+              placeholder="请选择"
+              clearable
+              style="max-width: 480px"
+            >
+              <el-option
+                v-for="o in discountActivityOptions"
+                :key="o.value"
+                :label="o.label"
+                :value="o.value"
+              />
+            </el-select>
+            <p class="field-tip">
+              部分行业可报名优惠费率活动,活动介绍请查看
+              <el-link type="primary" :underline="false" @click="openDiscountDetail">查看详情</el-link>
+            </p>
+          </div>
+        </el-form-item> -->
+      </el-form>
+    </section>
+
+    <div class="footer-actions">
+      <el-button @click="onBack"> 返回 </el-button>
+      <el-button type="primary" class="btn-next" :loading="submitLoading" @click="onSubmit"> 下一步 </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, reactive, ref } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+import { localGet, localSet } from "@/utils/index";
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+
+const formRef = ref<FormInstance>();
+const submitLoading = ref(false);
+const route = useRoute();
+const router = useRouter();
+
+/** 演示选项,可对接字典/接口 */
+const industryOptions = [
+  { label: "餐饮", value: "716" },
+  { label: "零售", value: "catering_retail_retail" },
+  { label: "生活服务", value: "life_service" },
+  { label: "电商平台", value: "ecommerce" }
+];
+
+const discountActivityOptions = [
+  { label: "活动一:新商户费率优惠", value: "act_1" },
+  { label: "活动二:行业专项优惠", value: "act_2" }
+];
+
+/** 按行业展示结算费率(演示:默认与示意图一致) */
+const industryRateMap: Record<string, string> = {
+  "716": "0.6%",
+  catering_retail_catering: "0.6%",
+  catering_retail_retail: "0.6%",
+  life_service: "0.6%",
+  ecommerce: "0.6%"
+};
+
+const form = reactive({
+  industry: "716",
+  discountActivity: "" as string
+});
+
+const settlementRateText = computed(() => {
+  if (!form.industry) return "—";
+  return industryRateMap[form.industry] ?? "0.6%";
+});
+
+const rules: FormRules = {
+  industry: [{ required: true, message: "请选择所属行业", trigger: "change" }]
+};
+
+function onIndustryChange() {
+  formRef.value?.validateField("industry").catch(() => {});
+}
+
+function openDiscountDetail() {
+  ElMessage.info("优惠费率活动说明(可对接文档或外链)");
+}
+
+function onBack() {
+  router.push({ path: "/businessInfo/manageInfo", query: { ...route.query } });
+}
+
+function onSaveDraft() {
+  ElMessage.success("草稿已保存(可对接接口)");
+}
+
+function mergeSettlementIntoBusinessDataCache() {
+  const prev = localGet(BUSINESS_DATA_CACHE_KEY);
+  const base = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...(prev as Record<string, unknown>) } : {};
+  const prevSt =
+    base.settlement_info && typeof base.settlement_info === "object" && !Array.isArray(base.settlement_info)
+      ? { ...(base.settlement_info as Record<string, unknown>) }
+      : {};
+
+  const selected = industryOptions.find(o => o.value === form.industry);
+  const industryLabel = (selected?.label ?? "").trim();
+  const settlementId = selected != null ? String(selected.value).trim() : "";
+
+  base.settlement_info = {
+    ...prevSt,
+    qualification_type: industryLabel,
+    settlement_id: settlementId
+  };
+  localSet(BUSINESS_DATA_CACHE_KEY, base);
+}
+
+async function onSubmit() {
+  if (!formRef.value) return;
+  submitLoading.value = true;
+  try {
+    await formRef.value.validate();
+    mergeSettlementIntoBusinessDataCache();
+    await router.push({
+      path: "/businessInfo/accountInfo",
+      query: { ...route.query }
+    });
+  } catch {
+    ElMessage.warning("请完善必填信息");
+  } finally {
+    submitLoading.value = false;
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.industry-qual-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 40px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 24px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.form-block {
+  margin-bottom: 24px;
+}
+.section-head {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  margin: 0 0 20px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.section-intro {
+  margin-left: 12px;
+  font-size: 13px;
+  font-weight: 400;
+  line-height: 1.65;
+  color: #909399;
+}
+.industry-form {
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+}
+.settlement-rate-text {
+  font-size: 14px;
+  color: #303133;
+}
+.field-stack {
+  width: 100%;
+}
+.field-tip {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.footer-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+  margin-top: 16px;
+  border-top: 1px solid #ebeef5;
+}
+.footer-center {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+}
+.btn-next {
+  min-width: 100px;
+  background: $wechat-green;
+  border-color: $wechat-green;
+  &:hover {
+    background: #06ad56;
+    border-color: #06ad56;
+  }
+}
+</style>

+ 1078 - 0
src/views/businessInfo/manageInfo.vue

@@ -0,0 +1,1078 @@
+<template>
+  <div class="manage-info-page">
+    <h1 class="page-title">经营信息</h1>
+
+    <el-form
+      ref="formRef"
+      class="manage-form"
+      :model="form"
+      :rules="rules"
+      label-width="200px"
+      require-asterisk-position="right"
+      label-position="right"
+    >
+      <!-- 基础经营信息 -->
+      <section class="form-block">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          经营信息
+        </h2>
+
+        <el-form-item prop="merchantShortName">
+          <template #label>
+            <span class="label-with-icon">
+              商户简称
+              <el-tooltip placement="top" content="简称将展示给消费者,需与营业执照或品牌一致,勿使用无关或违规词汇。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="field-stack">
+            <el-input
+              v-model="form.merchantShortName"
+              placeholder="请输入商户简称"
+              clearable
+              maxlength="64"
+              show-word-limit
+              style="max-width: 480px"
+            />
+            <p class="field-tip">请与营业执照名称或品牌简称保持一致,便于用户识别;具体命名规则以微信支付平台要求为准。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item prop="servicePhone">
+          <template #label>
+            <span class="label-with-icon">
+              客服电话
+              <el-tooltip placement="top" content="用于用户咨询与平台联系,请填写真实可接通号码。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="field-stack">
+            <el-input
+              v-model="form.servicePhone"
+              placeholder="请输入客服电话"
+              clearable
+              maxlength="20"
+              style="max-width: 480px"
+            />
+            <p class="field-tip">请填写真实、可接通的客服电话,以便用户咨询。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="经营场景" prop="scenarioBits" required>
+          <div class="field-stack">
+            <div class="scenario-checks">
+              <el-checkbox v-model="form.scenarios.offline"> 线下场景 </el-checkbox>
+              <el-checkbox v-model="form.scenarios.miniProgram"> 小程序 </el-checkbox>
+              <el-checkbox v-model="form.scenarios.app"> APP </el-checkbox>
+              <el-checkbox v-model="form.scenarios.wechatAccount"> 服务号或订阅号 </el-checkbox>
+              <el-checkbox v-model="form.scenarios.website"> 互联网网站 </el-checkbox>
+              <el-checkbox v-model="form.scenarios.wecom"> 企业微信 </el-checkbox>
+            </div>
+          </div>
+        </el-form-item>
+      </section>
+
+      <!-- 线下场景 -->
+      <section v-if="form.scenarios.offline" class="form-block sub-section">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          线下场景
+        </h2>
+
+        <el-form-item label="线下场所名称" prop="offlineVenueName">
+          <el-input v-model="form.offlineVenueName" placeholder="请输入线下场所名称" clearable style="max-width: 480px" />
+        </el-form-item>
+
+        <el-form-item label="线下场所省市" prop="offlineProvinceCity">
+          <el-select v-model="form.offlineProvince" placeholder="请选择省" filterable style="width: 200px">
+            <el-option v-for="p in provinceOptions" :key="p.value" :label="p.label" :value="p.value" />
+          </el-select>
+          <el-select
+            v-model="form.offlineCity"
+            placeholder="请选择市"
+            filterable
+            style="width: 200px; margin-left: 12px"
+            :disabled="!form.offlineProvince"
+          >
+            <el-option v-for="c in cityOptions" :key="c.value" :label="c.label" :value="c.value" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="线下场所地址" prop="offlineAddress">
+          <div class="field-stack">
+            <el-input
+              v-model="form.offlineAddress"
+              type="textarea"
+              :rows="2"
+              placeholder="请输入详细地址"
+              maxlength="200"
+              show-word-limit
+              style="max-width: 480px"
+            />
+            <p class="field-tip">如有多个经营场所,请填写主要营业地址。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item prop="offlineStorefrontUrls">
+          <template #label>
+            <span class="label-with-icon">
+              线下场所门头照片
+              <el-tooltip placement="top" content="需清晰展示门头招牌与店名。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="field-stack">
+            <el-upload
+              v-model:file-list="form.offlineStorefrontFileList"
+              list-type="picture-card"
+              :limit="5"
+              accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+              :before-upload="beforeImageUpload"
+              :http-request="opt => handleMultiUpload(opt, 'storefront')"
+              :on-remove="(f, fl) => onMultiRemove(f, fl, 'storefront')"
+            >
+              <el-icon><Plus /></el-icon>
+            </el-upload>
+            <p class="field-tip">请上传清晰、完整的门头照片,招牌与店名需可辨认。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item prop="offlineInteriorUrls">
+          <template #label>
+            <span class="label-with-icon">
+              线下场所内部照片
+              <el-tooltip placement="top" content="展示店内经营环境。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="field-stack">
+            <el-upload
+              v-model:file-list="form.offlineInteriorFileList"
+              list-type="picture-card"
+              :limit="5"
+              accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+              :before-upload="beforeImageUpload"
+              :http-request="opt => handleMultiUpload(opt, 'interior')"
+              :on-remove="(f, fl) => onMultiRemove(f, fl, 'interior')"
+            >
+              <el-icon><Plus /></el-icon>
+            </el-upload>
+            <p class="field-tip">请上传店内环境照片,便于审核经营真实性。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="线下场所对应的服务号或公众号 APPID">
+          <div class="field-stack">
+            <el-input v-model="form.offlineMpAppId" placeholder="选填" clearable style="max-width: 480px" />
+            <p class="field-tip">如有线下场景关联的公众号,可填写 APPID。</p>
+          </div>
+        </el-form-item>
+      </section>
+
+      <!-- 小程序 -->
+      <section v-if="form.scenarios.miniProgram" class="form-block sub-section">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          小程序
+        </h2>
+
+        <el-form-item label="小程序 APPID" prop="miniProgramAppId">
+          <div class="field-stack">
+            <el-input v-model="form.miniProgramAppId" placeholder="请输入小程序 APPID" clearable style="max-width: 480px" />
+            <p class="field-tip">请填写已认证小程序的 APPID。</p>
+          </div>
+        </el-form-item>
+
+        <el-form-item label="小程序截图">
+          <div class="field-stack">
+            <el-upload
+              v-model:file-list="form.miniProgramShotFileList"
+              list-type="picture-card"
+              :limit="5"
+              accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+              :before-upload="beforeImageUpload"
+              :http-request="opt => handleMultiUpload(opt, 'miniShot')"
+              :on-remove="(f, fl) => onMultiRemove(f, fl, 'miniShot')"
+            >
+              <el-icon><Plus /></el-icon>
+            </el-upload>
+            <p class="field-tip">请上传商品或服务相关页面截图(最多 5 张)。</p>
+          </div>
+        </el-form-item>
+      </section>
+
+      <!-- APP -->
+      <section v-if="form.scenarios.app" class="form-block sub-section">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          APP
+        </h2>
+
+        <el-form-item label="AppID 来源" prop="appIdSource" required>
+          <el-radio-group v-model="form.appIdSource">
+            <el-radio value="provider"> 服务商应用 AppID </el-radio>
+            <el-radio value="merchant"> 商家应用 AppID </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <el-form-item v-if="form.appIdSource === 'provider'" label="服务商应用 AppID" prop="providerAppId">
+          <div class="field-stack">
+            <el-select v-model="form.providerAppId" placeholder="请选择" filterable style="max-width: 480px">
+              <el-option v-for="o in providerAppOptions" :key="o.value" :label="o.label" :value="o.value" />
+            </el-select>
+          </div>
+        </el-form-item>
+
+        <el-form-item prop="appShotUrls">
+          <template #label>
+            <span class="label-with-icon">
+              APP 截图
+              <el-tooltip placement="top" content="首页、商品列表、详情、支付等相关页面。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="field-stack">
+            <el-upload
+              v-model:file-list="form.appShotFileList"
+              list-type="picture-card"
+              :limit="5"
+              accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+              :before-upload="beforeImageUpload"
+              :http-request="opt => handleMultiUpload(opt, 'appShot')"
+              :on-remove="(f, fl) => onMultiRemove(f, fl, 'appShot')"
+            >
+              <el-icon><Plus /></el-icon>
+            </el-upload>
+            <p class="field-tip">请上传首页、商品列表、商品详情、支付等页面截图(最多 5 张)。</p>
+          </div>
+        </el-form-item>
+      </section>
+    </el-form>
+
+    <div class="footer-actions">
+      <el-button @click="onBack"> 返回 </el-button>
+      <el-button type="primary" class="btn-next" :loading="submitLoading" @click="onSubmit"> 下一步 </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+import type { UploadRequestOptions, UploadUserFile } from "element-plus";
+import { Plus, InfoFilled } from "@element-plus/icons-vue";
+import { getUpload } from "@/api/modules/businessInfo";
+import { localGet, localSet } from "@/utils/index";
+import cityJson from "@/assets/json/city.json";
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+
+const formRef = ref<FormInstance>();
+const submitLoading = ref(false);
+const route = useRoute();
+const router = useRouter();
+
+type UploadKind = "storefront" | "interior" | "miniShot" | "appShot";
+
+const form = reactive({
+  merchantShortName: "",
+  servicePhone: "",
+  scenarios: {
+    offline: true,
+    miniProgram: true,
+    app: true,
+    wechatAccount: false,
+    website: false,
+    wecom: false
+  },
+  offlineVenueName: "",
+  offlineProvince: "",
+  offlineCity: "",
+  offlineAddress: "",
+  offlineStorefrontFileList: [] as UploadUserFile[],
+  offlineStorefrontUrls: [] as string[],
+  offlineInteriorFileList: [] as UploadUserFile[],
+  offlineInteriorUrls: [] as string[],
+  offlineMpAppId: "",
+  miniProgramAppId: "",
+  miniProgramShotFileList: [] as UploadUserFile[],
+  miniProgramShotUrls: [] as string[],
+  appIdSource: "provider" as "provider" | "merchant",
+  providerAppId: "",
+  merchantAppId: "",
+  appShotFileList: [] as UploadUserFile[],
+  appShotUrls: [] as string[],
+  /** 用于校验至少选一种经营场景 */
+  scenarioBits: "1"
+});
+
+/** 与进件文档 business_info.sales_info.sales_scenes_type 枚举对应 */
+function buildSalesScenesType(): string[] {
+  const s = form.scenarios;
+  const types: string[] = [];
+  if (s.offline) types.push("SALES_SCENES_STORE");
+  if (s.miniProgram) types.push("SALES_SCENES_MINI_PROGRAM");
+  if (s.app) types.push("SALES_SCENES_APP");
+  if (s.wechatAccount) types.push("SALES_SCENES_MP");
+  if (s.website) types.push("SALES_SCENES_WEB");
+  if (s.wecom) types.push("SALES_SCENES_WEWORK");
+  return types;
+}
+
+/** 上传组件更新 file-list 时可能丢 response,用 uid 备份 media_id */
+const wechatMediaIdByFileUid = new Map<number, string>();
+
+function getMediaIdFromUploadFile(f: UploadUserFile): string {
+  const tagged = String((f as UploadUserFile & { __wxMediaId?: string }).__wxMediaId ?? "").trim();
+  if (tagged) return tagged;
+  const uid = (f as UploadUserFile & { uid?: number }).uid;
+  if (uid != null && wechatMediaIdByFileUid.has(uid)) {
+    return wechatMediaIdByFileUid.get(uid) ?? "";
+  }
+  const r = (f as UploadUserFile & { response?: unknown }).response;
+  if (r && typeof r === "object" && !Array.isArray(r)) {
+    const o = r as Record<string, unknown>;
+    const direct = String(o.media_id ?? o.mediaId ?? "").trim();
+    if (direct) return direct;
+    const nested = extractMediaUploadMeta(r).mediaId;
+    if (nested) return nested;
+  }
+  return "";
+}
+
+/** 写入进件缓存的四处图片字段均为微信 media/upload 返回的 media_id */
+function collectMediaIdsForMerge(list: UploadUserFile[]): string[] {
+  return list
+    .filter(f => f.status === "success")
+    .map(f => getMediaIdFromUploadFile(f))
+    .filter(Boolean);
+}
+
+function mergeManageInfoIntoBusinessDataCache() {
+  const prev = localGet(BUSINESS_DATA_CACHE_KEY);
+  const base = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...(prev as Record<string, unknown>) } : {};
+  const prevBi =
+    base.business_info && typeof base.business_info === "object" && !Array.isArray(base.business_info)
+      ? { ...(base.business_info as Record<string, unknown>) }
+      : {};
+  const prevSales =
+    prevBi.sales_info && typeof prevBi.sales_info === "object" && !Array.isArray(prevBi.sales_info)
+      ? { ...(prevBi.sales_info as Record<string, unknown>) }
+      : {};
+
+  const sales_info: Record<string, unknown> = {
+    ...prevSales,
+    sales_scenes_type: buildSalesScenesType()
+  };
+  if (form.scenarios.offline) {
+    sales_info.biz_store_info = {
+      biz_store_name: String(form.offlineVenueName || "").trim(),
+      biz_address_code: String(form.offlineCity || "").trim(),
+      biz_store_address: String(form.offlineAddress || "").trim(),
+      store_entrance_pic: collectMediaIdsForMerge(form.offlineStorefrontFileList),
+      indoor_pic: collectMediaIdsForMerge(form.offlineInteriorFileList),
+      biz_sub_appid: String(form.offlineMpAppId || "").trim()
+    };
+  } else {
+    delete sales_info.biz_store_info;
+  }
+
+  if (form.scenarios.miniProgram) {
+    sales_info.mini_program_info = {
+      mini_program_sub_appid: String(form.miniProgramAppId || "").trim(),
+      mini_program_pics: collectMediaIdsForMerge(form.miniProgramShotFileList)
+    };
+  } else {
+    delete sales_info.mini_program_info;
+  }
+
+  if (form.scenarios.app) {
+    sales_info.app_info = {
+      app_appid: String(form.providerAppId || "").trim(),
+      app_sub_appid: String(form.merchantAppId || "").trim(),
+      app_pics: collectMediaIdsForMerge(form.appShotFileList)
+    };
+  } else {
+    delete sales_info.app_info;
+  }
+
+  base.business_info = {
+    ...prevBi,
+    merchant_shortname: String(form.merchantShortName || "").trim(),
+    service_phone: String(form.servicePhone || "").trim(),
+    sales_info
+  };
+  localSet(BUSINESS_DATA_CACHE_KEY, base);
+}
+
+type CityJsonEntry = { name: string; adCode: string; cityCode: string; type?: string };
+type CityJsonRoot = { cityList: { letter: string; list: CityJsonEntry[] }[] };
+
+/** GB 行政区划代码前两位 → 省级名称(与 city.json 中 adCode 对应) */
+const PROVINCE_ROWS: [string, string][] = [
+  ["11", "北京市"],
+  ["12", "天津市"],
+  ["13", "河北省"],
+  ["14", "山西省"],
+  ["15", "内蒙古自治区"],
+  ["21", "辽宁省"],
+  ["22", "吉林省"],
+  ["23", "黑龙江省"],
+  ["31", "上海市"],
+  ["32", "江苏省"],
+  ["33", "浙江省"],
+  ["34", "安徽省"],
+  ["35", "福建省"],
+  ["36", "江西省"],
+  ["37", "山东省"],
+  ["41", "河南省"],
+  ["42", "湖北省"],
+  ["43", "湖南省"],
+  ["44", "广东省"],
+  ["45", "广西壮族自治区"],
+  ["46", "海南省"],
+  ["50", "重庆市"],
+  ["51", "四川省"],
+  ["52", "贵州省"],
+  ["53", "云南省"],
+  ["54", "西藏自治区"],
+  ["61", "陕西省"],
+  ["62", "甘肃省"],
+  ["63", "青海省"],
+  ["64", "宁夏回族自治区"],
+  ["65", "新疆维吾尔自治区"],
+  ["71", "台湾省"],
+  ["81", "香港特别行政区"],
+  ["82", "澳门特别行政区"]
+];
+const PROVINCE_BY_PREFIX = Object.fromEntries(PROVINCE_ROWS) as Record<string, string>;
+const PROVINCE_PREFIX_ORDER = PROVINCE_ROWS.map(([k]) => k);
+
+function buildProvinceCityOptions(): {
+  label: string;
+  value: string;
+  cities: { label: string; value: string }[];
+}[] {
+  const root = cityJson as CityJsonRoot;
+  const flat = root.cityList.flatMap(g => g.list);
+  const bucket = new Map<string, Map<string, CityJsonEntry>>();
+  for (const c of flat) {
+    const digits = String(c.adCode ?? "").replace(/\D/g, "");
+    const code = digits.length >= 6 ? digits.slice(-6) : digits.padStart(6, "0");
+    if (code.length !== 6) continue;
+    const prefix = code.slice(0, 2);
+    if (!PROVINCE_BY_PREFIX[prefix]) continue;
+    if (!bucket.has(prefix)) bucket.set(prefix, new Map());
+    bucket.get(prefix)!.set(c.adCode, c);
+  }
+  const out = [...bucket.entries()].map(([prefix, cityMap]) => ({
+    value: prefix,
+    label: PROVINCE_BY_PREFIX[prefix],
+    cities: [...cityMap.values()]
+      .sort((a, b) => a.name.localeCompare(b.name, "zh-CN"))
+      .map(ci => ({ label: ci.name, value: ci.adCode }))
+  }));
+  out.sort((a, b) => {
+    const ia = PROVINCE_PREFIX_ORDER.indexOf(a.value);
+    const ib = PROVINCE_PREFIX_ORDER.indexOf(b.value);
+    return (ia === -1 ? 999 : ia) - (ib === -1 ? 999 : ib);
+  });
+  return out;
+}
+
+const provinceOptions = buildProvinceCityOptions();
+
+const cityOptions = ref<{ label: string; value: string }[]>([]);
+
+watch(
+  () => form.offlineProvince,
+  code => {
+    form.offlineCity = "";
+    const p = provinceOptions.find(x => x.value === code);
+    cityOptions.value = p?.cities ?? [];
+  }
+);
+
+const providerAppOptions = [
+  { label: "请选择", value: "" },
+  { label: "wxfe73c5f183941efc", value: "wxfe73c5f183941efc" }
+];
+
+const scenarioChecked = computed(() => {
+  const s = form.scenarios;
+  return s.offline || s.miniProgram || s.app || s.wechatAccount || s.website || s.wecom;
+});
+
+watch(
+  () => form.scenarios,
+  () => {
+    form.scenarioBits = scenarioChecked.value ? "1" : "";
+  },
+  { deep: true }
+);
+
+function asStringArray(v: unknown): string[] {
+  if (!Array.isArray(v)) return [];
+  return v.map(x => String(x ?? "").trim()).filter(Boolean);
+}
+
+/** 从 localStorage businessData.business_info 回显经营信息表单 */
+function hydrateManageFormFromBusinessDataCache() {
+  const raw = localGet(BUSINESS_DATA_CACHE_KEY) as Record<string, unknown> | null | undefined;
+  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
+  const bi = raw.business_info as Record<string, unknown> | undefined;
+  if (!bi || typeof bi !== "object" || Array.isArray(bi)) return;
+
+  form.merchantShortName = String(bi.merchant_shortname ?? "").trim();
+  form.servicePhone = String(bi.service_phone ?? "").trim();
+
+  let pendingOfflineCity = "";
+
+  const si = bi.sales_info as Record<string, unknown> | undefined;
+  if (si && typeof si === "object" && !Array.isArray(si)) {
+    const sceneTypes = si.sales_scenes_type;
+    if (Array.isArray(sceneTypes)) {
+      const set = new Set(sceneTypes.map(t => String(t)));
+      form.scenarios.offline = set.has("SALES_SCENES_STORE");
+      form.scenarios.miniProgram = set.has("SALES_SCENES_MINI_PROGRAM");
+      form.scenarios.app = set.has("SALES_SCENES_APP");
+      form.scenarios.wechatAccount = set.has("SALES_SCENES_MP");
+      form.scenarios.website = set.has("SALES_SCENES_WEB");
+      form.scenarios.wecom = set.has("SALES_SCENES_WEWORK");
+      form.scenarioBits = scenarioChecked.value ? "1" : "";
+    }
+
+    const bzs = si.biz_store_info as Record<string, unknown> | undefined;
+    if (bzs && typeof bzs === "object" && !Array.isArray(bzs)) {
+      form.offlineVenueName = String(bzs.biz_store_name ?? "").trim();
+      const digits = String(bzs.biz_address_code ?? "").replace(/\D/g, "");
+      const code6 = digits.length >= 6 ? digits.slice(-6) : digits;
+      if (code6.length >= 2) {
+        const prefix = code6.slice(0, 2);
+        form.offlineProvince = prefix;
+        const p = provinceOptions.find(x => x.value === prefix);
+        cityOptions.value = p?.cities ?? [];
+        if (code6.length >= 6) pendingOfflineCity = code6;
+      }
+      form.offlineAddress = String(bzs.biz_store_address ?? "").trim();
+      const se = asStringArray(bzs.store_entrance_pic);
+      const indoor = asStringArray(bzs.indoor_pic);
+      form.offlineStorefrontUrls = [...se];
+      form.offlineInteriorUrls = [...indoor];
+      form.offlineStorefrontFileList = se.map(
+        (url, i) =>
+          ({
+            name: `storefront-${i + 1}.jpg`,
+            url,
+            status: "success",
+            response: { url, media_id: url, mediaId: url },
+            __wxMediaId: url
+          }) as UploadUserFile
+      );
+      form.offlineInteriorFileList = indoor.map(
+        (url, i) =>
+          ({
+            name: `interior-${i + 1}.jpg`,
+            url,
+            status: "success",
+            response: { url, media_id: url, mediaId: url },
+            __wxMediaId: url
+          }) as UploadUserFile
+      );
+      form.offlineMpAppId = String(bzs.biz_sub_appid ?? "").trim();
+    }
+
+    const mpi = si.mini_program_info as Record<string, unknown> | undefined;
+    if (mpi && typeof mpi === "object" && !Array.isArray(mpi)) {
+      form.miniProgramAppId = String(mpi.mini_program_sub_appid ?? "").trim();
+      const pics = asStringArray(mpi.mini_program_pics);
+      form.miniProgramShotUrls = [...pics];
+      form.miniProgramShotFileList = pics.map(
+        (url, i) =>
+          ({
+            name: `mini-${i + 1}.jpg`,
+            url,
+            status: "success",
+            response: { url, media_id: url, mediaId: url },
+            __wxMediaId: url
+          }) as UploadUserFile
+      );
+    }
+
+    const appInf = si.app_info as Record<string, unknown> | undefined;
+    if (appInf && typeof appInf === "object" && !Array.isArray(appInf)) {
+      form.providerAppId = String(appInf.app_appid ?? "").trim();
+      form.merchantAppId = String(appInf.app_sub_appid ?? "").trim();
+      form.appIdSource = form.providerAppId ? "provider" : "merchant";
+      const pics = asStringArray(appInf.app_pics);
+      form.appShotUrls = [...pics];
+      form.appShotFileList = pics.map(
+        (url, i) =>
+          ({
+            name: `app-${i + 1}.jpg`,
+            url,
+            status: "success",
+            response: { url, media_id: url, mediaId: url },
+            __wxMediaId: url
+          }) as UploadUserFile
+      );
+    }
+  }
+
+  nextTick(() => {
+    if (pendingOfflineCity) form.offlineCity = pendingOfflineCity;
+    formRef.value?.clearValidate();
+  });
+}
+
+onMounted(() => {
+  hydrateManageFormFromBusinessDataCache();
+});
+
+const rules: FormRules = {
+  merchantShortName: [{ required: true, message: "请输入商户简称", trigger: "blur" }],
+  servicePhone: [
+    { required: true, message: "请输入客服电话", trigger: "blur" },
+    { pattern: /^[\d\-+\s]{5,20}$/, message: "请输入有效电话号码", trigger: "blur" }
+  ],
+  scenarioBits: [{ required: true, message: "请至少选择一种经营场景", trigger: "change" }],
+  offlineVenueName: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.offline && !String(form.offlineVenueName).trim()) {
+          cb(new Error("请输入线下场所名称"));
+        } else cb();
+      },
+      trigger: "blur"
+    }
+  ],
+  offlineProvinceCity: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.offline && (!form.offlineProvince || !form.offlineCity)) {
+          cb(new Error("请选择线下场所省市"));
+        } else cb();
+      },
+      trigger: "change"
+    }
+  ],
+  offlineAddress: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.offline && !String(form.offlineAddress).trim()) {
+          cb(new Error("请输入线下场所地址"));
+        } else cb();
+      },
+      trigger: "blur"
+    }
+  ],
+  offlineStorefrontUrls: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.offline && form.offlineStorefrontUrls.length < 1) {
+          cb(new Error("请上传门头照片"));
+        } else cb();
+      },
+      trigger: "change"
+    }
+  ],
+  offlineInteriorUrls: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.offline && form.offlineInteriorUrls.length < 1) {
+          cb(new Error("请上传内部照片"));
+        } else cb();
+      },
+      trigger: "change"
+    }
+  ],
+  miniProgramAppId: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.miniProgram && !String(form.miniProgramAppId).trim()) {
+          cb(new Error("请输入小程序 APPID"));
+        } else cb();
+      },
+      trigger: "blur"
+    }
+  ],
+  providerAppId: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.app && form.appIdSource === "provider" && !String(form.providerAppId).trim()) {
+          cb(new Error("请选择服务商应用 AppID"));
+        } else cb();
+      },
+      trigger: "change"
+    }
+  ],
+  appShotUrls: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.scenarios.app && form.appShotUrls.length < 1) {
+          cb(new Error("请上传 APP 截图"));
+        } else cb();
+      },
+      trigger: "change"
+    }
+  ]
+};
+
+const MAX_IMG_MB = 5;
+
+function beforeImageUpload(file: File) {
+  const name = file.name?.toLowerCase() || "";
+  const okExt = /\.(jpe?g|png|bmp)$/i.test(name);
+  const okMime = ["image/jpeg", "image/png", "image/bmp"].includes(file.type);
+  if (!okExt && !okMime) {
+    ElMessage.error("图片只支持 JPG、BMP、PNG 格式");
+    return false;
+  }
+  if (file.size / 1024 / 1024 > MAX_IMG_MB) {
+    ElMessage.error(`文件大小不能超过 ${MAX_IMG_MB}M`);
+    return false;
+  }
+  return true;
+}
+
+function urlListKey(kind: UploadKind): "offlineStorefrontUrls" | "offlineInteriorUrls" | "miniProgramShotUrls" | "appShotUrls" {
+  const map = {
+    storefront: "offlineStorefrontUrls",
+    interior: "offlineInteriorUrls",
+    miniShot: "miniProgramShotUrls",
+    appShot: "appShotUrls"
+  } as const;
+  return map[kind];
+}
+
+/** 解析 getUpload 响应:兼容 data 为字符串、双层 data、嵌套对象等 */
+function extractMediaUploadMeta(res: any): { fileUrl: string; mediaId: string; errMsg: string } {
+  const errMsg = String(res?.msg ?? res?.message ?? res?.data?.msg ?? res?.data?.message ?? "").trim();
+
+  const pickFromObject = (node: any): { fileUrl: string; mediaId: string } => {
+    if (!node || typeof node !== "object" || Array.isArray(node)) return { fileUrl: "", mediaId: "" };
+    const mediaId = String(node.media_id ?? node.mediaId ?? node.MediaId ?? "").trim();
+    const fileUrl = String(node.url ?? node.fileUrl ?? node.mediaUrl ?? node.picUrl ?? "").trim();
+    return { fileUrl, mediaId };
+  };
+
+  let root = res;
+  const rawData = root?.data;
+  if (rawData != null && typeof rawData === "string") {
+    const s = rawData.trim();
+    if (s.startsWith("{") || s.startsWith("[")) {
+      try {
+        root = { ...(root && typeof root === "object" ? root : {}), data: JSON.parse(s) };
+      } catch {
+        return { fileUrl: "", mediaId: s, errMsg };
+      }
+    } else if (s) {
+      return { fileUrl: "", mediaId: s, errMsg };
+    }
+  }
+
+  const candidates: any[] = [];
+  const push = (x: any) => {
+    if (x != null) candidates.push(x);
+  };
+  push(root);
+  push(root?.data);
+  if (root?.data != null && typeof root.data === "object" && !Array.isArray(root.data)) {
+    push(root.data.data);
+    for (const v of Object.values(root.data)) {
+      if (v && typeof v === "object" && !Array.isArray(v)) push(v);
+    }
+  }
+
+  let fileUrl = "";
+  let mediaId = "";
+  for (const c of candidates) {
+    if (typeof c === "string" && c.trim()) {
+      mediaId = c.trim();
+      break;
+    }
+    if (!c || typeof c !== "object") continue;
+    const p = pickFromObject(c);
+    if (p.mediaId) {
+      mediaId = p.mediaId;
+      fileUrl = p.fileUrl || fileUrl;
+      break;
+    }
+    for (const v of Object.values(c)) {
+      if (v && typeof v === "object" && !Array.isArray(v)) {
+        const p2 = pickFromObject(v);
+        if (p2.mediaId) {
+          mediaId = p2.mediaId;
+          fileUrl = p2.fileUrl || fileUrl;
+          break;
+        }
+      }
+    }
+    if (mediaId) break;
+  }
+
+  return { fileUrl, mediaId, errMsg };
+}
+
+async function handleMultiUpload(options: UploadRequestOptions, kind: UploadKind) {
+  const uploadFileItem = options.file as UploadUserFile;
+  const raw = uploadFileItem.raw || uploadFileItem;
+  const file = raw instanceof File ? raw : null;
+  if (!file) return;
+
+  uploadFileItem.status = "uploading";
+  try {
+    const fd = new FormData();
+    fd.append("file", file);
+    const res: any = await getUpload(fd);
+    const { fileUrl, mediaId, errMsg } = extractMediaUploadMeta(res);
+    if (mediaId) {
+      uploadFileItem.status = "success";
+      if (fileUrl) uploadFileItem.url = fileUrl;
+      uploadFileItem.response = { media_id: mediaId, url: fileUrl };
+      const uid = (uploadFileItem as UploadUserFile & { uid?: number }).uid;
+      if (uid != null) wechatMediaIdByFileUid.set(uid, mediaId);
+      (uploadFileItem as UploadUserFile & { __wxMediaId?: string }).__wxMediaId = mediaId;
+    } else {
+      uploadFileItem.status = "fail";
+      ElMessage.error(errMsg || "上传失败,未返回 media_id");
+    }
+  } catch {
+    uploadFileItem.status = "fail";
+  }
+  syncUrlsFromFileList(kind);
+  validateKind(kind);
+}
+
+function syncUrlsFromFileList(kind: UploadKind) {
+  const key = urlListKey(kind);
+  let list: UploadUserFile[] = [];
+  if (kind === "storefront") list = form.offlineStorefrontFileList;
+  else if (kind === "interior") list = form.offlineInteriorFileList;
+  else if (kind === "miniShot") list = form.miniProgramShotFileList;
+  else list = form.appShotFileList;
+
+  form[key] = list
+    .map(f => {
+      const fu = f as UploadUserFile & { url?: string; response?: { url?: string } };
+      const mid = getMediaIdFromUploadFile(f);
+      const url = String(fu.url ?? fu.response?.url ?? "").trim();
+      return mid || url;
+    })
+    .filter(Boolean) as string[];
+}
+
+function onMultiRemove(file: UploadUserFile, _fileList: UploadUserFile[], kind: UploadKind) {
+  const uid = (file as UploadUserFile & { uid?: number }).uid;
+  if (uid != null) wechatMediaIdByFileUid.delete(uid);
+  delete (file as UploadUserFile & { __wxMediaId?: string }).__wxMediaId;
+  syncUrlsFromFileList(kind);
+  validateKind(kind);
+}
+
+function syncAllUploadUrlArrays() {
+  syncUrlsFromFileList("storefront");
+  syncUrlsFromFileList("interior");
+  syncUrlsFromFileList("miniShot");
+  syncUrlsFromFileList("appShot");
+}
+
+function assertActiveScenarioPicsHaveMediaId(): boolean {
+  const groups: { label: string; list: UploadUserFile[] }[] = [];
+  if (form.scenarios.offline) {
+    groups.push({ label: "门头照片", list: form.offlineStorefrontFileList });
+    groups.push({ label: "内部照片", list: form.offlineInteriorFileList });
+  }
+  if (form.scenarios.miniProgram) {
+    groups.push({ label: "小程序截图", list: form.miniProgramShotFileList });
+  }
+  if (form.scenarios.app) {
+    groups.push({ label: "APP 截图", list: form.appShotFileList });
+  }
+  for (const g of groups) {
+    for (const f of g.list) {
+      if (f.status !== "success") continue;
+      if (!getMediaIdFromUploadFile(f)) {
+        ElMessage.warning(`「${g.label}」须使用微信素材上传接口返回的 media_id,请删除后重新上传`);
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+function validateKind(kind: UploadKind) {
+  const map: Partial<Record<UploadKind, string>> = {
+    storefront: "offlineStorefrontUrls",
+    interior: "offlineInteriorUrls",
+    appShot: "appShotUrls"
+  };
+  const f = map[kind];
+  if (f) formRef.value?.validateField(f).catch(() => {});
+}
+
+function openScenarioGuide() {
+  ElMessage.info("经营场景填写指引(可对接文档)");
+}
+function openStorefrontGuide() {
+  ElMessage.info("门头照片拍摄指引");
+}
+function openAppidGuide() {
+  ElMessage.info("公众号 APPID 查找说明");
+}
+function openMiniAppidGuide() {
+  ElMessage.info("小程序 APPID 说明");
+}
+function openProviderAppGuide() {
+  ElMessage.info("服务商应用说明");
+}
+function openMerchantAppGuide() {
+  ElMessage.info("商家应用说明");
+}
+function openAppShotExample() {
+  ElMessage.info("APP 截图示例");
+}
+
+function onBack() {
+  router.push({ path: "/businessInfo/dataEntry", query: { ...route.query } });
+}
+
+function onSaveDraft() {
+  ElMessage.success("草稿已保存(可对接接口)");
+}
+
+async function onSubmit() {
+  if (!formRef.value) return;
+  submitLoading.value = true;
+  try {
+    await formRef.value.validate();
+    syncAllUploadUrlArrays();
+    if (!assertActiveScenarioPicsHaveMediaId()) return;
+    mergeManageInfoIntoBusinessDataCache();
+    await router.push({
+      path: "/businessInfo/industryQualifications",
+      query: { ...route.query }
+    });
+  } catch {
+    ElMessage.warning("请完善必填信息");
+  } finally {
+    submitLoading.value = false;
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.manage-info-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 40px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 24px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.manage-form {
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+}
+.form-block {
+  padding-bottom: 16px;
+  margin-bottom: 28px;
+  border-bottom: 1px solid #ebeef5;
+  &:last-of-type {
+    border-bottom: none;
+  }
+}
+.sub-section {
+  padding: 8px 16px 20px;
+  margin-top: 8px;
+  background: #fafafa;
+  border: 1px solid #ebeef5;
+  border-radius: 8px;
+}
+.section-head {
+  display: flex;
+  align-items: center;
+  margin: 16px 0 20px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.field-stack {
+  width: 100%;
+}
+.field-tip {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.scenario-checks {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px 20px;
+  margin-bottom: 8px;
+}
+.label-with-icon {
+  display: inline-flex;
+  gap: 4px;
+  align-items: center;
+}
+.info-icon {
+  color: #909399;
+  cursor: help;
+}
+:deep(.el-upload--picture-card) {
+  --el-upload-picture-card-size: 120px;
+}
+:deep(.el-upload-list--picture-card .el-upload-list__item) {
+  width: 120px;
+  height: 120px;
+}
+.footer-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+  margin-top: 16px;
+  border-top: 1px solid #ebeef5;
+}
+.footer-center {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+}
+.btn-next {
+  min-width: 100px;
+  background: $wechat-green;
+  border-color: $wechat-green;
+  &:hover {
+    background: #06ad56;
+    border-color: #06ad56;
+  }
+}
+</style>

+ 1150 - 0
src/views/businessInfo/subjectInfo.vue

@@ -0,0 +1,1150 @@
+<template>
+  <div class="subject-info-page">
+    <h1 class="page-title">主体信息</h1>
+
+    <el-form
+      ref="formRef"
+      class="subject-form"
+      :model="form"
+      :rules="rules"
+      label-width="140px"
+      require-asterisk-position="right"
+      label-position="right"
+    >
+      <!-- 主体身份 -->
+      <section class="form-block">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          主体身份 <span class="section-intro">请上传「营业执照」,需年检章齐全,当年注册除外</span>
+        </h2>
+
+        <!-- <el-form-item label="是否金融机构" prop="isFinancialInstitution">
+          <div class="field-stack">
+            <el-select v-model="form.isFinancialInstitution" placeholder="请选择" style="width: 260px">
+              <el-option label="否" :value="0" />
+              <el-option label="是" :value="1" />
+            </el-select>
+            <p class="field-tip">
+              金融机构是指从事金融类业务的机构,如信贷、融资、理财、担保、信托、货币兑换等。
+            </p>
+          </div>
+        </el-form-item> -->
+
+        <el-form-item prop="businessLicenseUrl">
+          <template #label>
+            <span class="label-with-icon">
+              营业执照照片
+              <el-tooltip placement="top" content="请上传清晰、完整的营业执照照片,需与后续填写信息一致。">
+                <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+              </el-tooltip>
+            </span>
+          </template>
+          <div class="license-upload-wrap">
+            <el-upload
+              v-model:file-list="form.businessLicenseFileList"
+              list-type="picture-card"
+              :limit="1"
+              accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+              :before-upload="beforeLicenseUpload"
+              :http-request="handleLicenseUpload"
+              :on-remove="onLicenseRemove"
+            >
+              <el-icon><Plus /></el-icon>
+            </el-upload>
+            <!-- <div class="license-example" aria-hidden="true" style="border:1px solid red;">
+              <div class="license-example-thumb">
+                <span class="license-example-placeholder">营业执照</span>
+              </div>
+            </div> -->
+          </div>
+          <div class="upload-rules">
+            <p>
+              1.
+              请上传彩色照片或彩色扫描件或加盖公章鲜章的复印件,要求正面拍摄,露出证件四角且清晰、完整,所有字符清晰可识别,不得反光或遮挡。不得翻拍、截图、镜像、PS。
+            </p>
+            <p>2. 图片只支持 JPG、BMP、PNG 格式,文件大小不能超过 5M。</p>
+          </div>
+        </el-form-item>
+        <div v-if="hasBusinessLicenseOcr" class="license-ocr-result">
+          <div v-if="businessLicenseOcr.creditCode" class="license-ocr-row">
+            <span class="license-ocr-label">统一社会信用代码</span>
+            <span class="license-ocr-value">{{ businessLicenseOcr.creditCode }}</span>
+          </div>
+          <div v-if="businessLicenseOcr.companyName" class="license-ocr-row">
+            <span class="license-ocr-label">企业名称</span>
+            <span class="license-ocr-value">{{ businessLicenseOcr.companyName }}</span>
+          </div>
+          <div v-if="businessLicenseOcr.legalPerson" class="license-ocr-row">
+            <span class="license-ocr-label">法定代表人</span>
+            <span class="license-ocr-value">{{ businessLicenseOcr.legalPerson }}</span>
+          </div>
+        </div>
+      </section>
+
+      <!-- 法定代表人证件 -->
+      <section class="form-block">
+        <h2 class="section-head">
+          <span class="section-bar" aria-hidden="true" />
+          法定代表人证件
+          <span class="section-intro">请上传法定代表人的证件信息</span>
+        </h2>
+
+        <el-form-item label="证件类型" prop="legalIdType">
+          <div class="field-stack">
+            <el-select v-model="form.legalIdType" placeholder="请选择" clearable style="width: 260px">
+              <el-option label="居民身份证" value="id_card" />
+              <el-option label="护照" value="passport" />
+              <el-option label="港澳居民来往内地通行证" value="hk_macau_pass" />
+              <el-option label="台湾居民来往大陆通行证" value="taiwan_pass" />
+            </el-select>
+            <p class="field-tip">若需变更受益人信息请</p>
+          </div>
+        </el-form-item>
+
+        <!-- 居民身份证:人像面 / 国徽面 -->
+        <template v-if="form.legalIdType === 'id_card'">
+          <el-form-item prop="idPortraitUrl">
+            <template #label>
+              <span class="label-with-icon">
+                身份证人像面照片
+                <el-tooltip placement="top" content="请上传身份证人像面(带头像一面)清晰彩色照片。">
+                  <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+                </el-tooltip>
+              </span>
+            </template>
+            <div class="license-upload-wrap">
+              <el-upload
+                v-model:file-list="form.idPortraitFileList"
+                list-type="picture-card"
+                :limit="1"
+                accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+                :before-upload="beforeLicenseUpload"
+                :http-request="opt => handleIdCardUpload(opt, 'portrait')"
+                :on-remove="(_f, fl) => onIdCardRemove(fl, 'portrait')"
+              >
+                <el-icon><Plus /></el-icon>
+              </el-upload>
+              <!-- <div class="license-example" aria-hidden="true">
+                <div class="license-example-thumb id-example-thumb">
+                  <span class="license-example-badge">示例</span>
+                  <span class="license-example-placeholder">人像面</span>
+                </div>
+              </div> -->
+            </div>
+            <div class="upload-rules">
+              <p>
+                1. 请上传彩色照片 or 彩色扫描件 or
+                加盖公章鲜章的复印件,要求正面拍摄,露出证件四角且清晰、完整,所有字符清晰可识别,不得反光或遮挡。不得翻拍、截图、镜像、PS。
+              </p>
+              <p>2. 图片只支持 JPG、BMP、PNG 格式,文件大小不能超过 5M。</p>
+            </div>
+          </el-form-item>
+
+          <el-form-item prop="idEmblemUrl">
+            <template #label>
+              <span class="label-with-icon">
+                身份证国徽面照片
+                <el-tooltip placement="top" content="请上传身份证国徽面清晰彩色照片。">
+                  <el-icon class="info-icon" :size="16"><InfoFilled /></el-icon>
+                </el-tooltip>
+              </span>
+            </template>
+            <div class="license-upload-wrap">
+              <el-upload
+                v-model:file-list="form.idEmblemFileList"
+                list-type="picture-card"
+                :limit="1"
+                accept=".jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp"
+                :before-upload="beforeLicenseUpload"
+                :http-request="opt => handleIdCardUpload(opt, 'emblem')"
+                :on-remove="(_f, fl) => onIdCardRemove(fl, 'emblem')"
+              >
+                <el-icon><Plus /></el-icon>
+              </el-upload>
+              <!-- <div class="license-example" aria-hidden="true">
+                <div class="license-example-thumb id-example-thumb">
+                  <span class="license-example-badge">示例</span>
+                  <span class="license-example-placeholder">国徽面</span>
+                </div>
+              </div> -->
+            </div>
+            <div class="upload-rules">
+              <p>
+                1. 请上传彩色照片 or 彩色扫描件 or
+                加盖公章鲜章的复印件,要求正面拍摄,露出证件四角且清晰、完整,所有字符清晰可识别,不得反光或遮挡。不得翻拍、截图、镜像、PS。
+              </p>
+              <p>2. 图片只支持 JPG、BMP、PNG 格式,文件大小不能超过 5M。</p>
+            </div>
+
+            <div v-if="showIdPortraitOcrBlock" class="ocr-result-container">
+              <div v-if="isIdPortraitOcrProcessing" class="ocr-result-item">
+                <span class="label">识别中:</span>
+                <span class="value">正在识别身份证信息,请稍候...</span>
+              </div>
+              <template v-else>
+                <div v-if="idPortraitOcr.name" class="ocr-result-item">
+                  <span class="label">姓名:</span>
+                  <span class="value">{{ idPortraitOcr.name }}</span>
+                </div>
+                <div v-if="idPortraitOcr.idNumber" class="ocr-result-item">
+                  <span class="label">身份证号:</span>
+                  <span class="value">{{ idPortraitOcr.idNumber }}</span>
+                </div>
+                <div v-if="idCardValidityDisplay" class="ocr-result-item">
+                  <span class="label">身份证有效期:</span>
+                  <span class="value">{{ idCardValidityDisplay }}</span>
+                </div>
+                <div v-if="!idPortraitOcr.name && !idPortraitOcr.idNumber && !idCardValidityDisplay" class="ocr-result-tip">
+                  请等待身份证识别完成
+                </div>
+              </template>
+            </div>
+          </el-form-item>
+
+          <p class="ubo-footer-tip">
+            平台将通过外部渠道核验该法人是否为受益人,若通过,将使用法人信息作为该主体的受益人(UBO)信息
+          </p>
+        </template>
+      </section>
+    </el-form>
+
+    <div class="footer-actions">
+      <el-button @click="onBack"> 返回 </el-button>
+      <el-button type="primary" class="btn-next" :loading="nextLoading" @click="onNext"> 下一步 </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import type { FormInstance, FormRules } from "element-plus";
+import type { UploadRequestOptions, UploadUserFile } from "element-plus";
+import { Plus, InfoFilled } from "@element-plus/icons-vue";
+import { getOcrRequestByBase64, getUpload } from "@/api/modules/businessInfo";
+import { localGet, localSet } from "@/utils/index";
+
+const BUSINESS_DATA_CACHE_KEY = "businessData";
+
+const formRef = ref<FormInstance>();
+const nextLoading = ref(false);
+const route = useRoute();
+const router = useRouter();
+
+const businessLicenseOcr = reactive({
+  creditCode: "",
+  companyName: "",
+  legalPerson: ""
+});
+
+const hasBusinessLicenseOcr = computed(
+  () => !!(businessLicenseOcr.creditCode || businessLicenseOcr.companyName || businessLicenseOcr.legalPerson)
+);
+
+function clearBusinessLicenseOcr() {
+  businessLicenseOcr.creditCode = "";
+  businessLicenseOcr.companyName = "";
+  businessLicenseOcr.legalPerson = "";
+}
+
+/** 从 ocrRequestByBase64 成功响应中取出 creditCode / companyName / legalPerson */
+function pickBusinessLicenseOcrFields(res: any) {
+  const raw = res?.data ?? res;
+  let node: any = raw;
+  if (node && typeof node === "object" && "data" in node && node.data !== undefined) {
+    node = node.data;
+  }
+  const item = Array.isArray(node) ? node[0] : node;
+  if (!item || typeof item !== "object") {
+    return { creditCode: "", companyName: "", legalPerson: "" };
+  }
+  return {
+    creditCode: String(item.creditCode ?? item.credit_code ?? "").trim(),
+    companyName: String(item.companyName ?? item.company_name ?? "").trim(),
+    legalPerson: String(item.legalPerson ?? item.legal_person ?? "").trim()
+  };
+}
+
+/** 身份证有效期文案 → YYYY-MM-DD */
+function splitIdCardValidPeriod(raw: string): { begin: string; end: string } {
+  const s = (raw || "").trim();
+  if (!s) return { begin: "", end: "" };
+  if (/长期|长期有效/.test(s)) return { begin: "", end: "长期" };
+  const norm = s
+    .replace(/年|月|日/g, ".")
+    .replace(/\.+/g, ".")
+    .trim();
+  const parts = norm.split(/[-至~~]/);
+  const normOne = (p: string) => {
+    const m = p.trim().match(/(\d{4})\D*(\d{1,2})\D*(\d{1,2})/);
+    if (m) return `${m[1]}-${m[2].padStart(2, "0")}-${m[3].padStart(2, "0")}`;
+    return p.trim();
+  };
+  if (parts.length >= 2) {
+    return { begin: normOne(parts[0]), end: normOne(parts[1]) };
+  }
+  return { begin: "", end: "" };
+}
+
+/** 人像面 getOcrRequestByBase64(ID_CARD) 成功响应 */
+function pickIdCardPortraitOcrFields(res: any): {
+  name: string;
+  idNumber: string;
+  idCardAddress: string;
+  cardPeriodBegin: string;
+  cardPeriodEnd: string;
+} {
+  const raw = res?.data ?? res;
+  let node: any = raw;
+  if (node && typeof node === "object" && "data" in node && node.data !== undefined) {
+    node = node.data;
+  }
+  const arr = Array.isArray(node) ? node : [node];
+  const item = arr[0];
+  const item2 = arr[1];
+  if (!item || typeof item !== "object") {
+    return { name: "", idNumber: "", idCardAddress: "", cardPeriodBegin: "", cardPeriodEnd: "" };
+  }
+  let name = String(item.name ?? item.userName ?? "").trim();
+  let idNumber = String(item.idNumber ?? item.id_number ?? item.idCard ?? item.id_card ?? "").trim();
+  const faceData = item.face?.data || item2?.face?.data;
+  const backData = item.back?.data || item2?.back?.data;
+  if (faceData && typeof faceData === "object") {
+    if (!name) name = String(faceData.name ?? "").trim();
+    if (!idNumber) idNumber = String(faceData.idNumber ?? faceData.id_number ?? "").trim();
+  }
+  let idCardAddress = "";
+  if (backData && typeof backData === "object") {
+    idCardAddress = String(backData.address ?? backData.registeredAddress ?? backData.issueAuthority ?? "").trim();
+  }
+  if (faceData && typeof faceData === "object" && !idCardAddress) {
+    idCardAddress = String(faceData.address ?? "").trim();
+  }
+  const faceKv = item.face?.prism_keyValueInfo || item2?.face?.prism_keyValueInfo;
+  if (Array.isArray(faceKv)) {
+    for (const row of faceKv) {
+      if (row?.key === "name" && row?.value && !name) name = String(row.value).trim();
+      if (row?.key === "idNumber" && row?.value && !idNumber) idNumber = String(row.value).trim();
+      if (row?.key === "address" && row?.value && !idCardAddress) {
+        idCardAddress = String(row.value).trim();
+      }
+    }
+  }
+  const backKv = item.back?.prism_keyValueInfo || item2?.back?.prism_keyValueInfo;
+  let validPeriodFromKv = "";
+  if (Array.isArray(backKv)) {
+    for (const row of backKv) {
+      if (row?.key === "address" && row?.value && !idCardAddress) {
+        idCardAddress = String(row.value).trim();
+      }
+      if (row?.value) {
+        const keyRaw = String(row.key || "");
+        if (/有效期限|有效期|失效日期|签发日期|validPeriod|validDate|valid_period/i.test(keyRaw)) {
+          const v = String(row.value).trim();
+          if (v && !validPeriodFromKv) validPeriodFromKv = v;
+        }
+      }
+    }
+  }
+  let vp = String(
+    (backData && (backData.validPeriod ?? backData.validDate)) ||
+      (faceData && (faceData.validPeriod ?? faceData.validDate)) ||
+      (item && (item.validPeriod ?? item.validDate)) ||
+      (item2 && (item2.validPeriod ?? item2.validDate)) ||
+      ""
+  ).trim();
+  if (!vp && validPeriodFromKv) vp = validPeriodFromKv;
+  const { begin: cardPeriodBegin, end: cardPeriodEnd } = splitIdCardValidPeriod(vp);
+  return { name, idNumber, idCardAddress, cardPeriodBegin, cardPeriodEnd };
+}
+
+const form = reactive<{
+  isFinancialInstitution: number;
+  businessLicenseFileList: UploadUserFile[];
+  businessLicenseUrl: string;
+  legalIdType: string;
+  idPortraitFileList: UploadUserFile[];
+  idEmblemFileList: UploadUserFile[];
+  idPortraitUrl: string;
+  idEmblemUrl: string;
+}>({
+  isFinancialInstitution: 0,
+  businessLicenseFileList: [],
+  businessLicenseUrl: "",
+  legalIdType: "id_card",
+  idPortraitFileList: [],
+  idEmblemFileList: [],
+  idPortraitUrl: "",
+  idEmblemUrl: ""
+});
+
+const idPortraitOcr = reactive({
+  name: "",
+  idNumber: "",
+  idCardAddress: "",
+  cardPeriodBegin: "",
+  cardPeriodEnd: ""
+});
+
+const isIdPortraitOcrProcessing = ref(false);
+
+const hasPortraitUploadSuccess = computed(() => {
+  const f = form.idPortraitFileList[0];
+  return f?.status === "success";
+});
+
+const hasEmblemUploadSuccess = computed(() => {
+  const f = form.idEmblemFileList[0];
+  return f?.status === "success";
+});
+
+/** 身份证有效期展示(国徽面 OCR 主要提供) */
+const idCardValidityDisplay = computed(() => {
+  const b = (idPortraitOcr.cardPeriodBegin || "").trim();
+  const e = (idPortraitOcr.cardPeriodEnd || "").trim();
+  if (b && e) return e === "长期" ? `${b} 至 长期` : `${b} 至 ${e}`;
+  if (e === "长期" && !b) return "长期";
+  if (b && !e) return b;
+  if (!b && e) return e;
+  return "";
+});
+
+const hasIdPortraitOcrDisplay = computed(() => !!(idPortraitOcr.name || idPortraitOcr.idNumber || idCardValidityDisplay.value));
+
+const showIdPortraitOcrBlock = computed(
+  () =>
+    form.legalIdType === "id_card" &&
+    (hasPortraitUploadSuccess.value ||
+      hasEmblemUploadSuccess.value ||
+      isIdPortraitOcrProcessing.value ||
+      hasIdPortraitOcrDisplay.value)
+);
+
+function clearIdPortraitOcr() {
+  idPortraitOcr.name = "";
+  idPortraitOcr.idNumber = "";
+  idPortraitOcr.idCardAddress = "";
+  idPortraitOcr.cardPeriodBegin = "";
+  idPortraitOcr.cardPeriodEnd = "";
+}
+
+function buildSubjectInfoForBusinessData(): {
+  contact_type: "LEGAL";
+  subject_type: "SUBJECT_TYPE_ENTERPRISE" | "SUBJECT_TYPE_INDIVIDUAL";
+  business_license_info: {
+    license_copy: string;
+    license_number: string;
+    merchant_name: string;
+    legal_person: string;
+  };
+  identity_info: {
+    id_doc_type: string;
+    id_holder_type: "LEGAL";
+    id_card_info: {
+      id_card_copy: string;
+      id_card_national: string;
+      id_card_name: string;
+      id_card_number: string;
+      id_card_address: string;
+      card_period_begin: string;
+      card_period_end: string;
+    };
+  };
+} {
+  const cached = localGet(BUSINESS_DATA_CACHE_KEY) as { entityType?: string } | null | undefined;
+  const entityType = String(
+    (cached && typeof cached === "object" && cached.entityType) ||
+      (typeof route.query.entityType === "string" ? route.query.entityType : "") ||
+      ""
+  ).trim();
+  /** 企业 → SUBJECT_TYPE_ENTERPRISE;个体工商户(entityType=individual)及其他默认 → SUBJECT_TYPE_INDIVIDUAL */
+  const subject_type = entityType === "enterprise" ? ("SUBJECT_TYPE_ENTERPRISE" as const) : ("SUBJECT_TYPE_INDIVIDUAL" as const);
+
+  return {
+    contact_type: "LEGAL" as const,
+    subject_type,
+    business_license_info: {
+      license_copy: (form.businessLicenseUrl || "").trim(),
+      license_number: (businessLicenseOcr.creditCode || "").trim(),
+      merchant_name: (businessLicenseOcr.companyName || "").trim(),
+      legal_person: (businessLicenseOcr.legalPerson || "").trim()
+    },
+    identity_info: {
+      id_doc_type: "IDENTIFICATION_TYPE_IDCARD",
+      id_holder_type: "LEGAL" as const,
+      id_card_info: {
+        id_card_copy: (form.idPortraitUrl || "").trim(),
+        id_card_national: (form.idEmblemUrl || "").trim(),
+        id_card_name: (idPortraitOcr.name || "").trim(),
+        id_card_number: (idPortraitOcr.idNumber || "").trim(),
+        id_card_address: (idPortraitOcr.idCardAddress || "").trim(),
+        card_period_begin: (idPortraitOcr.cardPeriodBegin || "").trim(),
+        card_period_end: (idPortraitOcr.cardPeriodEnd || "").trim()
+      }
+    }
+  };
+}
+
+function mergeSubjectInfoIntoBusinessDataCache() {
+  const prev = localGet(BUSINESS_DATA_CACHE_KEY);
+  const base = prev && typeof prev === "object" && !Array.isArray(prev) ? { ...(prev as Record<string, unknown>) } : {};
+  base.subject_info = buildSubjectInfoForBusinessData();
+  localSet(BUSINESS_DATA_CACHE_KEY, base);
+}
+
+function mapApiIdDocTypeToLegalId(apiType: unknown): string {
+  const s = String(apiType || "").trim();
+  switch (s) {
+    case "IDENTIFICATION_TYPE_IDCARD":
+      return "id_card";
+    case "IDENTIFICATION_TYPE_OVERSEA_PASSPORT":
+      return "passport";
+    case "IDENTIFICATION_TYPE_HONGKONG_PASSPORT":
+    case "IDENTIFICATION_TYPE_MACAO_PASSPORT":
+      return "hk_macau_pass";
+    case "IDENTIFICATION_TYPE_TAIWAN_PASSPORT":
+      return "taiwan_pass";
+    default:
+      if (/IDCARD|ID_CARD/i.test(s)) return "id_card";
+      return "id_card";
+  }
+}
+
+/** 从 localStorage businessData.subject_info 回显本页表单与 OCR 展示 */
+function hydrateSubjectFormFromBusinessDataCache() {
+  const raw = localGet(BUSINESS_DATA_CACHE_KEY) as Record<string, unknown> | null | undefined;
+  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
+  const si = raw.subject_info as Record<string, unknown> | undefined;
+  if (!si || typeof si !== "object" || Array.isArray(si)) return;
+
+  const bli = si.business_license_info as Record<string, unknown> | undefined;
+  if (bli && typeof bli === "object" && !Array.isArray(bli)) {
+    const lic = String(bli.license_copy ?? "").trim();
+    if (lic) {
+      form.businessLicenseUrl = lic;
+      form.businessLicenseFileList = [{ name: "license.jpg", url: lic, status: "success" } as UploadUserFile];
+    } else {
+      form.businessLicenseUrl = "";
+      form.businessLicenseFileList = [];
+    }
+    businessLicenseOcr.creditCode = String(bli.license_number ?? "").trim();
+    businessLicenseOcr.companyName = String(bli.merchant_name ?? "").trim();
+    businessLicenseOcr.legalPerson = String(bli.legal_person ?? "").trim();
+  }
+
+  const ii = si.identity_info as Record<string, unknown> | undefined;
+  if (ii && typeof ii === "object" && !Array.isArray(ii)) {
+    if (String(ii.id_doc_type ?? "").trim()) {
+      form.legalIdType = mapApiIdDocTypeToLegalId(ii.id_doc_type);
+    }
+    const ici = ii.id_card_info as Record<string, unknown> | undefined;
+    if (ici && typeof ici === "object" && !Array.isArray(ici)) {
+      const copy = String(ici.id_card_copy ?? "").trim();
+      const nat = String(ici.id_card_national ?? "").trim();
+      if (copy) {
+        form.idPortraitUrl = copy;
+        form.idPortraitFileList = [{ name: "id-portrait.jpg", url: copy, status: "success" } as UploadUserFile];
+      } else {
+        form.idPortraitUrl = "";
+        form.idPortraitFileList = [];
+      }
+      if (nat) {
+        form.idEmblemUrl = nat;
+        form.idEmblemFileList = [{ name: "id-emblem.jpg", url: nat, status: "success" } as UploadUserFile];
+      } else {
+        form.idEmblemUrl = "";
+        form.idEmblemFileList = [];
+      }
+      idPortraitOcr.name = String(ici.id_card_name ?? "").trim();
+      idPortraitOcr.idNumber = String(ici.id_card_number ?? "").trim();
+      idPortraitOcr.idCardAddress = String(ici.id_card_address ?? "").trim();
+      idPortraitOcr.cardPeriodBegin = String(ici.card_period_begin ?? "").trim();
+      idPortraitOcr.cardPeriodEnd = String(ici.card_period_end ?? "").trim();
+    }
+  }
+
+  nextTick(() => {
+    formRef.value?.clearValidate();
+  });
+}
+
+const rules: FormRules = {
+  businessLicenseUrl: [
+    {
+      required: true,
+      validator: (_r, _v, cb) => {
+        if (!form.businessLicenseUrl?.trim()) {
+          cb(new Error("请上传营业执照照片"));
+        } else {
+          cb();
+        }
+      },
+      trigger: "change"
+    }
+  ],
+  legalIdType: [{ required: true, message: "请选择证件类型", trigger: "change" }],
+  idPortraitUrl: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.legalIdType === "id_card" && !form.idPortraitUrl?.trim()) {
+          cb(new Error("请上传身份证人像面照片"));
+        } else {
+          cb();
+        }
+      },
+      trigger: "change"
+    }
+  ],
+  idEmblemUrl: [
+    {
+      validator: (_r, _v, cb) => {
+        if (form.legalIdType === "id_card" && !form.idEmblemUrl?.trim()) {
+          cb(new Error("请上传身份证国徽面照片"));
+        } else {
+          cb();
+        }
+      },
+      trigger: "change"
+    }
+  ]
+};
+
+watch(
+  () => form.legalIdType,
+  v => {
+    if (v !== "id_card") {
+      form.idPortraitUrl = "";
+      form.idEmblemUrl = "";
+      form.idPortraitFileList = [];
+      form.idEmblemFileList = [];
+      clearIdPortraitOcr();
+    }
+  }
+);
+
+const MAX_LICENSE_MB = 5;
+
+function beforeLicenseUpload(file: File) {
+  const name = file.name?.toLowerCase() || "";
+  const okExt = /\.(jpe?g|png|bmp)$/i.test(name);
+  const okMime = ["image/jpeg", "image/png", "image/bmp"].includes(file.type);
+  if (!okExt && !okMime) {
+    ElMessage.error("图片只支持 JPG、BMP、PNG 格式");
+    return false;
+  }
+  const sizeMb = file.size / 1024 / 1024;
+  if (sizeMb > MAX_LICENSE_MB) {
+    ElMessage.error(`文件大小不能超过 ${MAX_LICENSE_MB}M`);
+    return false;
+  }
+  return true;
+}
+
+/** 与 getUpload(微信 media/upload)返回结构对齐 */
+function parseMediaUploadResult(res: any): { fileUrl: string; mediaId: string; errMsg: string } {
+  const envelope = res?.data ?? res;
+  const body = envelope?.data !== undefined ? envelope.data : envelope;
+  const fileUrl =
+    body?.url ??
+    body?.fileUrl ??
+    envelope?.url ??
+    envelope?.data?.url ??
+    envelope?.data?.fileUrl ??
+    body?.mediaUrl ??
+    body?.data?.mediaUrl ??
+    "";
+  const mediaId =
+    body?.media_id ?? body?.mediaId ?? envelope?.media_id ?? envelope?.data?.media_id ?? envelope?.data?.mediaId ?? "";
+  const errMsg = envelope?.msg ?? body?.msg ?? res?.msg ?? "";
+  return { fileUrl, mediaId, errMsg };
+}
+
+function mergeIdCardOcrFromFields(fields: ReturnType<typeof pickIdCardPortraitOcrFields>, mode: "portrait" | "emblem") {
+  if (mode === "portrait") {
+    if (fields.name) idPortraitOcr.name = fields.name;
+    if (fields.idNumber) idPortraitOcr.idNumber = fields.idNumber;
+    if (fields.idCardAddress) idPortraitOcr.idCardAddress = fields.idCardAddress;
+    if (fields.cardPeriodBegin) idPortraitOcr.cardPeriodBegin = fields.cardPeriodBegin;
+    if (fields.cardPeriodEnd) idPortraitOcr.cardPeriodEnd = fields.cardPeriodEnd;
+  } else {
+    if (fields.cardPeriodBegin) idPortraitOcr.cardPeriodBegin = fields.cardPeriodBegin;
+    if (fields.cardPeriodEnd) idPortraitOcr.cardPeriodEnd = fields.cardPeriodEnd;
+    if (fields.idCardAddress) idPortraitOcr.idCardAddress = fields.idCardAddress;
+  }
+}
+
+async function requestIdCardPortraitOcr(file: File) {
+  const formData = new FormData();
+  formData.append("imageFile", file, file.name || "id-portrait.jpg");
+  formData.append("ocrType", "ID_CARD");
+  isIdPortraitOcrProcessing.value = true;
+  try {
+    const res: any = await getOcrRequestByBase64(formData);
+    if (res?.code === 200 || res?.code === "200") {
+      const fields = pickIdCardPortraitOcrFields(res);
+      mergeIdCardOcrFromFields(fields, "portrait");
+      ElMessage.success("身份证人像面识别成功");
+    } else {
+      clearIdPortraitOcr();
+      ElMessage.warning(res?.msg || "身份证人像面识别未通过,请核对照片清晰度");
+    }
+  } finally {
+    isIdPortraitOcrProcessing.value = false;
+  }
+}
+
+/** 国徽面单独 OCR,合并有效期限(及背面地址等),不清空人像面已识别字段 */
+async function requestIdCardEmblemOcr(file: File) {
+  const formData = new FormData();
+  formData.append("imageFile", file, file.name || "id-emblem.jpg");
+  formData.append("ocrType", "ID_CARD");
+  isIdPortraitOcrProcessing.value = true;
+  try {
+    const res: any = await getOcrRequestByBase64(formData);
+    if (res?.code === 200 || res?.code === "200") {
+      const fields = pickIdCardPortraitOcrFields(res);
+      mergeIdCardOcrFromFields(fields, "emblem");
+      if (fields.cardPeriodBegin || fields.cardPeriodEnd) {
+        ElMessage.success("身份证国徽面识别成功");
+      } else {
+        ElMessage.warning("未识别到有效期限,请确认国徽面照片清晰完整");
+      }
+    } else {
+      ElMessage.warning(res?.msg || "身份证国徽面识别未通过,请核对照片清晰度");
+    }
+  } finally {
+    isIdPortraitOcrProcessing.value = false;
+  }
+}
+
+async function requestBusinessLicenseOcr(file: File) {
+  const formData = new FormData();
+  formData.append("imageFile", file, file.name || "license.jpg");
+  formData.append("ocrType", "BUSINESS_LICENSE");
+  const res: any = await getOcrRequestByBase64(formData);
+  if (res?.code === 200 || res?.code === "200") {
+    const fields = pickBusinessLicenseOcrFields(res);
+    businessLicenseOcr.creditCode = fields.creditCode;
+    businessLicenseOcr.companyName = fields.companyName;
+    businessLicenseOcr.legalPerson = fields.legalPerson;
+    ElMessage.success("营业执照识别成功");
+  } else {
+    clearBusinessLicenseOcr();
+    ElMessage.warning(res?.msg || "营业执照识别未通过,请核对照片清晰度");
+  }
+}
+
+async function handleLicenseUpload(options: UploadRequestOptions) {
+  const uploadFileItem = options.file as UploadUserFile;
+  const raw = uploadFileItem.raw || uploadFileItem;
+  const file = raw instanceof File ? raw : null;
+  if (!file) return;
+
+  uploadFileItem.status = "uploading";
+  try {
+    const formData = new FormData();
+    formData.append("file", file);
+    const res: any = await getUpload(formData);
+    const { fileUrl, mediaId, errMsg } = parseMediaUploadResult(res);
+
+    if (fileUrl || mediaId) {
+      uploadFileItem.status = "success";
+      if (fileUrl) {
+        uploadFileItem.url = fileUrl;
+      }
+      uploadFileItem.response = { media_id: mediaId, url: fileUrl };
+      form.businessLicenseUrl = fileUrl || mediaId;
+      try {
+        await requestBusinessLicenseOcr(file);
+      } catch {
+        clearBusinessLicenseOcr();
+        ElMessage.warning("营业执照识别服务暂时不可用,请稍后重试");
+      }
+    } else {
+      uploadFileItem.status = "fail";
+      ElMessage.error(errMsg || "上传失败,未返回可用结果");
+    }
+  } catch {
+    uploadFileItem.status = "fail";
+  }
+  formRef.value?.validateField("businessLicenseUrl").catch(() => {});
+}
+
+function onLicenseRemove(_file: UploadUserFile, fileList: UploadUserFile[]) {
+  if (!fileList.length) {
+    form.businessLicenseUrl = "";
+    clearBusinessLicenseOcr();
+  } else {
+    const first = fileList[0] as UploadUserFile & { url?: string; response?: { url?: string } };
+    form.businessLicenseUrl = first?.url || first?.response?.url || "";
+  }
+  formRef.value?.validateField("businessLicenseUrl").catch(() => {});
+}
+
+type IdCardSide = "portrait" | "emblem";
+
+async function handleIdCardUpload(options: UploadRequestOptions, side: IdCardSide) {
+  const uploadFileItem = options.file as UploadUserFile;
+  const raw = uploadFileItem.raw || uploadFileItem;
+  const file = raw instanceof File ? raw : null;
+  if (!file) return;
+
+  uploadFileItem.status = "uploading";
+  try {
+    const formData = new FormData();
+    formData.append("file", file);
+    const res: any = await getUpload(formData);
+    const { fileUrl, mediaId, errMsg } = parseMediaUploadResult(res);
+
+    if (fileUrl || mediaId) {
+      uploadFileItem.status = "success";
+      if (fileUrl) {
+        uploadFileItem.url = fileUrl;
+      }
+      uploadFileItem.response = { media_id: mediaId, url: fileUrl };
+      const stored = fileUrl || mediaId;
+      if (side === "portrait") {
+        form.idPortraitUrl = stored;
+        try {
+          await requestIdCardPortraitOcr(file);
+        } catch {
+          clearIdPortraitOcr();
+          ElMessage.warning("身份证识别服务暂时不可用,请稍后重试");
+        }
+      } else {
+        form.idEmblemUrl = stored;
+        try {
+          await requestIdCardEmblemOcr(file);
+        } catch {
+          ElMessage.warning("身份证国徽面识别服务暂时不可用,请稍后重试");
+        }
+      }
+    } else {
+      uploadFileItem.status = "fail";
+      ElMessage.error(errMsg || "上传失败,未返回可用结果");
+    }
+  } catch {
+    uploadFileItem.status = "fail";
+  }
+  const field = side === "portrait" ? "idPortraitUrl" : "idEmblemUrl";
+  formRef.value?.validateField(field).catch(() => {});
+}
+
+function onIdCardRemove(fileList: UploadUserFile[], side: IdCardSide) {
+  if (!fileList.length) {
+    if (side === "portrait") {
+      form.idPortraitUrl = "";
+      clearIdPortraitOcr();
+    } else {
+      form.idEmblemUrl = "";
+      idPortraitOcr.cardPeriodBegin = "";
+      idPortraitOcr.cardPeriodEnd = "";
+    }
+  } else {
+    const first = fileList[0] as UploadUserFile & {
+      url?: string;
+      response?: { url?: string; media_id?: string; mediaId?: string };
+    };
+    const r = first?.response;
+    const stored = first?.url || r?.url || r?.media_id || r?.mediaId || "";
+    if (side === "portrait") form.idPortraitUrl = stored;
+    else form.idEmblemUrl = stored;
+  }
+  const field = side === "portrait" ? "idPortraitUrl" : "idEmblemUrl";
+  formRef.value?.validateField(field).catch(() => {});
+}
+
+/** 从草稿/详情接口 URL 还原身份证上传展示(可在外部拉取数据后调用) */
+function restoreIdCardFromUrls(portraitUrl?: string | null, emblemUrl?: string | null) {
+  if (portraitUrl) {
+    form.idPortraitUrl = portraitUrl;
+    form.idPortraitFileList = [{ name: "id-portrait.jpg", url: portraitUrl, status: "success" } as UploadUserFile];
+  }
+  if (emblemUrl) {
+    form.idEmblemUrl = emblemUrl;
+    form.idEmblemFileList = [{ name: "id-emblem.jpg", url: emblemUrl, status: "success" } as UploadUserFile];
+  }
+}
+
+onMounted(() => {
+  hydrateSubjectFormFromBusinessDataCache();
+  const q = route.query as Record<string, string | string[] | undefined>;
+  const pu = typeof q.idPortraitUrl === "string" ? q.idPortraitUrl : undefined;
+  const eu = typeof q.idEmblemUrl === "string" ? q.idEmblemUrl : undefined;
+  if (pu && !form.idPortraitUrl?.trim()) {
+    form.legalIdType = "id_card";
+    restoreIdCardFromUrls(pu, undefined);
+  }
+  if (eu && !form.idEmblemUrl?.trim()) {
+    form.legalIdType = "id_card";
+    restoreIdCardFromUrls(undefined, eu);
+  }
+});
+
+defineExpose({ restoreIdCardFromUrls, hydrateSubjectFormFromBusinessDataCache });
+
+function onModifyUbo() {
+  ElMessage.info("受益人信息修改入口可在此对接");
+}
+
+function onBack() {
+  router.push({
+    path: "/businessInfo/dataEntry",
+    query: { ...route.query }
+  });
+}
+
+function onSaveDraft() {
+  ElMessage.success("草稿已保存(可对接接口)");
+}
+
+async function onNext() {
+  if (!formRef.value) return;
+  nextLoading.value = true;
+  try {
+    await formRef.value.validate();
+    mergeSubjectInfoIntoBusinessDataCache();
+    await router.push({
+      path: "/businessInfo/manageInfo",
+      query: { ...route.query }
+    });
+  } catch {
+    ElMessage.warning("请完善必填信息");
+  } finally {
+    nextLoading.value = false;
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$wechat-green: #07c160;
+.subject-info-page {
+  box-sizing: border-box;
+  min-height: 100%;
+  padding: 24px 32px 40px;
+  margin: 0 auto;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 24px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.subject-form {
+  :deep(.el-form-item__label) {
+    font-weight: 500;
+    color: #606266;
+  }
+}
+.form-block {
+  padding-bottom: 8px;
+  margin-bottom: 28px;
+  border-bottom: 1px solid #ebeef5;
+  &:last-of-type {
+    border-bottom: none;
+  }
+}
+.section-head {
+  display: flex;
+  align-items: center;
+  margin: 0 0 16px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+}
+.section-bar {
+  display: inline-block;
+  flex-shrink: 0;
+  width: 4px;
+  height: 16px;
+  margin-right: 8px;
+  background: $wechat-green;
+  border-radius: 2px;
+}
+.section-intro {
+  padding-left: 20px;
+  font-size: 13px;
+  line-height: 1.65;
+  color: #909399;
+}
+.field-stack {
+  width: 100%;
+}
+.field-tip {
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+}
+.label-with-icon {
+  display: inline-flex;
+  gap: 4px;
+  align-items: center;
+}
+.info-icon {
+  color: #909399;
+  cursor: help;
+}
+.license-upload-wrap {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  align-items: flex-start;
+}
+.license-example {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+.license-example-label {
+  font-size: 12px;
+  color: #909399;
+}
+.license-example-thumb {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 148px;
+  height: 148px;
+  background: #f5f7fa;
+  border: 1px dashed #dcdfe6;
+  border-radius: 6px;
+}
+.license-example-placeholder {
+  font-size: 12px;
+  color: #c0c4cc;
+}
+.id-example-thumb {
+  position: relative;
+}
+.license-example-badge {
+  position: absolute;
+  top: 6px;
+  right: 6px;
+  padding: 2px 6px;
+  font-size: 11px;
+  color: #ffffff;
+  background: rgb(0 0 0 / 45%);
+  border-radius: 4px;
+}
+.ubo-footer-tip {
+  padding: 12px 0 0;
+  margin: 8px 0 0;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+  border-top: 1px dashed #ebeef5;
+}
+:deep(.el-form-item__content) {
+  display: block;
+}
+.upload-rules {
+  margin-top: 12px;
+  font-size: 12px;
+  line-height: 1.65;
+  color: #909399;
+  p {
+    margin: 0 0 6px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+}
+.ocr-result-container {
+  max-width: 640px;
+  padding: 14px 16px;
+  margin-top: 12px;
+  background: #f5f7fa;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+}
+.ocr-result-item {
+  display: flex;
+  gap: 12px;
+  align-items: flex-start;
+  margin-bottom: 10px;
+  font-size: 13px;
+  line-height: 1.5;
+  &:last-child {
+    margin-bottom: 0;
+  }
+  .label {
+    flex-shrink: 0;
+    min-width: 88px;
+    font-weight: 600;
+    color: #606266;
+  }
+  .value {
+    flex: 1;
+    color: #303133;
+    word-break: break-all;
+  }
+}
+.ocr-result-tip {
+  font-size: 13px;
+  line-height: 1.5;
+  color: #909399;
+}
+.license-ocr-result {
+  max-width: 640px;
+  padding: 14px 16px;
+  margin-top: 12px;
+  margin-left: 140px;
+  background: #f5f7fa;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+}
+.license-ocr-row {
+  display: flex;
+  gap: 12px;
+  align-items: flex-start;
+  margin-bottom: 10px;
+  font-size: 13px;
+  line-height: 1.5;
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+.license-ocr-label {
+  flex-shrink: 0;
+  width: 132px;
+  font-weight: 600;
+  color: #606266;
+}
+.license-ocr-value {
+  flex: 1;
+  color: #303133;
+  word-break: break-all;
+}
+:deep(.el-upload--picture-card) {
+  --el-upload-picture-card-size: 148px;
+}
+:deep(.el-upload-list--picture-card .el-upload-list__item) {
+  width: 148px;
+  height: 148px;
+}
+.footer-actions {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+  margin-top: 8px;
+  border-top: 1px solid #ebeef5;
+}
+.footer-center {
+  display: flex;
+  flex: 1;
+  justify-content: center;
+}
+.btn-next {
+  min-width: 100px;
+  background: $wechat-green;
+  border-color: $wechat-green;
+  &:hover {
+    background: #06ad56;
+    border-color: #06ad56;
+  }
+}
+</style>

+ 266 - 0
src/views/businessInfo/weChartExamine.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="table-box we-chart-examine-page">
+    <h1 class="page-title">查看微信审核</h1>
+
+    <el-alert v-if="loadError" class="mb-16" type="warning" :closable="false" show-icon :title="loadError" />
+
+    <ProTable row-key="_rowKey" :columns="columns" :request-api="getExamineList" :init-param="initParam" :pagination="false">
+      <template #signUrl="scope">
+        <el-link v-if="isHttpUrl(scope.row.signUrl)" :href="scope.row.signUrl" target="_blank" type="primary">
+          {{ scope.row.signUrl }}
+        </el-link>
+        <span v-else>{{ scope.row.signUrl }}</span>
+      </template>
+    </ProTable>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import { useRoute } from "vue-router";
+import ProTable from "@/components/ProTable/index.vue";
+import type { ColumnProps } from "@/components/ProTable/interface";
+import { localGet } from "@/utils/index";
+import { applymentExamine } from "@/api/modules/businessInfo";
+
+const GEEKER_USER_KEY = "geeker-user";
+
+type ExamineDisplayRow = {
+  id: string;
+  applymentNo: string;
+  signUrl: string;
+  applymentState: string;
+  rejectReason: string;
+  _rowKey: string;
+};
+
+const KEY_ID = ["id", "Id", "_id"];
+const KEY_APPLYMENT_NO = ["applyment_id", "applymentId", "out_request_no", "outRequestNo", "business_code", "businessCode"];
+const KEY_SIGN = ["sign_url", "signUrl"];
+const KEY_REJECT = ["reject_reason", "rejectReason"];
+
+/** 微信支付子商户进件申请单状态 → 中文 */
+const APPLYMENT_STATE_LABEL: Record<string, string> = {
+  APPLYMENT_STATE_EDITTING: "编辑中",
+  APPLYMENT_STATE_EDITING: "编辑中",
+  APPLYMENT_STATE_AUDITING: "审核中",
+  APPLYMENT_STATE_REJECTED: "已驳回",
+  APPLYMENT_STATE_TO_BE_CONFIRMED: "待账户验证",
+  APPLYMENT_STATE_TO_BE_SIGNED: "待签约",
+  APPLYMENT_STATE_SIGNING: "开通权限中",
+  APPLYMENT_STATE_FINISHED: "已完成",
+  APPLYMENT_STATE_CANCELED: "已作废"
+};
+
+function formatApplymentStateLabel(raw: string): string {
+  const t = String(raw ?? "").trim();
+  if (!t || t === "—") return "—";
+  const upper = t.toUpperCase().replace(/\s+/g, "_");
+  if (APPLYMENT_STATE_LABEL[upper]) return APPLYMENT_STATE_LABEL[upper];
+  if (APPLYMENT_STATE_LABEL[t]) return APPLYMENT_STATE_LABEL[t];
+  return t;
+}
+
+function pickApplymentStateRaw(row: Record<string, unknown>): string {
+  const codeKeys = ["applyment_state", "applymentState"] as const;
+  for (const k of codeKeys) {
+    if (Object.prototype.hasOwnProperty.call(row, k)) {
+      const v = row[k];
+      if (v !== undefined && v !== null && v !== "") {
+        return String(v).trim();
+      }
+    }
+  }
+  const descKeys = ["applyment_state_desc", "applymentStateDesc"] as const;
+  for (const k of descKeys) {
+    if (Object.prototype.hasOwnProperty.call(row, k)) {
+      const v = row[k];
+      if (v !== undefined && v !== null && v !== "") {
+        return String(v).trim();
+      }
+    }
+  }
+  return "";
+}
+
+function resolveApplymentStoreId(): string | number | null {
+  const geeker = localGet(GEEKER_USER_KEY) as { userInfo?: { storeId?: string | number | null } } | null | undefined;
+  const sid = geeker?.userInfo?.storeId ?? localGet("createdId");
+  if (sid === undefined || sid === null || sid === "") return null;
+  return sid;
+}
+
+const route = useRoute();
+
+function resolveStoreIdParam(): string | number | null {
+  const q = route.query.storeId;
+  if (q !== undefined && q !== null && q !== "") {
+    const s = (Array.isArray(q) ? q[0] : q) as string;
+    if (s) {
+      const n = Number(s);
+      return Number.isNaN(n) ? s : n;
+    }
+  }
+  return resolveApplymentStoreId();
+}
+
+const loadError = ref("");
+
+const initParam = reactive({
+  storeId: localGet(GEEKER_USER_KEY)?.userInfo?.storeId ?? localGet("createdId") ?? ""
+});
+
+const columns: ColumnProps<ExamineDisplayRow>[] = [
+  { prop: "id", label: "ID", width: 100, align: "center" },
+  { prop: "applymentNo", label: "申请单编号", minWidth: 180 },
+  { prop: "signUrl", label: "签约链接", minWidth: 220 },
+  { prop: "applymentState", label: "申请状态", minWidth: 140 },
+  { prop: "rejectReason", label: "驳回原因", minWidth: 200 }
+];
+
+function formatCell(v: unknown): string {
+  if (v === null || v === undefined || v === "") return "—";
+  if (typeof v === "object") {
+    try {
+      return JSON.stringify(v);
+    } catch {
+      return String(v);
+    }
+  }
+  return String(v);
+}
+
+function isHttpUrl(s: string): boolean {
+  if (!s || s === "—") return false;
+  return /^https?:\/\//i.test(s.trim());
+}
+
+function pickField(row: Record<string, unknown>, keys: string[]): string {
+  for (const k of keys) {
+    if (Object.prototype.hasOwnProperty.call(row, k)) {
+      const v = row[k];
+      if (v !== undefined && v !== null && v !== "") {
+        return formatCell(v);
+      }
+    }
+  }
+  return "—";
+}
+
+function normalizeRow(row: Record<string, unknown>): Omit<ExamineDisplayRow, "_rowKey"> {
+  const stateRaw = pickApplymentStateRaw(row);
+  return {
+    id: pickField(row, KEY_ID),
+    applymentNo: pickField(row, KEY_APPLYMENT_NO),
+    signUrl: pickField(row, KEY_SIGN),
+    applymentState: stateRaw ? formatApplymentStateLabel(stateRaw) : "—",
+    rejectReason: pickField(row, KEY_REJECT)
+  };
+}
+
+function unwrapPayload(raw: unknown): unknown {
+  if (raw === null || raw === undefined) return null;
+  if (Array.isArray(raw)) return raw;
+  if (typeof raw !== "object") return raw;
+  const o = raw as Record<string, unknown>;
+  if (Array.isArray(o.list)) return o.list;
+  if (Array.isArray(o.records)) return o.records;
+  if (Array.isArray(o.rows)) return o.rows;
+  if (o.data !== undefined && o.data !== null) {
+    const inner = o.data;
+    if (Array.isArray(inner)) return inner;
+    if (typeof inner === "object" && !Array.isArray(inner)) {
+      const obj = inner as Record<string, unknown>;
+      if (Array.isArray(obj.list)) return obj.list;
+      if (Array.isArray(obj.records)) return obj.records;
+    }
+    return inner;
+  }
+  return raw;
+}
+
+function isPlainObjectRow(x: unknown): x is Record<string, unknown> {
+  return x !== null && typeof x === "object" && !Array.isArray(x);
+}
+
+function buildDisplayRows(payload: unknown): Omit<ExamineDisplayRow, "_rowKey">[] {
+  if (payload === null || payload === undefined) return [];
+
+  if (Array.isArray(payload)) {
+    if (payload.length === 0) return [];
+    if (isPlainObjectRow(payload[0])) {
+      return (payload as Record<string, unknown>[]).map(normalizeRow);
+    }
+    return [
+      {
+        id: "—",
+        applymentNo: "—",
+        signUrl: "—",
+        applymentState: "—",
+        rejectReason: formatCell(payload)
+      }
+    ];
+  }
+
+  if (isPlainObjectRow(payload)) {
+    return [normalizeRow(payload)];
+  }
+
+  return [
+    {
+      id: "—",
+      applymentNo: "—",
+      signUrl: "—",
+      applymentState: "—",
+      rejectReason: formatCell(payload)
+    }
+  ];
+}
+
+function withRowKeys(rows: Omit<ExamineDisplayRow, "_rowKey">[]): ExamineDisplayRow[] {
+  return rows.map((r, i) => ({
+    ...r,
+    _rowKey: `examine-${i}-${r.id}-${r.applymentNo}`.replace(/\s/g, "")
+  }));
+}
+
+/**
+ * 与 tableManagement.vue 中 ProTable 约定一致:返回 { data }。
+ * 无分页时 useTable 将 data 视为列表(见 useTable 无分页分支)。
+ */
+async function getExamineList(_params: any) {
+  const storeId = resolveStoreIdParam();
+  if (storeId === null) {
+    loadError.value = "未获取到门店 storeId,请重新登录或通过路由传入 storeId。";
+    return { data: [] as ExamineDisplayRow[] };
+  }
+
+  loadError.value = "";
+  try {
+    const res = (await applymentExamine(storeId)) as { data?: unknown };
+    const payload = unwrapPayload(res?.data ?? res);
+    const list = withRowKeys(buildDisplayRows(payload));
+    return { data: list };
+  } catch (e: unknown) {
+    const msg = e && typeof e === "object" && "msg" in e ? String((e as { msg?: string }).msg) : "";
+    loadError.value = msg || "获取审核信息失败";
+    return { data: [] as ExamineDisplayRow[] };
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.we-chart-examine-page {
+  padding: 24px 32px 40px;
+  background: #ffffff;
+}
+.page-title {
+  margin: 0 0 20px;
+  font-size: 20px;
+  font-weight: 600;
+  color: #303133;
+}
+.mb-16 {
+  margin-bottom: 16px;
+}
+</style>

+ 15 - 0
src/views/businessInfo/weChartIndex.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="we-chart-index">
+    <CreateApply />
+  </div>
+</template>
+
+<script setup lang="ts">
+import CreateApply from "./createApply.vue";
+</script>
+
+<style scoped>
+.we-chart-index {
+  min-height: 100%;
+}
+</style>