Explorar o código

Merge remote-tracking branch 'origin/master'

sunshihao hai 4 días
pai
achega
ec5ac9f626
Modificáronse 100 ficheiros con 4140 adicións e 363 borrados
  1. 2 2
      xinkeaboard-admin/config/config.js
  2. 1 0
      xinkeaboard-admin/src/models/global.js
  3. 15 4
      xinkeaboard-admin/src/pages/User/Login.js
  4. 1 4
      xinkeaboard-admin/src/pages/decorate/pc/home/main_banner_pc.js
  5. 3 3
      xinkeaboard-admin/src/pages/manage/order/enquiry/add_track.js
  6. 16 18
      xinkeaboard-admin/src/pages/manage/order/enquiry/enquiry_lists.js
  7. 11 1
      xinkeaboard-admin/src/pages/manage/store/edit_settled_store.js
  8. 1 1
      xinkeaboard-admin/src/pages/manage/store/settled_store_detail.js
  9. 46 46
      xinkeaboard-admin/src/pages/statistics/realtime.js
  10. 1 1
      xinkeaboard-admin/src/utils/utils.js
  11. 45 3
      xinkeaboard-gemini-langgraph_prompt/backend/src/agent/graph.py
  12. 29 0
      xinkeaboard-promotion-portal/.eslintrc.cjs
  13. 3 0
      xinkeaboard-promotion-portal/.gitignore
  14. 6 0
      xinkeaboard-promotion-portal/.prettierrc
  15. 31 0
      xinkeaboard-promotion-portal/README.md
  16. 12 0
      xinkeaboard-promotion-portal/index.html
  17. 27 0
      xinkeaboard-promotion-portal/package.json
  18. 1970 0
      xinkeaboard-promotion-portal/pnpm-lock.yaml
  19. 11 0
      xinkeaboard-promotion-portal/src/App.vue
  20. 22 0
      xinkeaboard-promotion-portal/src/components/HelloWorld.vue
  21. 9 0
      xinkeaboard-promotion-portal/src/main.ts
  22. 16 0
      xinkeaboard-promotion-portal/src/router/index.ts
  23. 12 0
      xinkeaboard-promotion-portal/src/store/index.ts
  24. 132 0
      xinkeaboard-promotion-portal/src/utils/http.ts
  25. 21 0
      xinkeaboard-promotion-portal/tsconfig.json
  26. 11 0
      xinkeaboard-promotion-portal/vite.config.ts
  27. 15 1
      xinkeaboard-seller/src/components/SldEditFormCom/SldEditFormCom.js
  28. 15 1
      xinkeaboard-seller/src/components/SldTableRowThree/index.js
  29. 17 2
      xinkeaboard-seller/src/components/SldTableRowTwo/index.js
  30. 61 18
      xinkeaboard-seller/src/components/SldUEditor/index.js
  31. BIN=BIN
      xinkeaboard-seller/src/components/SlideVerify/icons/refresh.png
  32. BIN=BIN
      xinkeaboard-seller/src/components/SlideVerify/icons/right.png
  33. BIN=BIN
      xinkeaboard-seller/src/components/SlideVerify/icons/success.png
  34. 396 0
      xinkeaboard-seller/src/components/SlideVerify/index.js
  35. 137 0
      xinkeaboard-seller/src/components/SlideVerify/index.less
  36. 1 0
      xinkeaboard-seller/src/models/global.js
  37. 105 66
      xinkeaboard-seller/src/pages/User/Login.js
  38. 24 0
      xinkeaboard-seller/src/pages/User/Login.less
  39. 12 0
      xinkeaboard-seller/src/utils/regex.js
  40. 1 1
      xinkeaboard-seller/src/utils/utils.js
  41. 5 0
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/CommonConst.java
  42. 12 0
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/RedisConst.java
  43. 9 0
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/StoreConst.java
  44. 6 0
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/util/WebUtil.java
  45. 5 2
      xinkeaboard-server/b2b2c-core/src/main/resources/i18n_en.properties
  46. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/dto/FriendLinkAddDTO.java
  47. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/dto/FriendLinkUpdateDTO.java
  48. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/example/FriendLinkExample.java
  49. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/pojo/FriendLink.java
  50. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/dto/SearchConditionDTO.java
  51. 6 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/example/GoodsSearchWordsExample.java
  52. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/pojo/GoodsSearchWords.java
  53. 1 1
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/member/pojo/Member.java
  54. 5 2
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/OwnStoreAddDTO.java
  55. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/OwnStoreUpdateDTO.java
  56. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/StoreBusinessVO.java
  57. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreCompanyShowListExample.java
  58. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreExample.java
  59. 11 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreSiteInfoExample.java
  60. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/pojo/Store.java
  61. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/pojo/StoreSiteInfo.java
  62. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/dto/EnquiryAddDTO.java
  63. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/NavigationExample.java
  64. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/PcFirstAdvExample.java
  65. 5 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/SearchLogExample.java
  66. 10 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/Enquiry.java
  67. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/Navigation.java
  68. 7 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/PcFirstAdv.java
  69. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/SearchLog.java
  70. 1 1
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/TplPcMallData.java
  71. 3 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/admin/AdminFriendLinkController.java
  72. 2 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/front/FrontArticleController.java
  73. 2 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/front/FrontFriendLinkController.java
  74. 17 15
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/FrontGoodsCategoryController.java
  75. 20 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/GoodsListController.java
  76. 3 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/GoodsSearchWordsController.java
  77. 1 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/seller/GoodsCategorySellerController.java
  78. 37 7
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/admin/AdminEnquiryController.java
  79. 4 4
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/MemberPasswordController.java
  80. 367 61
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEmailActiveController.java
  81. 20 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEnquiryController.java
  82. 1 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/msg/seller/SellerVerifyController.java
  83. 2 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminCateAuditController.java
  84. 34 19
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminOwnStoreController.java
  85. 8 6
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminStoreAuditController.java
  86. 20 3
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminStoreController.java
  87. 2 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/front/FrontCategoryController.java
  88. 79 16
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/front/FrontStoreController.java
  89. 20 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/seller/SellerStoreController.java
  90. 1 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/seller/SellerVendorController.java
  91. 7 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/sso/front/FrontAuthController.java
  92. 19 5
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminFlowAnalysisController.java
  93. 15 7
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminGoodsAnalysisController.java
  94. 19 4
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminMemberAnalysisController.java
  95. 4 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminOverviewController.java
  96. 2 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminPresentAnalysisController.java
  97. 24 7
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminStoreAnalysisController.java
  98. 7 4
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminTradeAnalysisController.java
  99. 2 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/front/FrontMemberBehaviorController.java
  100. 16 10
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/system/admin/AdminNavigationController.java

+ 2 - 2
xinkeaboard-admin/config/config.js

@@ -75,8 +75,8 @@ export default {
   },
   proxy: {
     "/api/": {
-      // target: "http://54.46.9.88:8001/",
-      target: 'http://192.168.0.158:8001/',
+      target: "http://54.46.9.88:8001/",
+      // target: 'http://192.168.0.158:8001/',
       changeOrigin: true,
       pathRewrite: { "^/api": "" },
     },

+ 1 - 0
xinkeaboard-admin/src/models/global.js

@@ -95,6 +95,7 @@ export default {
       };
     },
     setCurrentSite(state, { payload }) {
+      localStorage.setItem('currentSite', payload)
       return {
         ...state,
         currentSite: payload,

+ 15 - 4
xinkeaboard-admin/src/pages/User/Login.js

@@ -1,6 +1,6 @@
 import React, { Component } from 'react';
 import { connect } from 'dva';
-import { Form, Input } from 'antd';
+import { Form, Input, Button } from 'antd';
 import styles from './Login.less';
 import global from '@/global.less';
 import {
@@ -30,6 +30,7 @@ export default class LoginPage extends Component {
 		autoLogin: true,
 		login_img: {},
     captcha: '',
+    loading: false
 	};
 
   captcha = '';//图形验证码的key
@@ -88,6 +89,7 @@ export default class LoginPage extends Component {
 				//用户登录
 				const { dispatch } = this.props;
         values.verifyKey = this.captcha;
+        this.setState({loading: true})
 				dispatch({
 					type: 'login/login',
 					payload: { ...values },
@@ -104,6 +106,7 @@ export default class LoginPage extends Component {
 						  failTip(res.msg);
               this.getCaptcha('captcha')
             }
+            this.setState({loading: false})
 					},
 				});
 			}
@@ -118,7 +121,7 @@ export default class LoginPage extends Component {
 
 	render() {
 		const { getFieldDecorator } = this.props.form;
-		const {login_img,captcha} = this.state;
+		const {login_img,captcha, loading} = this.state;
 		return (
 			<div className={styles.full_screen}
 				 style={{ backgroundImage: window.location.href.indexOf('user') != -1 ? 'url(' + login_img.admin_login_bg + ')' : 'none',backgroundSize:'100% 100%' }}>
@@ -181,9 +184,17 @@ export default class LoginPage extends Component {
                   )}
                 </FormItem>
                 <div className={styles.sld_login_btn_wrap}>
-                  <div className={`${styles.sld_login_btn} ${global.flex_row_center_center}`} onClick={() => this.props.form.submit(this.handleSubmits)}>
+                  {/* <div className={`${styles.sld_login_btn} ${global.flex_row_center_center}`} >
                     {sldComLanguage('立即登录')}
-                  </div>
+                  </div> */}
+                  <Button 
+                   type='primary' 
+                   className={`${styles.sld_login_btn} ${global.flex_row_center_center}`} 
+                   loading={loading} 
+                   onClick={() => this.props.form.submit(this.handleSubmits)}
+                  >
+                    {sldComLanguage('立即登录')}
+                  </Button>
                 </div>
               </Form>
             </div>

+ 1 - 4
xinkeaboard-admin/src/pages/decorate/pc/home/main_banner_pc.js

@@ -164,17 +164,14 @@ export default class MainBannerPc extends Component {
       data = nextProps.tpl_info;
       console.log('nextProps.tpl_info:{}', data);
       console.log('data.hasOwnProperty("info"):{}', data.hasOwnProperty('info'));
-
       if (data.hasOwnProperty('info')) {
         banner_data = data;
       } else {
         if (data.length == 0) {
           banner_data.info.carousel_info.data = tpl_info.data;
         } else {
-          if (data.hasOwnProperty('data')) {
+          if (data.data?.length) {
             banner_data.info.carousel_info.data = data.data;
-          } else {
-            banner_data.info.carousel_info.data = data;
           }
         }
       }

+ 3 - 3
xinkeaboard-admin/src/pages/manage/order/enquiry/add_track.js

@@ -106,7 +106,7 @@ export default class AddTrack extends Component {
   componentDidMount() {
     const { query } = this.state;
     this.setState({ initEditorFlag: true });
-    this.get_vendor_list();
+    this.get_vendor_list(query.store_id);
     if (query.enquiry_id != undefined && query.enquiry_id != null && query.enquiry_id != '' && query.enquiry_id > 0) {
       this.trackEnquiryRecord({ pageSize: pageSize });
     }
@@ -117,12 +117,12 @@ export default class AddTrack extends Component {
   }
 
   //跟踪人列表
-  get_vendor_list = (params = {}) => {
+  get_vendor_list = (storeId) => {
     const { dispatch } = this.props;
     let { search_data } = this.state;
     dispatch({
       type: 'order/get_return_subadmin_lists',
-      payload: {},
+      payload: {storeId},
       callback: (res) => {
         if (res.state == 200) {
           let tmp_data = search_data.filter(item => item.name == 'vendorId')[0];

+ 16 - 18
xinkeaboard-admin/src/pages/manage/order/enquiry/enquiry_lists.js

@@ -315,9 +315,10 @@ export default class EnquiryLists extends Component {
                 pathname: '/manage_order/enquiry_track_to_add',
                 query: {
                   enquiry_id: record.id,
+                  store_id: record.storeId
                 },
               }}>
-                {sldtbaleOpeBtnText(`${sldComLanguage('跟踪')}`, () => null)}
+                {sldtbaleOpeBtnText(`${sldComLanguage('跟踪')}`)}
               </Link>
               {/* 只有管理员才可以操作 */}
               {/*{(record.isDel == 1) ?*/}
@@ -391,22 +392,32 @@ export default class EnquiryLists extends Component {
   componentDidMount() {
     this.get_list({ pageSize: pageSize });
     this.get_store_list();
-    this.get_vendor_list();
   }
 
   //获取用户数据列表
-  get_vendor_list = (params = {}) => {
+  get_vendor_list = (record) => {
     const { dispatch } = this.props;
     let { assignData } = this.state;
     dispatch({
       type: 'order/get_return_subadmin_lists',
-      payload: {},
+      payload: {storeId: record.storeId},
       callback: (res) => {
         if (res.state == 200) {
           let tmp_data = assignData.filter(item => item.name == 'vendorId')[0];
           tmp_data.sel_data = res.data.list;
+          let { operateData, addressType } = this.state;
+          operateData = getSldCopyData(assignData);
+          for (let i in operateData) {
+            operateData[i].initialValue = record[operateData[i].name];
+          }
+          this.cur_edit_id = record.id;//当前操作数据id
           this.setState({
             assignData,
+            type: 'assign',
+            title: `${sldComLanguage('询盘分配')}`,
+            operateData,
+            modalVisible: true,
+            show_foot: true,
           });
         } else {
           failTip(res.msg);
@@ -523,20 +534,7 @@ export default class EnquiryLists extends Component {
 
   //询盘分配按钮
   assignEnquiry = (val) => {
-    let { assignData, operateData, addressType } = this.state;
-    operateData = getSldCopyData(assignData);
-    for (let i in operateData) {
-      operateData[i].initialValue = val[operateData[i].name];
-    }
-
-    this.cur_edit_id = val.id;//当前操作数据id
-    this.setState({
-      type: 'assign',
-      title: `${sldComLanguage('询盘分配')}`,
-      operateData,
-      modalVisible: true,
-      show_foot: true,
-    });//询盘分配
+    this.get_vendor_list(val);
   };
 
   //询盘分配操作

+ 11 - 1
xinkeaboard-admin/src/pages/manage/store/edit_settled_store.js

@@ -645,7 +645,7 @@ export default class EditSettledStore extends Component {
 
   //保存
   save = () => {
-    let { query, siteList, store_detail, business_license_img, replenish_img, personal_front_card_img } = this.state;
+    let { query, currentSite, siteList, store_detail, business_license_img, replenish_img, personal_front_card_img } = this.state;
     this.props.form.validateFieldsAndScroll((err, values) => {
       if(!err){
         let params = { ...values };
@@ -727,6 +727,16 @@ export default class EditSettledStore extends Component {
             }
           },
         });
+      } else {
+        const errorKeys = Object.keys(err);
+        const firstKeyBelongSite = errorKeys[0].replace(/^[^_]*_/, "");
+        const matchSite = siteList.find(site => site.webSite === firstKeyBelongSite);
+        if ( matchSite && firstKeyBelongSite !== currentSite.webSite) {
+          this.setCurrentSite({
+            webSite: firstKeyBelongSite,
+            webSiteName: matchSite.webSiteName
+          })
+        }
       }
 
     });

+ 1 - 1
xinkeaboard-admin/src/pages/manage/store/settled_store_detail.js

@@ -298,7 +298,7 @@ export default class ApplyStoreDetail extends Component {
   parseText = (text, name) => {
     let newText = text;
     if (name == 'openTime') {
-      newText = `${text}${sldComLanguage('年')}`;
+      newText = text ? `${text}${sldComLanguage('年')}` : '';
     } else if (name == 'payAmount') {
       newText = `${text}${sldComLanguage('元')}`;
     } else if (name == 'billCycle') {

+ 46 - 46
xinkeaboard-admin/src/pages/statistics/realtime.js

@@ -66,6 +66,41 @@ export default class StatisticsRealtime extends Component {
           },
         ],
       },
+      siteRealTimeData: {
+        icon: require('@/assets/real_icon_1.png'),
+        title: `${sldComLanguage('平台汇总')}`,
+        list: [
+          // {
+          //   name: `${sldComLanguage('销售总额(元)')}`,
+          //   value: '',
+          //   isHelpIcon: false,
+          //   tip: `${sldComLanguage('截止至当前时间,全平台累计销售额')}`,
+          //   mapKey: 'orderPayAmountTotal',
+          //   isMoney: true,
+          // },
+          {
+            name: `${sldComLanguage('会员总数')}`,
+            value: '',
+            isHelpIcon: true,
+            tip: `${sldComLanguage('截止至当前时间,全平台注册会员数')}`,
+            mapKey: 'webSiteMemberNum',
+          },
+          {
+            name: `${sldComLanguage('店铺总数')}`,
+            value: '',
+            isHelpIcon: true,
+            tip: `${sldComLanguage('截止至当前时间,全平台商家总数,包括自营商家和入驻商家')}`,
+            mapKey: 'webSiteStoreNum',
+          },
+          {
+            name: `${sldComLanguage('在售商品数')}`,
+            value: '',
+            isHelpIcon: true,
+            tip: `${sldComLanguage('截止至当前时间,状态为在售的商品数量')}`,
+            mapKey: 'webSiteSaleGoodsNum',
+          },
+        ],
+      },
       realTimeData2: {
         icon: require('@/assets/real_icon_2.png'),
         title: `${sldComLanguage('今日实时')}`,
@@ -249,8 +284,8 @@ export default class StatisticsRealtime extends Component {
           detailData = res.data;
 
           //渲染头部实时分析的数据
-          const { realTimeData1, realTimeData2 } = this.state;
-          const tempArray = [...realTimeData1.list, ...realTimeData2.list];
+          const { realTimeData1, realTimeData2, siteRealTimeData } = this.state;
+          const tempArray = [...realTimeData1.list, ...realTimeData2.list, ...siteRealTimeData.list];
           const tempActionData = { ...res.data.platformSummary, ...res.data.platformTodaySummary,orderPayAmountTotal:res.data.platformSummary.orderPayAmount };
           tempArray.forEach((item, index) => {
             tempArray[index]['value'] = tempActionData[item.mapKey];
@@ -260,6 +295,7 @@ export default class StatisticsRealtime extends Component {
             detailData,
             realTimeData2,
             realTimeData1,
+            siteRealTimeData,
             refreshTime,
           });
 
@@ -289,7 +325,8 @@ export default class StatisticsRealtime extends Component {
   }
 
   platformSummary = (type) => {
-    const { currentSiteName, realTimeData2, realTimeData1, initLoading, refreshTime, screenW, loadedFlag, detailData } = this.state;
+    const { currentSiteName, realTimeData2, siteRealTimeData, realTimeData1, initLoading, refreshTime, screenW, loadedFlag, detailData } = this.state;
+    const renderRealTimeData = type ? siteRealTimeData : realTimeData1
     const leftW = this.props.global != undefined && this.props.global.collapsed != undefined && this.props.global.collapsed ? 90 : 150;
     let itemW = (screenW * 1 - leftW - 20 - 100 - 30 - 80) / 5;
     return (
@@ -297,12 +334,12 @@ export default class StatisticsRealtime extends Component {
         {this.realtimeAnalysis()}
         <div className={`${stat.num_stat_item} ${global.flex_row_start_center} ${global.no_border}`}>
           <div className={`${stat.left_slide} ${global.flex_column_center_center}`}>
-            <img src={realTimeData1.icon} className={`${stat.slide_icon}`}></img>
-            <span className={`${stat.slide_title}`}>{realTimeData1.title}</span>
+            <img src={renderRealTimeData.icon} className={`${stat.slide_icon}`}></img>
+            <span className={`${stat.slide_title}`}>{renderRealTimeData.title}</span>
           </div>
           <div className={`${stat.right_main}`}>
             <ul className={`${global.flex_row_start_center}`}>
-              {realTimeData1.list.map((item, index) => (
+              {renderRealTimeData.list.map((item, index) => (
                 <li key={index} className={`${global.flex_column_center_start}`} style={{ width: itemW }}>
                   <div className={`${stat.up_desc}`}>
                     <span>{item.name}</span>
@@ -349,47 +386,10 @@ export default class StatisticsRealtime extends Component {
         >
           <Spin spinning={initLoading}>
             <div className={`${stat.module_item}`}>
-              {currentSiteName && this.platformSummary()}
-              {currentSiteName && <div className={ styles.current_site }>{ currentSiteName }</div> }
+              {this.platformSummary()}
+              {<div className={ styles.current_site }>{ currentSiteName }</div> }
               <div className={`${stat.real_num_panel} ${styles.current_site_stat}`}>
-                {this.realtimeAnalysis()}
-                <div className={`${stat.num_stat_item} ${global.flex_row_start_center} ${styles.no_border}`}>
-                  <div className={`${stat.left_slide} ${global.flex_column_center_center}`}>
-                    <img src={realTimeData1.icon} className={`${stat.slide_icon}`}></img>
-                    <span className={`${stat.slide_title}`}>{realTimeData1.title}</span>
-                  </div>
-                  <div className={`${stat.right_main}`}>
-                    <ul className={`${global.flex_row_start_center}`}>
-                      {realTimeData1.list.map((item, index) => (
-                        <li key={index} className={`${global.flex_column_center_start}`} style={{ width: itemW }}>
-                          <div className={`${stat.up_desc}`}>
-                            <span>{item.name}</span>
-
-                            {item.isHelpIcon ? <Tooltip placement="right" title={item.tip}>
-                              <img src={require('@/assets/home_basic/help_icon.png')}></img>
-                            </Tooltip> : ''}
-                          </div>
-                          <div className={`${stat.down_num}`} title={item.value}>
-                            <span>
-                            {loadedFlag && (
-                              item.value > 10000
-                                ? formatNum(item.value, item.isMoney ? 2 : 0)
-                                : <TweenOne animation={{
-                                  Children: {
-                                    value: item.value, floatLength: item.isMoney ? 2 : 0,
-                                    formatMoney: true,
-                                  },
-                                  duration: 1000,
-                                }}/>
-                            )}
-                          </span>
-                          </div>
-                        </li>
-                      ))}
-
-                    </ul>
-                  </div>
-                </div>
+                {this.platformSummary('site')}
                 <div>
                   <div className={`${stat.num_stat_item} ${global.flex_row_start_start} ${styles.no_border}`}>
                     <div

+ 1 - 1
xinkeaboard-admin/src/utils/utils.js

@@ -1329,7 +1329,7 @@ export function getSldStatYTitle() {
  * */
 export function sldComRequest(method, url, params, data_type = '') {
   const state = window.g_app._store.getState();
-  const currentSite = state.global.currentSite;
+  const currentSite = state.global.currentSite || localStorage.getItem('currentSite');
   const currentPath = state.routing.location.pathname;
   if (!currentPath.includes('/user/login')) {
     params = Object.assign({}, params ?? {}, { webSite: currentSite })

+ 45 - 3
xinkeaboard-gemini-langgraph_prompt/backend/src/agent/graph.py

@@ -305,14 +305,56 @@ def finalize_answer(state: OverallState, config: RunnableConfig):
     logger.info("开始:llm.invoke")
     result = llm.invoke(formatted_prompt)
     logger.info("结束:llm.invoke:{}",result)
+    
     # Replace the short urls with the original urls and add all used urls to the sources_gathered
     unique_sources = []
+    citation_map = {}  # Map of short_url to source info
+    citation_numbers = {}  # Map of short_url to citation number
+    
+    # Build source map and assign citation numbers
+    citation_counter = 1
     for source in state["sources_gathered"]:
         if source["short_url"] in result.content:
-            result.content = result.content.replace(
-                source["short_url"], source["value"]
-            )
             unique_sources.append(source)
+            citation_map[source["short_url"]] = source
+            citation_numbers[source["short_url"]] = citation_counter
+            citation_counter += 1
+    
+    # Collect citations from the content
+    citations_in_text = []
+    
+    # Find all citations in the content and replace them with numbered markers
+    import re
+    
+    # Pattern to match markdown links like [text](url)
+    link_pattern = r'\[([^\]]+)\]\(([^)]+)\)'
+    
+    def replace_with_numbered_citation(match):
+        text = match.group(1)
+        url = match.group(2)
+        if url in citation_numbers:
+            # Store the citation for later use
+            citations_in_text.append((citation_numbers[url], text, citation_map[url]))
+            # Return just the text with a numbered citation marker
+            return f"{text}[{citation_numbers[url]}]"
+        return match.group(0)  # Return unchanged if not a citation
+    
+    # Replace inline citations with numbered markers
+    result.content = re.sub(link_pattern, replace_with_numbered_citation, result.content)
+    
+    # Add a section for citations at the end
+    if citations_in_text:
+        # Sort citations by their number
+        citations_in_text.sort(key=lambda x: x[0])
+        
+        # Add citations section
+        result.content += "\n\n## 参考资料\n"
+        added_citations = set()  # To avoid duplicates
+        for num, text, source in citations_in_text:
+            if num not in added_citations:
+                result.content += f"{num}. [{source['label']}]({source['value']})\n"
+                added_citations.add(num)
+    
     #save the result to a markdown file
     # with open(f"result_{get_research_topic(state['messages'])}.md", "w", encoding="utf-8") as f:
     #     f.write(result.content)

+ 29 - 0
xinkeaboard-promotion-portal/.eslintrc.cjs

@@ -0,0 +1,29 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+    browser: true,
+    es2021: true
+  },
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    parser: '@typescript-eslint/parser',
+    ecmaVersion: 12,
+    sourceType: 'module',
+    ecmaFeatures: {
+      jsx: true
+    }
+  },
+  extends: [
+    'eslint:recommended',
+    'plugin:vue/vue3-essential',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:prettier/recommended'
+  ],
+  plugins: ['vue', '@typescript-eslint', 'prettier'],
+  rules: {
+    'prettier/prettier': 'error',
+    'vue/multi-word-component-names': 'off',
+    '@typescript-eslint/no-explicit-any': 'off'
+  }
+}

+ 3 - 0
xinkeaboard-promotion-portal/.gitignore

@@ -0,0 +1,3 @@
+/node_modules/
+/.DS_Store
+dist

+ 6 - 0
xinkeaboard-promotion-portal/.prettierrc

@@ -0,0 +1,6 @@
+{
+  "semi": true,
+  "singleQuote": true,
+  "printWidth": 100,
+  "trailingComma": "none"
+}

+ 31 - 0
xinkeaboard-promotion-portal/README.md

@@ -0,0 +1,31 @@
+# 🚀 项目名称 xinkeaboard-promotion-portal
+
+
+## ⚙️ 环境准备
+
+建议使用 [nvm](https://github.com/nvm-sh/nvm) 管理 Node.js 版本:
+
+```bash
+nvm install 18.20.4
+nvm use 18.20.4
+```
+
+安装 pnpm:
+
+```bash
+npm install -g pnpm@10.12.1
+```
+
+## 安装依赖
+
+```bash
+pnpm install
+```
+
+## 启动开发环境
+
+```bash
+pnpm dev
+```
+
+Start the development server on http://localhost:5173

+ 12 - 0
xinkeaboard-promotion-portal/index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>招商门户</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 27 - 0
xinkeaboard-promotion-portal/package.json

@@ -0,0 +1,27 @@
+{
+  "name": "xinkeaboard-promotion-portal",
+  "version": "1.0.0",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "lint": "eslint --ext .ts,.vue src"
+  },
+  "dependencies": {
+    "axios": "^1.11.0",
+    "pinia": "^2.0.0",
+    "vue": "^3.2.0",
+    "vue-router": "^4.0.0"
+  },
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^5.0.0",
+    "@typescript-eslint/parser": "^5.0.0",
+    "@vitejs/plugin-vue": "^4.0.0",
+    "eslint": "^8.0.0",
+    "eslint-config-prettier": "^8.0.0",
+    "eslint-plugin-prettier": "^4.0.0",
+    "eslint-plugin-vue": "^9.0.0",
+    "prettier": "^2.8.0",
+    "typescript": "^5.0.0",
+    "vite": "^4.0.0"
+  }
+}

+ 1970 - 0
xinkeaboard-promotion-portal/pnpm-lock.yaml

@@ -0,0 +1,1970 @@
+lockfileVersion: '9.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+importers:
+
+  .:
+    dependencies:
+      axios:
+        specifier: ^1.11.0
+        version: 1.11.0
+      pinia:
+        specifier: ^2.0.0
+        version: 2.3.1(typescript@5.9.2)(vue@3.5.18(typescript@5.9.2))
+      vue:
+        specifier: ^3.2.0
+        version: 3.5.18(typescript@5.9.2)
+      vue-router:
+        specifier: ^4.0.0
+        version: 4.5.1(vue@3.5.18(typescript@5.9.2))
+    devDependencies:
+      '@typescript-eslint/eslint-plugin':
+        specifier: ^5.0.0
+        version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)
+      '@typescript-eslint/parser':
+        specifier: ^5.0.0
+        version: 5.62.0(eslint@8.57.1)(typescript@5.9.2)
+      '@vitejs/plugin-vue':
+        specifier: ^4.0.0
+        version: 4.6.2(vite@4.5.14)(vue@3.5.18(typescript@5.9.2))
+      eslint:
+        specifier: ^8.0.0
+        version: 8.57.1
+      eslint-config-prettier:
+        specifier: ^8.0.0
+        version: 8.10.2(eslint@8.57.1)
+      eslint-plugin-prettier:
+        specifier: ^4.0.0
+        version: 4.2.5(eslint-config-prettier@8.10.2(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8)
+      eslint-plugin-vue:
+        specifier: ^9.0.0
+        version: 9.33.0(eslint@8.57.1)
+      prettier:
+        specifier: ^2.8.0
+        version: 2.8.8
+      typescript:
+        specifier: ^5.0.0
+        version: 5.9.2
+      vite:
+        specifier: ^4.0.0
+        version: 4.5.14
+
+packages:
+
+  '@babel/helper-string-parser@7.27.1':
+    resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-identifier@7.27.1':
+    resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/parser@7.28.0':
+    resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/types@7.28.2':
+    resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@esbuild/android-arm64@0.18.20':
+    resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.18.20':
+    resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.18.20':
+    resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.18.20':
+    resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.18.20':
+    resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.18.20':
+    resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.18.20':
+    resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.18.20':
+    resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.18.20':
+    resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.18.20':
+    resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.18.20':
+    resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.18.20':
+    resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.18.20':
+    resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.18.20':
+    resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.18.20':
+    resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.18.20':
+    resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-x64@0.18.20':
+    resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-x64@0.18.20':
+    resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.18.20':
+    resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.18.20':
+    resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.18.20':
+    resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.18.20':
+    resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@eslint-community/eslint-utils@4.7.0':
+    resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+  '@eslint-community/regexpp@4.12.1':
+    resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  '@eslint/eslintrc@2.1.4':
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@eslint/js@8.57.1':
+    resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@humanwhocodes/config-array@0.13.0':
+    resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
+    engines: {node: '>=10.10.0'}
+    deprecated: Use @eslint/config-array instead
+
+  '@humanwhocodes/module-importer@1.0.1':
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+
+  '@humanwhocodes/object-schema@2.0.3':
+    resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+    deprecated: Use @eslint/object-schema instead
+
+  '@jridgewell/sourcemap-codec@1.5.4':
+    resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
+
+  '@nodelib/fs.scandir@2.1.5':
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.stat@2.0.5':
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.walk@1.2.8':
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+
+  '@types/json-schema@7.0.15':
+    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+  '@types/semver@7.7.0':
+    resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==}
+
+  '@typescript-eslint/eslint-plugin@5.62.0':
+    resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^5.0.0
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/parser@5.62.0':
+    resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/scope-manager@5.62.0':
+    resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@typescript-eslint/type-utils@5.62.0':
+    resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '*'
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/types@5.62.0':
+    resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@typescript-eslint/typescript-estree@5.62.0':
+    resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/utils@5.62.0':
+    resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+  '@typescript-eslint/visitor-keys@5.62.0':
+    resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@ungap/structured-clone@1.3.0':
+    resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+
+  '@vitejs/plugin-vue@4.6.2':
+    resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^4.0.0 || ^5.0.0
+      vue: ^3.2.25
+
+  '@vue/compiler-core@3.5.18':
+    resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==}
+
+  '@vue/compiler-dom@3.5.18':
+    resolution: {integrity: sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==}
+
+  '@vue/compiler-sfc@3.5.18':
+    resolution: {integrity: sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==}
+
+  '@vue/compiler-ssr@3.5.18':
+    resolution: {integrity: sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==}
+
+  '@vue/devtools-api@6.6.4':
+    resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
+
+  '@vue/reactivity@3.5.18':
+    resolution: {integrity: sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==}
+
+  '@vue/runtime-core@3.5.18':
+    resolution: {integrity: sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==}
+
+  '@vue/runtime-dom@3.5.18':
+    resolution: {integrity: sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==}
+
+  '@vue/server-renderer@3.5.18':
+    resolution: {integrity: sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==}
+    peerDependencies:
+      vue: 3.5.18
+
+  '@vue/shared@3.5.18':
+    resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==}
+
+  acorn-jsx@5.3.2:
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+  acorn@8.15.0:
+    resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+  ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+
+  ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+
+  argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+  array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+
+  asynckit@0.4.0:
+    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+  axios@1.11.0:
+    resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==}
+
+  balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+  boolbase@1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+  brace-expansion@1.1.12:
+    resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
+
+  braces@3.0.3:
+    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+    engines: {node: '>=8'}
+
+  call-bind-apply-helpers@1.0.2:
+    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+    engines: {node: '>= 0.4'}
+
+  callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+
+  chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+
+  color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+
+  color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+  combined-stream@1.0.8:
+    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+    engines: {node: '>= 0.8'}
+
+  concat-map@0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+  cross-spawn@7.0.6:
+    resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+    engines: {node: '>= 8'}
+
+  cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+  debug@4.4.1:
+    resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+  delayed-stream@1.0.0:
+    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+    engines: {node: '>=0.4.0'}
+
+  dir-glob@3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+
+  doctrine@3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+
+  dunder-proto@1.0.1:
+    resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+    engines: {node: '>= 0.4'}
+
+  entities@4.5.0:
+    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+    engines: {node: '>=0.12'}
+
+  es-define-property@1.0.1:
+    resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+    engines: {node: '>= 0.4'}
+
+  es-errors@1.3.0:
+    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+    engines: {node: '>= 0.4'}
+
+  es-object-atoms@1.1.1:
+    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+    engines: {node: '>= 0.4'}
+
+  es-set-tostringtag@2.1.0:
+    resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+    engines: {node: '>= 0.4'}
+
+  esbuild@0.18.20:
+    resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+
+  eslint-config-prettier@8.10.2:
+    resolution: {integrity: sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==}
+    hasBin: true
+    peerDependencies:
+      eslint: '>=7.0.0'
+
+  eslint-plugin-prettier@4.2.5:
+    resolution: {integrity: sha512-9Ni+xgemM2IWLq6aXEpP2+V/V30GeA/46Ar629vcMqVPodFFWC9skHu/D1phvuqtS8bJCFnNf01/qcmqYEwNfg==}
+    engines: {node: '>=12.0.0'}
+    peerDependencies:
+      eslint: '>=7.28.0'
+      eslint-config-prettier: '*'
+      prettier: '>=2.0.0'
+    peerDependenciesMeta:
+      eslint-config-prettier:
+        optional: true
+
+  eslint-plugin-vue@9.33.0:
+    resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
+
+  eslint-scope@5.1.1:
+    resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
+    engines: {node: '>=8.0.0'}
+
+  eslint-scope@7.2.2:
+    resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint-visitor-keys@3.4.3:
+    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint@8.57.1:
+    resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
+    hasBin: true
+
+  espree@9.6.1:
+    resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  esquery@1.6.0:
+    resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+    engines: {node: '>=0.10'}
+
+  esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+
+  estraverse@4.3.0:
+    resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+    engines: {node: '>=4.0'}
+
+  estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+
+  estree-walker@2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+
+  fast-deep-equal@3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+  fast-diff@1.3.0:
+    resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+
+  fast-glob@3.3.3:
+    resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+    engines: {node: '>=8.6.0'}
+
+  fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+  fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+  fastq@1.19.1:
+    resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+  file-entry-cache@6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  fill-range@7.1.1:
+    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+    engines: {node: '>=8'}
+
+  find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+
+  flat-cache@3.2.0:
+    resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  flatted@3.3.3:
+    resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+  follow-redirects@1.15.11:
+    resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+
+  form-data@4.0.4:
+    resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
+    engines: {node: '>= 6'}
+
+  fs.realpath@1.0.0:
+    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  function-bind@1.1.2:
+    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+  get-intrinsic@1.3.0:
+    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+    engines: {node: '>= 0.4'}
+
+  get-proto@1.0.1:
+    resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+    engines: {node: '>= 0.4'}
+
+  glob-parent@5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+
+  glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+
+  glob@7.2.3:
+    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    deprecated: Glob versions prior to v9 are no longer supported
+
+  globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+    engines: {node: '>=8'}
+
+  globby@11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+
+  gopd@1.2.0:
+    resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+    engines: {node: '>= 0.4'}
+
+  graphemer@1.4.0:
+    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+  has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+
+  has-symbols@1.1.0:
+    resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+    engines: {node: '>= 0.4'}
+
+  has-tostringtag@1.0.2:
+    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+    engines: {node: '>= 0.4'}
+
+  hasown@2.0.2:
+    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+    engines: {node: '>= 0.4'}
+
+  ignore@5.3.2:
+    resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+    engines: {node: '>= 4'}
+
+  import-fresh@3.3.1:
+    resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+    engines: {node: '>=6'}
+
+  imurmurhash@0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+
+  inflight@1.0.6:
+    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+    deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+  inherits@2.0.4:
+    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+  is-extglob@2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-glob@4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+
+  is-number@7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+
+  is-path-inside@3.0.3:
+    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+    engines: {node: '>=8'}
+
+  isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+  js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+
+  json-buffer@3.0.1:
+    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+  json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+  json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+  keyv@4.5.4:
+    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+  levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+
+  locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+
+  lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+  lodash@4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+  magic-string@0.30.17:
+    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+  math-intrinsics@1.1.0:
+    resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+    engines: {node: '>= 0.4'}
+
+  merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+
+  micromatch@4.0.8:
+    resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+    engines: {node: '>=8.6'}
+
+  mime-db@1.52.0:
+    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+    engines: {node: '>= 0.6'}
+
+  mime-types@2.1.35:
+    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+    engines: {node: '>= 0.6'}
+
+  minimatch@3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+  ms@2.1.3:
+    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+  nanoid@3.3.11:
+    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  natural-compare-lite@1.4.0:
+    resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+
+  natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+  nth-check@2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+  once@1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+  optionator@0.9.4:
+    resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+    engines: {node: '>= 0.8.0'}
+
+  p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+
+  p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+
+  parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+
+  path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+
+  path-is-absolute@1.0.1:
+    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+    engines: {node: '>=0.10.0'}
+
+  path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+
+  path-type@4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+
+  picocolors@1.1.1:
+    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+  picomatch@2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+
+  pinia@2.3.1:
+    resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
+    peerDependencies:
+      typescript: '>=4.4.4'
+      vue: ^2.7.0 || ^3.5.11
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  postcss-selector-parser@6.1.2:
+    resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+    engines: {node: '>=4'}
+
+  postcss@8.5.6:
+    resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+    engines: {node: ^10 || ^12 || >=14}
+
+  prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+
+  prettier-linter-helpers@1.0.0:
+    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+    engines: {node: '>=6.0.0'}
+
+  prettier@2.8.8:
+    resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+
+  proxy-from-env@1.1.0:
+    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+  punycode@2.3.1:
+    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+    engines: {node: '>=6'}
+
+  queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+  resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+
+  reusify@1.1.0:
+    resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+  rimraf@3.0.2:
+    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    deprecated: Rimraf versions prior to v4 are no longer supported
+    hasBin: true
+
+  rollup@3.29.5:
+    resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}
+    engines: {node: '>=14.18.0', npm: '>=8.0.0'}
+    hasBin: true
+
+  run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+  semver@7.7.2:
+    resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+
+  shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+
+  slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+
+  source-map-js@1.2.1:
+    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+    engines: {node: '>=0.10.0'}
+
+  strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+
+  strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+
+  supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+
+  text-table@0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+
+  to-regex-range@5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+
+  tslib@1.14.1:
+    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+
+  tsutils@3.21.0:
+    resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+    engines: {node: '>= 6'}
+    peerDependencies:
+      typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+
+  type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+
+  type-fest@0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+
+  typescript@5.9.2:
+    resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  uri-js@4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+  vite@4.5.14:
+    resolution: {integrity: sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': '>= 14'
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+
+  vue-demi@0.14.10:
+    resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  vue-eslint-parser@9.4.3:
+    resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '>=6.0.0'
+
+  vue-router@4.5.1:
+    resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==}
+    peerDependencies:
+      vue: ^3.2.0
+
+  vue@3.5.18:
+    resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+
+  word-wrap@1.2.5:
+    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+    engines: {node: '>=0.10.0'}
+
+  wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+  xml-name-validator@4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+
+  yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+
+snapshots:
+
+  '@babel/helper-string-parser@7.27.1': {}
+
+  '@babel/helper-validator-identifier@7.27.1': {}
+
+  '@babel/parser@7.28.0':
+    dependencies:
+      '@babel/types': 7.28.2
+
+  '@babel/types@7.28.2':
+    dependencies:
+      '@babel/helper-string-parser': 7.27.1
+      '@babel/helper-validator-identifier': 7.27.1
+
+  '@esbuild/android-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/android-arm@0.18.20':
+    optional: true
+
+  '@esbuild/android-x64@0.18.20':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/darwin-x64@0.18.20':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-arm@0.18.20':
+    optional: true
+
+  '@esbuild/linux-ia32@0.18.20':
+    optional: true
+
+  '@esbuild/linux-loong64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.18.20':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.18.20':
+    optional: true
+
+  '@esbuild/linux-s390x@0.18.20':
+    optional: true
+
+  '@esbuild/linux-x64@0.18.20':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.18.20':
+    optional: true
+
+  '@esbuild/sunos-x64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-arm64@0.18.20':
+    optional: true
+
+  '@esbuild/win32-ia32@0.18.20':
+    optional: true
+
+  '@esbuild/win32-x64@0.18.20':
+    optional: true
+
+  '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)':
+    dependencies:
+      eslint: 8.57.1
+      eslint-visitor-keys: 3.4.3
+
+  '@eslint-community/regexpp@4.12.1': {}
+
+  '@eslint/eslintrc@2.1.4':
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.4.1
+      espree: 9.6.1
+      globals: 13.24.0
+      ignore: 5.3.2
+      import-fresh: 3.3.1
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@eslint/js@8.57.1': {}
+
+  '@humanwhocodes/config-array@0.13.0':
+    dependencies:
+      '@humanwhocodes/object-schema': 2.0.3
+      debug: 4.4.1
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@humanwhocodes/module-importer@1.0.1': {}
+
+  '@humanwhocodes/object-schema@2.0.3': {}
+
+  '@jridgewell/sourcemap-codec@1.5.4': {}
+
+  '@nodelib/fs.scandir@2.1.5':
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+
+  '@nodelib/fs.stat@2.0.5': {}
+
+  '@nodelib/fs.walk@1.2.8':
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.19.1
+
+  '@types/json-schema@7.0.15': {}
+
+  '@types/semver@7.7.0': {}
+
+  '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)':
+    dependencies:
+      '@eslint-community/regexpp': 4.12.1
+      '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.9.2)
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.9.2)
+      '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.2)
+      debug: 4.4.1
+      eslint: 8.57.1
+      graphemer: 1.4.0
+      ignore: 5.3.2
+      natural-compare-lite: 1.4.0
+      semver: 7.7.2
+      tsutils: 3.21.0(typescript@5.9.2)
+    optionalDependencies:
+      typescript: 5.9.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.9.2)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.2)
+      debug: 4.4.1
+      eslint: 8.57.1
+    optionalDependencies:
+      typescript: 5.9.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/scope-manager@5.62.0':
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/visitor-keys': 5.62.0
+
+  '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.9.2)':
+    dependencies:
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.2)
+      '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.9.2)
+      debug: 4.4.1
+      eslint: 8.57.1
+      tsutils: 3.21.0(typescript@5.9.2)
+    optionalDependencies:
+      typescript: 5.9.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/types@5.62.0': {}
+
+  '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.2)':
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/visitor-keys': 5.62.0
+      debug: 4.4.1
+      globby: 11.1.0
+      is-glob: 4.0.3
+      semver: 7.7.2
+      tsutils: 3.21.0(typescript@5.9.2)
+    optionalDependencies:
+      typescript: 5.9.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.9.2)':
+    dependencies:
+      '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1)
+      '@types/json-schema': 7.0.15
+      '@types/semver': 7.7.0
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.2)
+      eslint: 8.57.1
+      eslint-scope: 5.1.1
+      semver: 7.7.2
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  '@typescript-eslint/visitor-keys@5.62.0':
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      eslint-visitor-keys: 3.4.3
+
+  '@ungap/structured-clone@1.3.0': {}
+
+  '@vitejs/plugin-vue@4.6.2(vite@4.5.14)(vue@3.5.18(typescript@5.9.2))':
+    dependencies:
+      vite: 4.5.14
+      vue: 3.5.18(typescript@5.9.2)
+
+  '@vue/compiler-core@3.5.18':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/shared': 3.5.18
+      entities: 4.5.0
+      estree-walker: 2.0.2
+      source-map-js: 1.2.1
+
+  '@vue/compiler-dom@3.5.18':
+    dependencies:
+      '@vue/compiler-core': 3.5.18
+      '@vue/shared': 3.5.18
+
+  '@vue/compiler-sfc@3.5.18':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/compiler-core': 3.5.18
+      '@vue/compiler-dom': 3.5.18
+      '@vue/compiler-ssr': 3.5.18
+      '@vue/shared': 3.5.18
+      estree-walker: 2.0.2
+      magic-string: 0.30.17
+      postcss: 8.5.6
+      source-map-js: 1.2.1
+
+  '@vue/compiler-ssr@3.5.18':
+    dependencies:
+      '@vue/compiler-dom': 3.5.18
+      '@vue/shared': 3.5.18
+
+  '@vue/devtools-api@6.6.4': {}
+
+  '@vue/reactivity@3.5.18':
+    dependencies:
+      '@vue/shared': 3.5.18
+
+  '@vue/runtime-core@3.5.18':
+    dependencies:
+      '@vue/reactivity': 3.5.18
+      '@vue/shared': 3.5.18
+
+  '@vue/runtime-dom@3.5.18':
+    dependencies:
+      '@vue/reactivity': 3.5.18
+      '@vue/runtime-core': 3.5.18
+      '@vue/shared': 3.5.18
+      csstype: 3.1.3
+
+  '@vue/server-renderer@3.5.18(vue@3.5.18(typescript@5.9.2))':
+    dependencies:
+      '@vue/compiler-ssr': 3.5.18
+      '@vue/shared': 3.5.18
+      vue: 3.5.18(typescript@5.9.2)
+
+  '@vue/shared@3.5.18': {}
+
+  acorn-jsx@5.3.2(acorn@8.15.0):
+    dependencies:
+      acorn: 8.15.0
+
+  acorn@8.15.0: {}
+
+  ajv@6.12.6:
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+
+  ansi-regex@5.0.1: {}
+
+  ansi-styles@4.3.0:
+    dependencies:
+      color-convert: 2.0.1
+
+  argparse@2.0.1: {}
+
+  array-union@2.1.0: {}
+
+  asynckit@0.4.0: {}
+
+  axios@1.11.0:
+    dependencies:
+      follow-redirects: 1.15.11
+      form-data: 4.0.4
+      proxy-from-env: 1.1.0
+    transitivePeerDependencies:
+      - debug
+
+  balanced-match@1.0.2: {}
+
+  boolbase@1.0.0: {}
+
+  brace-expansion@1.1.12:
+    dependencies:
+      balanced-match: 1.0.2
+      concat-map: 0.0.1
+
+  braces@3.0.3:
+    dependencies:
+      fill-range: 7.1.1
+
+  call-bind-apply-helpers@1.0.2:
+    dependencies:
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+
+  callsites@3.1.0: {}
+
+  chalk@4.1.2:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+
+  color-convert@2.0.1:
+    dependencies:
+      color-name: 1.1.4
+
+  color-name@1.1.4: {}
+
+  combined-stream@1.0.8:
+    dependencies:
+      delayed-stream: 1.0.0
+
+  concat-map@0.0.1: {}
+
+  cross-spawn@7.0.6:
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+
+  cssesc@3.0.0: {}
+
+  csstype@3.1.3: {}
+
+  debug@4.4.1:
+    dependencies:
+      ms: 2.1.3
+
+  deep-is@0.1.4: {}
+
+  delayed-stream@1.0.0: {}
+
+  dir-glob@3.0.1:
+    dependencies:
+      path-type: 4.0.0
+
+  doctrine@3.0.0:
+    dependencies:
+      esutils: 2.0.3
+
+  dunder-proto@1.0.1:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      es-errors: 1.3.0
+      gopd: 1.2.0
+
+  entities@4.5.0: {}
+
+  es-define-property@1.0.1: {}
+
+  es-errors@1.3.0: {}
+
+  es-object-atoms@1.1.1:
+    dependencies:
+      es-errors: 1.3.0
+
+  es-set-tostringtag@2.1.0:
+    dependencies:
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      has-tostringtag: 1.0.2
+      hasown: 2.0.2
+
+  esbuild@0.18.20:
+    optionalDependencies:
+      '@esbuild/android-arm': 0.18.20
+      '@esbuild/android-arm64': 0.18.20
+      '@esbuild/android-x64': 0.18.20
+      '@esbuild/darwin-arm64': 0.18.20
+      '@esbuild/darwin-x64': 0.18.20
+      '@esbuild/freebsd-arm64': 0.18.20
+      '@esbuild/freebsd-x64': 0.18.20
+      '@esbuild/linux-arm': 0.18.20
+      '@esbuild/linux-arm64': 0.18.20
+      '@esbuild/linux-ia32': 0.18.20
+      '@esbuild/linux-loong64': 0.18.20
+      '@esbuild/linux-mips64el': 0.18.20
+      '@esbuild/linux-ppc64': 0.18.20
+      '@esbuild/linux-riscv64': 0.18.20
+      '@esbuild/linux-s390x': 0.18.20
+      '@esbuild/linux-x64': 0.18.20
+      '@esbuild/netbsd-x64': 0.18.20
+      '@esbuild/openbsd-x64': 0.18.20
+      '@esbuild/sunos-x64': 0.18.20
+      '@esbuild/win32-arm64': 0.18.20
+      '@esbuild/win32-ia32': 0.18.20
+      '@esbuild/win32-x64': 0.18.20
+
+  escape-string-regexp@4.0.0: {}
+
+  eslint-config-prettier@8.10.2(eslint@8.57.1):
+    dependencies:
+      eslint: 8.57.1
+
+  eslint-plugin-prettier@4.2.5(eslint-config-prettier@8.10.2(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8):
+    dependencies:
+      eslint: 8.57.1
+      prettier: 2.8.8
+      prettier-linter-helpers: 1.0.0
+    optionalDependencies:
+      eslint-config-prettier: 8.10.2(eslint@8.57.1)
+
+  eslint-plugin-vue@9.33.0(eslint@8.57.1):
+    dependencies:
+      '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1)
+      eslint: 8.57.1
+      globals: 13.24.0
+      natural-compare: 1.4.0
+      nth-check: 2.1.1
+      postcss-selector-parser: 6.1.2
+      semver: 7.7.2
+      vue-eslint-parser: 9.4.3(eslint@8.57.1)
+      xml-name-validator: 4.0.0
+    transitivePeerDependencies:
+      - supports-color
+
+  eslint-scope@5.1.1:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 4.3.0
+
+  eslint-scope@7.2.2:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+
+  eslint-visitor-keys@3.4.3: {}
+
+  eslint@8.57.1:
+    dependencies:
+      '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1)
+      '@eslint-community/regexpp': 4.12.1
+      '@eslint/eslintrc': 2.1.4
+      '@eslint/js': 8.57.1
+      '@humanwhocodes/config-array': 0.13.0
+      '@humanwhocodes/module-importer': 1.0.1
+      '@nodelib/fs.walk': 1.2.8
+      '@ungap/structured-clone': 1.3.0
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.6
+      debug: 4.4.1
+      doctrine: 3.0.0
+      escape-string-regexp: 4.0.0
+      eslint-scope: 7.2.2
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      esquery: 1.6.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.24.0
+      graphemer: 1.4.0
+      ignore: 5.3.2
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      is-path-inside: 3.0.3
+      js-yaml: 4.1.0
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.4
+      strip-ansi: 6.0.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+
+  espree@9.6.1:
+    dependencies:
+      acorn: 8.15.0
+      acorn-jsx: 5.3.2(acorn@8.15.0)
+      eslint-visitor-keys: 3.4.3
+
+  esquery@1.6.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  esrecurse@4.3.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  estraverse@4.3.0: {}
+
+  estraverse@5.3.0: {}
+
+  estree-walker@2.0.2: {}
+
+  esutils@2.0.3: {}
+
+  fast-deep-equal@3.1.3: {}
+
+  fast-diff@1.3.0: {}
+
+  fast-glob@3.3.3:
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.8
+
+  fast-json-stable-stringify@2.1.0: {}
+
+  fast-levenshtein@2.0.6: {}
+
+  fastq@1.19.1:
+    dependencies:
+      reusify: 1.1.0
+
+  file-entry-cache@6.0.1:
+    dependencies:
+      flat-cache: 3.2.0
+
+  fill-range@7.1.1:
+    dependencies:
+      to-regex-range: 5.0.1
+
+  find-up@5.0.0:
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+
+  flat-cache@3.2.0:
+    dependencies:
+      flatted: 3.3.3
+      keyv: 4.5.4
+      rimraf: 3.0.2
+
+  flatted@3.3.3: {}
+
+  follow-redirects@1.15.11: {}
+
+  form-data@4.0.4:
+    dependencies:
+      asynckit: 0.4.0
+      combined-stream: 1.0.8
+      es-set-tostringtag: 2.1.0
+      hasown: 2.0.2
+      mime-types: 2.1.35
+
+  fs.realpath@1.0.0: {}
+
+  fsevents@2.3.3:
+    optional: true
+
+  function-bind@1.1.2: {}
+
+  get-intrinsic@1.3.0:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      es-define-property: 1.0.1
+      es-errors: 1.3.0
+      es-object-atoms: 1.1.1
+      function-bind: 1.1.2
+      get-proto: 1.0.1
+      gopd: 1.2.0
+      has-symbols: 1.1.0
+      hasown: 2.0.2
+      math-intrinsics: 1.1.0
+
+  get-proto@1.0.1:
+    dependencies:
+      dunder-proto: 1.0.1
+      es-object-atoms: 1.1.1
+
+  glob-parent@5.1.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob-parent@6.0.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob@7.2.3:
+    dependencies:
+      fs.realpath: 1.0.0
+      inflight: 1.0.6
+      inherits: 2.0.4
+      minimatch: 3.1.2
+      once: 1.4.0
+      path-is-absolute: 1.0.1
+
+  globals@13.24.0:
+    dependencies:
+      type-fest: 0.20.2
+
+  globby@11.1.0:
+    dependencies:
+      array-union: 2.1.0
+      dir-glob: 3.0.1
+      fast-glob: 3.3.3
+      ignore: 5.3.2
+      merge2: 1.4.1
+      slash: 3.0.0
+
+  gopd@1.2.0: {}
+
+  graphemer@1.4.0: {}
+
+  has-flag@4.0.0: {}
+
+  has-symbols@1.1.0: {}
+
+  has-tostringtag@1.0.2:
+    dependencies:
+      has-symbols: 1.1.0
+
+  hasown@2.0.2:
+    dependencies:
+      function-bind: 1.1.2
+
+  ignore@5.3.2: {}
+
+  import-fresh@3.3.1:
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
+
+  imurmurhash@0.1.4: {}
+
+  inflight@1.0.6:
+    dependencies:
+      once: 1.4.0
+      wrappy: 1.0.2
+
+  inherits@2.0.4: {}
+
+  is-extglob@2.1.1: {}
+
+  is-glob@4.0.3:
+    dependencies:
+      is-extglob: 2.1.1
+
+  is-number@7.0.0: {}
+
+  is-path-inside@3.0.3: {}
+
+  isexe@2.0.0: {}
+
+  js-yaml@4.1.0:
+    dependencies:
+      argparse: 2.0.1
+
+  json-buffer@3.0.1: {}
+
+  json-schema-traverse@0.4.1: {}
+
+  json-stable-stringify-without-jsonify@1.0.1: {}
+
+  keyv@4.5.4:
+    dependencies:
+      json-buffer: 3.0.1
+
+  levn@0.4.1:
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+
+  locate-path@6.0.0:
+    dependencies:
+      p-locate: 5.0.0
+
+  lodash.merge@4.6.2: {}
+
+  lodash@4.17.21: {}
+
+  magic-string@0.30.17:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.4
+
+  math-intrinsics@1.1.0: {}
+
+  merge2@1.4.1: {}
+
+  micromatch@4.0.8:
+    dependencies:
+      braces: 3.0.3
+      picomatch: 2.3.1
+
+  mime-db@1.52.0: {}
+
+  mime-types@2.1.35:
+    dependencies:
+      mime-db: 1.52.0
+
+  minimatch@3.1.2:
+    dependencies:
+      brace-expansion: 1.1.12
+
+  ms@2.1.3: {}
+
+  nanoid@3.3.11: {}
+
+  natural-compare-lite@1.4.0: {}
+
+  natural-compare@1.4.0: {}
+
+  nth-check@2.1.1:
+    dependencies:
+      boolbase: 1.0.0
+
+  once@1.4.0:
+    dependencies:
+      wrappy: 1.0.2
+
+  optionator@0.9.4:
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.5
+
+  p-limit@3.1.0:
+    dependencies:
+      yocto-queue: 0.1.0
+
+  p-locate@5.0.0:
+    dependencies:
+      p-limit: 3.1.0
+
+  parent-module@1.0.1:
+    dependencies:
+      callsites: 3.1.0
+
+  path-exists@4.0.0: {}
+
+  path-is-absolute@1.0.1: {}
+
+  path-key@3.1.1: {}
+
+  path-type@4.0.0: {}
+
+  picocolors@1.1.1: {}
+
+  picomatch@2.3.1: {}
+
+  pinia@2.3.1(typescript@5.9.2)(vue@3.5.18(typescript@5.9.2)):
+    dependencies:
+      '@vue/devtools-api': 6.6.4
+      vue: 3.5.18(typescript@5.9.2)
+      vue-demi: 0.14.10(vue@3.5.18(typescript@5.9.2))
+    optionalDependencies:
+      typescript: 5.9.2
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+
+  postcss-selector-parser@6.1.2:
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
+  postcss@8.5.6:
+    dependencies:
+      nanoid: 3.3.11
+      picocolors: 1.1.1
+      source-map-js: 1.2.1
+
+  prelude-ls@1.2.1: {}
+
+  prettier-linter-helpers@1.0.0:
+    dependencies:
+      fast-diff: 1.3.0
+
+  prettier@2.8.8: {}
+
+  proxy-from-env@1.1.0: {}
+
+  punycode@2.3.1: {}
+
+  queue-microtask@1.2.3: {}
+
+  resolve-from@4.0.0: {}
+
+  reusify@1.1.0: {}
+
+  rimraf@3.0.2:
+    dependencies:
+      glob: 7.2.3
+
+  rollup@3.29.5:
+    optionalDependencies:
+      fsevents: 2.3.3
+
+  run-parallel@1.2.0:
+    dependencies:
+      queue-microtask: 1.2.3
+
+  semver@7.7.2: {}
+
+  shebang-command@2.0.0:
+    dependencies:
+      shebang-regex: 3.0.0
+
+  shebang-regex@3.0.0: {}
+
+  slash@3.0.0: {}
+
+  source-map-js@1.2.1: {}
+
+  strip-ansi@6.0.1:
+    dependencies:
+      ansi-regex: 5.0.1
+
+  strip-json-comments@3.1.1: {}
+
+  supports-color@7.2.0:
+    dependencies:
+      has-flag: 4.0.0
+
+  text-table@0.2.0: {}
+
+  to-regex-range@5.0.1:
+    dependencies:
+      is-number: 7.0.0
+
+  tslib@1.14.1: {}
+
+  tsutils@3.21.0(typescript@5.9.2):
+    dependencies:
+      tslib: 1.14.1
+      typescript: 5.9.2
+
+  type-check@0.4.0:
+    dependencies:
+      prelude-ls: 1.2.1
+
+  type-fest@0.20.2: {}
+
+  typescript@5.9.2: {}
+
+  uri-js@4.4.1:
+    dependencies:
+      punycode: 2.3.1
+
+  util-deprecate@1.0.2: {}
+
+  vite@4.5.14:
+    dependencies:
+      esbuild: 0.18.20
+      postcss: 8.5.6
+      rollup: 3.29.5
+    optionalDependencies:
+      fsevents: 2.3.3
+
+  vue-demi@0.14.10(vue@3.5.18(typescript@5.9.2)):
+    dependencies:
+      vue: 3.5.18(typescript@5.9.2)
+
+  vue-eslint-parser@9.4.3(eslint@8.57.1):
+    dependencies:
+      debug: 4.4.1
+      eslint: 8.57.1
+      eslint-scope: 7.2.2
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      esquery: 1.6.0
+      lodash: 4.17.21
+      semver: 7.7.2
+    transitivePeerDependencies:
+      - supports-color
+
+  vue-router@4.5.1(vue@3.5.18(typescript@5.9.2)):
+    dependencies:
+      '@vue/devtools-api': 6.6.4
+      vue: 3.5.18(typescript@5.9.2)
+
+  vue@3.5.18(typescript@5.9.2):
+    dependencies:
+      '@vue/compiler-dom': 3.5.18
+      '@vue/compiler-sfc': 3.5.18
+      '@vue/runtime-dom': 3.5.18
+      '@vue/server-renderer': 3.5.18(vue@3.5.18(typescript@5.9.2))
+      '@vue/shared': 3.5.18
+    optionalDependencies:
+      typescript: 5.9.2
+
+  which@2.0.2:
+    dependencies:
+      isexe: 2.0.0
+
+  word-wrap@1.2.5: {}
+
+  wrappy@1.0.2: {}
+
+  xml-name-validator@4.0.0: {}
+
+  yocto-queue@0.1.0: {}

+ 11 - 0
xinkeaboard-promotion-portal/src/App.vue

@@ -0,0 +1,11 @@
+<template>
+  <router-view></router-view>
+</template>
+
+<script setup lang="ts">
+// 这里写你的业务逻辑
+</script>
+
+<style>
+/* 全局样式 */
+</style>

+ 22 - 0
xinkeaboard-promotion-portal/src/components/HelloWorld.vue

@@ -0,0 +1,22 @@
+<template>
+  <div>
+    <h1>招商门户网站</h1>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { useMainStore } from '../store'
+
+const store = useMainStore()
+</script>
+
+<style scoped>
+h1 {
+  width: 100%;
+  text-align: center;
+  color: #42b983;
+}
+button {
+  margin-top: 1em;
+}
+</style>

+ 9 - 0
xinkeaboard-promotion-portal/src/main.ts

@@ -0,0 +1,9 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import { createPinia } from 'pinia'
+
+const app = createApp(App)
+app.use(createPinia())
+app.use(router)
+app.mount('#app')

+ 16 - 0
xinkeaboard-promotion-portal/src/router/index.ts

@@ -0,0 +1,16 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const routes = [
+  {
+    path: '/',
+    name: 'Home',
+    component: () => import('../components/HelloWorld.vue'),
+  },
+]
+
+const router = createRouter({
+  history: createWebHistory(),
+  routes,
+})
+
+export default router

+ 12 - 0
xinkeaboard-promotion-portal/src/store/index.ts

@@ -0,0 +1,12 @@
+import { defineStore } from 'pinia'
+
+export const useMainStore = defineStore('main', {
+  state: () => ({
+    count: 0,
+  }),
+  actions: {
+    increment() {
+      this.count++
+    },
+  },
+})

+ 132 - 0
xinkeaboard-promotion-portal/src/utils/http.ts

@@ -0,0 +1,132 @@
+import axios, {
+  AxiosInstance,
+  AxiosRequestConfig,
+  AxiosResponse,
+  Canceler,
+  AxiosError
+} from 'axios';
+
+type RequestInterceptor = (
+  config: AxiosRequestConfig
+) => AxiosRequestConfig | Promise<AxiosRequestConfig>;
+type ResponseInterceptor = (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
+
+interface AxiosInterceptorOptions {
+  requestInterceptors?: RequestInterceptor[];
+  responseInterceptors?: ResponseInterceptor[];
+}
+
+class AxiosHttp {
+  private axiosInstance: AxiosInstance;
+  private cancelMap = new Map<string, Canceler>();
+
+  constructor(config?: AxiosRequestConfig, options?: AxiosInterceptorOptions) {
+    this.axiosInstance = axios.create(config);
+
+    // 添加请求拦截器
+    options?.requestInterceptors?.forEach((interceptor) => {
+      this.axiosInstance.interceptors.request.use(
+        async (config: any) => {
+          config = await interceptor(config);
+          return config;
+        },
+        (error: AxiosError) => Promise.reject(error)
+      );
+    });
+
+    // 添加响应拦截器
+    options?.responseInterceptors?.forEach((interceptor) => {
+      this.axiosInstance.interceptors.response.use(
+        async (response: AxiosResponse) => {
+          response = await interceptor(response);
+          return response;
+        },
+        (error: AxiosError) => Promise.reject(error)
+      );
+    });
+
+    // 统一请求拦截 - 生成取消Token
+    this.axiosInstance.interceptors.request.use((config) => {
+      const requestKey = this.getRequestKey(config);
+      if (this.cancelMap.has(requestKey)) {
+        // 取消重复请求
+        const cancel = this.cancelMap.get(requestKey);
+        cancel?.(`取消重复请求: ${requestKey}`);
+        this.cancelMap.delete(requestKey);
+      }
+      config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
+        this.cancelMap.set(requestKey, cancel);
+      });
+      return config;
+    });
+
+    // 请求完成后清除取消函数
+    this.axiosInstance.interceptors.response.use(
+      (response: AxiosResponse) => {
+        const requestKey = this.getRequestKey(response.config);
+        this.cancelMap.delete(requestKey);
+        return response;
+      },
+      (error: AxiosError) => {
+        if (axios.isCancel(error)) {
+          console.warn(error.message);
+        }
+        if (error.config) {
+          const requestKey = this.getRequestKey(error.config);
+          this.cancelMap.delete(requestKey);
+        }
+        return Promise.reject(error);
+      }
+    );
+  }
+
+  private getRequestKey(config: AxiosRequestConfig): string {
+    const url = config.url || '';
+    const method = config.method || 'get';
+    const params = config.params ? JSON.stringify(config.params) : '';
+    const data = config.data ? JSON.stringify(config.data) : '';
+    return [method, url, params, data].join('&');
+  }
+
+  request<T = any>(config: AxiosRequestConfig): Promise<T> {
+    return this.axiosInstance.request<T>(config).then((res: AxiosResponse) => res.data);
+  }
+
+  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
+    return this.request<T>({ ...config, method: 'get', url });
+  }
+
+  post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
+    return this.request<T>({ ...config, method: 'post', url, data });
+  }
+}
+
+const api = new AxiosHttp(
+  { baseURL: '/', timeout: 5000 },
+  {
+    requestInterceptors: [
+      (config) => {
+        config.headers = config.headers || {};
+        config.headers.Authorization = 'Bearer token';
+        return config;
+      }
+    ],
+    responseInterceptors: [
+      (response) => {
+        if (response.status !== 200) {
+          throw new Error('请求失败');
+        }
+        return response;
+      }
+    ]
+  }
+);
+
+// api
+//   .get('/users')
+//   .then((data) => console.log(data))
+//   .catch((err) => console.error(err.message));
+
+// // 同时重复请求会取消前一个请求
+// api.get('/users');
+// api.get('/users'); // 这会取消上一个

+ 21 - 0
xinkeaboard-promotion-portal/tsconfig.json

@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "strict": true,
+    "jsx": "preserve",
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    "esModuleInterop": true,
+    "lib": ["ESNext", "DOM"],
+    "skipLibCheck": true,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["src/*"]
+    }
+  },
+  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
+  "exclude": ["node_modules"]
+}

+ 11 - 0
xinkeaboard-promotion-portal/vite.config.ts

@@ -0,0 +1,11 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+  plugins: [vue()],
+  resolve: {
+    alias: {
+      '@': '/src'
+    }
+  }
+})

+ 15 - 1
xinkeaboard-seller/src/components/SldEditFormCom/SldEditFormCom.js

@@ -2,6 +2,7 @@ import React, { Component, Fragment } from 'react';
 import { Form, Select, Input,InputNumber,DatePicker,TreeSelect,Cascader,Checkbox,Radio } from 'antd';
 import global from '@/global.less';
 import { sldInputAfterAddons, } from '@/utils/utils';
+import { emojiRegex } from "@/utils/regex";
 import styles from './SldEditFormCom.less';
 const FormItem = Form.Item;
 const { RangePicker } = DatePicker;
@@ -43,13 +44,26 @@ export default  class SldEditFormCom extends Component {
     	  //普通输入框
       item_width  = item_width!=undefined?item_width:'auto'
 			if(val.type == 'input'){
+        // 统一规则定义
+        const unifyInputRules = [
+          {
+            validator: (_, value, callback) => {
+              const hasEmoji = emojiRegex.test(value);
+              if (hasEmoji) {
+                callback('不支持输入表情符号');
+              } else {
+                callback();
+              }
+            },
+          },
+        ];
 				return (<FormItem
 							key={index}
 							label={val.label}
 							extra={val.extra}
               style={{width:val.width!=undefined?val.width+80:250}}
 						>
-							{getFieldDecorator(val.name,{initialValue:val.initialValue,rules:val.rules})(
+							{getFieldDecorator(val.name,{initialValue:val.initialValue,rules: [...(val.rules || []), ...unifyInputRules]})(
 								<Input maxLength={val.maxLength!=undefined&&val.maxLength?val.maxLength:99999999} className={styles.item}  disabled={val.disable} placeholder={val.placeholder}/>
 							)}
 						</FormItem>

+ 15 - 1
xinkeaboard-seller/src/components/SldTableRowThree/index.js

@@ -8,6 +8,7 @@ import {
 import global from '@/global.less';
 import styles from './index.less';
 import { sldInputAfterAddons, sldBeforeUpload,input_limit_length ,sldComLanguage,getLocalStorageStingVal} from '@/utils/utils';
+import { emojiRegex } from "@/utils/regex";
 import { Scrollbars } from 'react-custom-scrollbars';
 import StandardTable from '@/components/StandardTable';
 
@@ -80,12 +81,25 @@ export default class SldTableRowTwo extends PureComponent {
       </div>
     );
     if (val.type == 'input') {
+      // 统一规则定义
+      const unifyInputRules = [
+        {
+          validator: (_, value, callback) => {
+            const hasEmoji = emojiRegex.test(value);
+            if (hasEmoji) {
+              callback('不支持输入表情符号');
+            } else {
+              callback();
+            }
+          },
+        },
+      ];
       return (<FormItem
           key={index}
           extra={val.extra}
           style={{width: `${val.ipwidth != undefined ? val.ipwidth : 80}%`}}
         >
-          {getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
+          {getFieldDecorator(val.name, { initialValue: val.initialValue, rules: [...(val.rules || []), ...unifyInputRules] })(
             <Input maxLength={val.maxLength!=undefined&&val.maxLength?val.maxLength:input_limit_length} disabled={val.disable != undefined ? val.disable : false} className={styles.item}
                    placeholder={val.placeholder}/>,
           )}

+ 17 - 2
xinkeaboard-seller/src/components/SldTableRowTwo/index.js

@@ -32,6 +32,7 @@ import {
   sldComLanguage,
   sldBeforeMoreUpload,
 } from '@/utils/utils';
+import { emojiRegex } from "@/utils/regex";
 import {reserveInfoLimitType} from '@/utils/util_data';
 import ALibbSvg from '@/components/ALibbSvg';
 
@@ -130,15 +131,29 @@ export default class SldTableRowTwo extends PureComponent {
       </div>
     );
     if (val.type == 'input') {
+      // 统一规则定义
+      const unifyInputRules = [
+        {
+          validator: (_, value, callback) => {
+            const hasEmoji = emojiRegex.test(value);
+            if (hasEmoji) {
+              callback('不支持输入表情符号');
+            } else {
+              callback();
+            }
+          },
+        },
+      ];
       return (<FormItem
           key={index}
           extra={val.extra}
           style={{ width: '80%' }}
         >
-          {getFieldDecorator(val.name, { initialValue: val.initialValue, rules: val.rules })(
+          {getFieldDecorator(val.name, { initialValue: val.initialValue, rules: [...(val.rules || []), ...unifyInputRules] })(
             <Input maxLength={val.maxLength != undefined ? val.maxLength : 250}
                    disabled={val.disable != undefined ? val.disable : false} className={styles.item}
-                   placeholder={val.placeholder}/>,
+                   placeholder={val.placeholder}
+            />,
           )}
         </FormItem>
       );

+ 61 - 18
xinkeaboard-seller/src/components/SldUEditor/index.js

@@ -1,11 +1,12 @@
-import React, { PureComponent, Fragment } from 'react';
-import {apiUrl} from '@/utils/sldconfig.js';
+import React, { PureComponent, Fragment } from "react";
+import { apiUrl } from "@/utils/sldconfig.js";
+import { emojiRegex } from "@/utils/regex";
+import { message } from "antd";
 
 export default class SldUEditor extends PureComponent {
   constructor(props) {
     super(props);
-    this.state = {
-    };
+    this.state = {};
   }
 
   componentDidMount() {
@@ -13,38 +14,80 @@ export default class SldUEditor extends PureComponent {
   }
 
   componentWillReceiveProps(nextProps, nextContext) {
-    if(nextProps.getContentFlag&&!this.props.getContentFlag){
+    if (nextProps.getContentFlag && !this.props.getContentFlag) {
       let con = UE.getEditor(nextProps.id).getContent();
       this.props.getEditorContent(con);
     }
   }
 
   componentWillUnmount() {
-    UE.delEditor(this.props.id)
+    UE.delEditor(this.props.id);
   }
 
   initEditor = () => {
-    const {id,initEditorContent} = this.props;
+    const { id, initEditorContent } = this.props;
     console.info();
-    const ueEditor = UE.getEditor(id,{
-      serverUrl: `${apiUrl}v3/oss/ueditor/upload?configPath=config.json&storeId=`+localStorage.getItem('storeId'),
+    const ueEditor = UE.getEditor(id, {
+      serverUrl:
+        `${apiUrl}v3/oss/ueditor/upload?configPath=config.json&storeId=` +
+        localStorage.getItem("storeId"),
     });
-    ueEditor.ready((editor)=>{
-      if(!editor){
+    ueEditor.ready((editor) => {
+      if (!editor) {
         UE.delEditor(id);
         this.initEditor();
-      }else{
+      } else {
         if (initEditorContent) {
           UE.getEditor(id).setContent(initEditorContent);
         }
+
+        // 监听输入内容变化
+        ueEditor.addListener("contentChange", () => {
+          const content = ueEditor.getContentTxt(); // 纯文本
+          if (this.hasEmoji(content)) {
+            message.warn("监测到输入表情符号,已自动去除");
+            ueEditor.body.innerHTML = ueEditor.body.innerHTML.replace(
+              emojiRegex,
+              ""
+            );
+            ueEditor.focus();
+            const range = ueEditor.selection.getRange();
+            const body = ueEditor.body;
+
+            // 找到最后一个文本节点或者元素节点
+            let lastNode = body.lastChild;
+
+            // 如果最后一个是元素节点,尝试找到它的最后一个文本节点
+            function getLastTextNode(node) {
+              if (node.nodeType === 3) return node; // 文本节点
+              if (!node.hasChildNodes()) return null;
+              return getLastTextNode(node.lastChild);
+            }
+
+            const lastTextNode = getLastTextNode(lastNode) || lastNode;
+
+            // 如果找到文本节点,光标放在文本末尾
+            if (lastTextNode && lastTextNode.nodeType === 3) {
+              range.setStart(lastTextNode, lastTextNode.nodeValue.length);
+            } else {
+              // 否则放在最后元素后面
+              range.setStartAfter(lastNode);
+            }
+
+            range.collapse(true);
+            range.select();
+          }
+        });
       }
-    })
-  }
+    });
+  };
+
+  hasEmoji = (str) => {
+    return emojiRegex.test(str);
+  };
 
   render() {
-    const {id} = this.props
-    return(
-      <div id={id} name="content" type="text/plain"></div>
-    )
+    const { id } = this.props;
+    return <div id={id} name="content" type="text/plain" />;
   }
 }

BIN=BIN
xinkeaboard-seller/src/components/SlideVerify/icons/refresh.png


BIN=BIN
xinkeaboard-seller/src/components/SlideVerify/icons/right.png


BIN=BIN
xinkeaboard-seller/src/components/SlideVerify/icons/success.png


+ 396 - 0
xinkeaboard-seller/src/components/SlideVerify/index.js

@@ -0,0 +1,396 @@
+import React from "react";
+import { Spin } from "antd";
+import { sldComLanguage } from "@/utils/utils";
+import styles from "./index.less";
+
+const PI = Math.PI;
+
+function sum(x, y) {
+  return x + y;
+}
+function square(x) {
+  return x * x;
+}
+
+class SlideVerify extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      success: false,
+      containerActive: false,
+      containerSuccess: false,
+      containerFail: false,
+      sliderLeft: 0,
+      sliderWidth: 0,
+      loadBlock: true,
+      blockX: 0,
+      blockY: 0,
+    };
+
+    this.origin = { x: 0, y: 0 };
+    this.isMouseDown = false;
+    this.timestamp = 0;
+    this.trail = [];
+
+    this.blockRef = React.createRef();
+    this.canvasRef = React.createRef();
+
+    this.img = null;
+
+    this.handleStart = this.handleStart.bind(this);
+    this.handleMove = this.handleMove.bind(this);
+    this.handleEnd = this.handleEnd.bind(this);
+    this.reset = this.reset.bind(this);
+    this.refresh = this.refresh.bind(this);
+  }
+
+  componentDidMount() {
+    this.initCanvas();
+
+    document.addEventListener("mousemove", this.handleMove);
+    document.addEventListener("mouseup", this.handleEnd);
+
+    // 如果需要支持移动端,也加对应touch事件监听
+    document.addEventListener("touchmove", this.handleMove, { passive: false });
+    document.addEventListener("touchend", this.handleEnd);
+  }
+
+  componentWillUnmount() {
+    document.removeEventListener("mousemove", this.handleMove);
+    document.removeEventListener("mouseup", this.handleEnd);
+
+    document.removeEventListener("touchmove", this.handleMove);
+    document.removeEventListener("touchend", this.handleEnd);
+  }
+
+  draw = (ctx, x, y, l, r, operation) => {
+    ctx.beginPath();
+    ctx.moveTo(x, y);
+    ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
+    ctx.lineTo(x + l, y);
+    ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
+    ctx.lineTo(x + l, y + l);
+    ctx.lineTo(x, y + l);
+    ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
+    ctx.lineTo(x, y);
+    ctx.lineWidth = 2;
+    ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
+    ctx.strokeStyle = "rgba(255, 255, 255, 0.7)";
+    ctx.stroke();
+    ctx[operation]();
+    ctx.globalCompositeOperation = "destination-over";
+  };
+
+  getRandomNumberByRange = (start, end) => {
+    return Math.round(Math.random() * (end - start) + start);
+  };
+
+  getRandomImg = (imgs, w, h) => {
+    if (!imgs || imgs.length === 0) {
+      return `https://picsum.photos/300/150?random=${Date.now()}`;
+    }
+    const idx = getRandomNumberByRange(0, imgs.length - 1);
+    return imgs[idx];
+  };
+
+  createImg = (imgs, onload) => {
+    const img = document.createElement("img");
+    img.crossOrigin = "Anonymous";
+    img.onload = onload;
+    img.onerror = () => {
+      img.src = this.getRandomImg(imgs);
+    };
+    img.src = this.getRandomImg(imgs);
+    return img;
+  };
+
+  initCanvas() {
+    const { w, h, l, r, imgs } = this.props;
+    const canvas = this.canvasRef.current;
+    const block = this.blockRef.current;
+    if (!canvas || !block) return;
+
+    this.canvasCtx = canvas.getContext("2d");
+    this.blockCtx = block.getContext("2d", { willReadFrequently: true });
+
+    this.img = this.createImg(imgs, () => {
+      this.setState({ loadBlock: false });
+
+      const L = l + r * 2 + 3;
+      const blockX = this.getRandomNumberByRange(L + 10, w - (L + 10));
+      const blockY = this.getRandomNumberByRange(10 + r * 2, h - (L + 10));
+
+      this.setState({ blockX, blockY });
+
+      if (this.canvasCtx && this.blockCtx) {
+        this.draw(this.canvasCtx, blockX, blockY, l, r, "fill");
+        this.draw(this.blockCtx, blockX, blockY, l, r, "clip");
+
+        this.canvasCtx.drawImage(this.img, 0, 0, w, h);
+        this.blockCtx.drawImage(this.img, 0, 0, w, h);
+
+        const _y = blockY - r * 2 - 1;
+        const imgData = this.blockCtx.getImageData(blockX, _y, L, L);
+        block.width = L;
+        this.blockCtx.putImageData(imgData, 0, _y);
+      }
+
+      if (this.props.onImageLoad) this.props.onImageLoad();
+    });
+  }
+
+  handleStart(e) {
+    if (this.state.success) return;
+
+    const nativeEvent = e.nativeEvent || e;
+
+    if (nativeEvent.touches && nativeEvent.touches.length > 0) {
+      this.origin.x = nativeEvent.touches[0].pageX;
+      this.origin.y = nativeEvent.touches[0].pageY;
+    } else if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
+      this.origin.x = nativeEvent.clientX;
+      this.origin.y = nativeEvent.clientY;
+    }
+    this.isMouseDown = true;
+    this.trail = [];
+    this.timestamp = Date.now();
+  }
+
+  handleMove(e) {
+    if (!this.isMouseDown) return false;
+
+    // 阻止滚动等默认事件
+    e.preventDefault();
+
+    const nativeEvent = e.nativeEvent || e;
+
+    let moveX = 0;
+    let moveY = 0;
+
+    if (nativeEvent.touches && nativeEvent.touches.length > 0) {
+      moveX = nativeEvent.touches[0].pageX - this.origin.x;
+      moveY = nativeEvent.touches[0].pageY - this.origin.y;
+    } else if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
+      moveX = nativeEvent.clientX - this.origin.x;
+      moveY = nativeEvent.clientY - this.origin.y;
+    }
+
+    const { w } = this.props;
+
+    if (moveX < 0 || moveX + 38 >= w) return false;
+
+    this.setState({
+      sliderLeft: moveX,
+      sliderWidth: moveX,
+      containerActive: true,
+      containerFail: false,
+      containerSuccess: false,
+    });
+
+    this.trail.push(moveY);
+  }
+
+  handleEnd(e) {
+    if (!this.isMouseDown) return false;
+    this.isMouseDown = false;
+
+    const nativeEvent = e.nativeEvent || e;
+
+    let moveX;
+
+    if (nativeEvent.changedTouches && nativeEvent.changedTouches.length > 0) {
+      moveX = nativeEvent.changedTouches[0].pageX;
+    } else if ("clientX" in nativeEvent) {
+      moveX = nativeEvent.clientX;
+    } else {
+      moveX = this.origin.x;
+    }
+
+    if (moveX === this.origin.x) return false;
+
+    const timestamp = Date.now() - this.timestamp;
+
+    const { spliced, TuringTest } = this.verify(
+      this.state.sliderLeft,
+      this.state.blockX,
+      this.props.accuracy
+    );
+
+    if (spliced) {
+      if (TuringTest) {
+        this.setState({
+          success: true,
+          containerSuccess: true,
+          containerFail: false,
+          sliderLeft: this.state.blockX,
+          sliderWidth: this.state.blockX,
+        });
+        this.props.onSuccess && this.props.onSuccess(timestamp);
+      } else {
+        this.setState({
+          containerFail: true,
+          containerSuccess: false,
+          sliderLeft: 0,
+          sliderWidth: 0,
+        });
+        this.props.onAgain && this.props.onAgain();
+      }
+    } else {
+      this.setState({
+        containerFail: true,
+        containerSuccess: false,
+        sliderLeft: 0,
+        sliderWidth: 0,
+      });
+      this.refresh();
+    }
+  }
+
+  verify(left, blockX, accuracy) {
+    const arr = this.trail;
+    const sum = (x, y) => x + y;
+    const square = (x) => x * x;
+
+    const average = arr.reduce(sum, 0) / arr.length || 0;
+    const deviations = arr.map((x) => x - average);
+    const stddev = Math.sqrt(
+      deviations.map(square).reduce(sum, 0) / arr.length || 0
+    );
+
+    const leftNum = parseInt(left);
+    accuracy = accuracy <= 1 ? 1 : accuracy > 10 ? 10 : accuracy;
+
+    return {
+      spliced: Math.abs(leftNum - blockX) <= accuracy,
+      TuringTest: average !== stddev,
+    };
+  }
+
+  reset() {
+    const { w, h, l, r, imgs } = this.props;
+    this.setState({
+      success: false,
+      containerActive: false,
+      containerSuccess: false,
+      containerFail: false,
+      sliderLeft: 0,
+      sliderWidth: 0,
+      loadBlock: true,
+    });
+
+    const block = this.blockRef.current;
+    if (block) block.style.left = "0px";
+    if (this.canvasCtx) this.canvasCtx.clearRect(0, 0, w, h);
+    if (this.blockCtx) this.blockCtx.clearRect(0, 0, w, h);
+    if (block) block.width = w;
+
+    this.img.src = this.getRandomImg(imgs);
+  }
+
+  refresh() {
+    this.reset();
+    this.props.onRefresh && this.props.onRefresh();
+  }
+
+  render() {
+    const { w, h, sliderText, show } = this.props;
+    const {
+      loadBlock,
+      containerActive,
+      containerSuccess,
+      containerFail,
+      sliderLeft,
+      sliderWidth,
+      success,
+    } = this.state;
+
+    // 容器className 组合
+    const containerCls = [
+      styles["slide-verify-slider"],
+      containerActive ? styles["container-active"] : "",
+      containerSuccess ? styles["container-success"] : "",
+      containerFail ? styles["container-fail"] : "",
+    ].join(" ");
+
+    return (
+      <div
+        id="slideVerify"
+        className={styles["slide-verify"]}
+        style={{ width: w }}
+        onSelect={(e) => e.preventDefault()}
+      >
+        <Spin spinning={loadBlock}>
+          <canvas
+            ref={this.canvasRef}
+            width={w}
+            height={h}
+            className={styles["slide-verify-canvas"]}
+          />
+
+          {show && (
+            <div
+              className={styles["slide-verify-refresh-icon"]}
+              onClick={this.refresh}
+            >
+              <i className={`iconfont ${styles["icon-refresh"]}`} />
+            </div>
+          )}
+
+          <canvas
+            ref={this.blockRef}
+            width={w}
+            height={h}
+            className={styles["slide-verify-block"]}
+            style={{ left: `${sliderLeft}px`, position: "absolute", top: 0 }}
+          />
+
+          <div className={containerCls}>
+            <div
+              className={styles["slide-verify-slider-mask"]}
+              style={{ width: sliderWidth }}
+            >
+              <div
+                className={styles["slide-verify-slider-mask-item"]}
+                style={{ left: sliderLeft }}
+                onMouseDown={this.handleStart}
+                onTouchStart={this.handleStart}
+                onTouchMove={this.handleMove}
+                onTouchEnd={this.handleEnd}
+              >
+                <img
+                  draggable={false}
+                  src={
+                    success
+                      ? require("./icons/success.png")
+                      : require("./icons/right.png")
+                  }
+                />
+              </div>
+            </div>
+            <span className={styles["slide-verify-slider-text"]}>
+              {sliderText}
+            </span>
+          </div>
+          <div className={styles["bottom-action"]} onClick={this.refresh}>
+            <img src={require("./icons/refresh.png")} />
+            <span>{sldComLanguage('刷新')}</span>
+          </div>
+        </Spin>
+      </div>
+    );
+  }
+}
+
+SlideVerify.defaultProps = {
+  l: 42,
+  r: 10,
+  w: 310,
+  h: 155,
+  sliderText: sldComLanguage("拖动滑块来填充拼图"),
+  accuracy: 5,
+  show: true,
+  imgs: [],
+  interval: 50,
+};
+
+export default SlideVerify;

+ 137 - 0
xinkeaboard-seller/src/components/SlideVerify/index.less

@@ -0,0 +1,137 @@
+@import "../../../src/themeColor.less";
+
+.slide-verify {
+  width: 100%;
+  position: relative;
+
+  canvas {
+    border-radius: 20px;
+  }
+}
+.slide-verify-loading {
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(255, 255, 255, 0.9);
+  z-index: 999;
+  animation: loading-3f647794 1.5s infinite;
+}
+.slide-verify-block {
+  position: absolute;
+  left: 0;
+  top: 0;
+}
+.slide-verify-refresh-icon {
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 34px;
+  height: 34px;
+  cursor: pointer;
+}
+.slide-verify-refresh-icon .iconfont {
+  font-size: 34px;
+  color: #fff;
+}
+.slide-verify-slider {
+  position: relative;
+  text-align: center;
+  width: 100%;
+  height: 50px;
+  line-height: 50px;
+  margin-top: 15px;
+  background: #f7f9fa;
+  color: #45494c;
+  border: 1px solid #e4e7eb;
+  border-radius: 25px;
+}
+.slide-verify-slider-mask {
+  position: absolute;
+  left: 0;
+  top: 0;
+  height: 50px;
+  border-radius: 25px;
+  background: @theme-color;
+}
+.slide-verify-slider-mask-item {
+  position: absolute;
+  left: 0;
+  top: 0;
+  background: #fff;
+  box-shadow: 0 0 3px #0000004d;
+  cursor: pointer;
+  transition: background 0.2s linear;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 50px;
+  height: 50px;
+  border-radius: 100%;
+
+  img {
+    width: 28px;
+  }
+}
+.slide-verify-slider-mask-item:hover {
+  background: #fff;
+}
+
+.container-active .slide-verify-slider-mask {
+  border-width: 1px;
+}
+.container-active .slide-verify-slider-mask-item {
+  top: -1px;
+  border: 1px solid @theme-color;
+}
+.container-success .slide-verify-slider-mask {
+  border: 1px solid @theme-color;
+  background-color: @theme-color;
+}
+.container-success .slide-verify-slider-mask-item {
+  top: -1px;
+  border: 1px solid @theme-color;
+  background-color: @theme-color !important;
+}
+
+.container-fail .slide-verify-slider-mask {
+  border: 1px solid #f57a7a;
+  background-color: #fce1e1;
+}
+.container-fail .slide-verify-slider-mask-item {
+  top: -1px;
+  border: 1px solid #f57a7a;
+  background-color: #f57a7a !important;
+}
+
+.container-active .slide-verify-slider-text,
+.container-success .slide-verify-slider-text,
+.container-fail .slide-verify-slider-text {
+  display: none;
+}
+@keyframes loading {
+  0% {
+    opacity: 0.7;
+  }
+  to {
+    opacity: 9;
+  }
+}
+
+.bottom-action {
+  margin: 10px 0;
+  cursor: pointer;
+  :global {
+    img {
+      width: 18px;
+    }
+
+    span {
+      font-size: 12px;
+      color: rgba(0, 0, 0, 0.85);
+      font-weight: bold;
+      margin-left: 5px;
+    }
+  }
+}

+ 1 - 0
xinkeaboard-seller/src/models/global.js

@@ -94,6 +94,7 @@ export default {
       };
     },
     setCurrentSite(state, { payload }) {
+      localStorage.setItem('currentSite', payload)
       return {
         ...state,
         currentSite: payload,

+ 105 - 66
xinkeaboard-seller/src/pages/User/Login.js

@@ -1,6 +1,7 @@
 import React, { Component } from 'react';
 import { connect } from 'dva';
-import { Form, Input, Modal, Button } from 'antd';
+import { Form, Input, Modal, Button, message } from 'antd';
+import SlideVerify from "@/components/SlideVerify"
 import styles from './Login.less';
 import global from '@/global.less';
 import {
@@ -46,6 +47,7 @@ export default class LoginPage extends Component {
     register_captcha: '',//注册——图形验证码
     login_captcha: '',//登录——图形验证码
     visibleModal: false,
+    visibleModalVerify: false,// 人机验证弹窗
     modal_type: 'register',  //区分忘记密码和立即注册弹框
     visibleModalSuccess: false,
     //商家账号
@@ -141,50 +143,55 @@ export default class LoginPage extends Component {
   //登录操作
   handleSubmits = () => {
     this.props.form.validateFieldsAndScroll(['username', 'password', 'verifyCode'], (err, values) => {
-      if (values.username == undefined || values.username == '') {
-        failTip(`${sldComLanguage('用户名不能为空')}`);
-      } else if (values.password == undefined || values.password == '') {
-        failTip(`${sldComLanguage('密码不能为空')}`);
-      } else if (values.verifyCode == undefined || values.verifyCode == '') {
-        failTip(`${sldComLanguage('验证码不能为空')}`);
-      } else {
-        //用户登录
-        values.verifyKey = this.login_captcha;
-        const { dispatch } = this.props;
-        this.setState({loginLoading: true})
-        dispatch({
-          type: 'login/login',
-          payload: { ...values },
-          callback: (res) => {
-            if (res.state == 200 || res.state == 267) {
-              localStorage.setItem('sld_token', res.data.access_token);
-              localStorage.setItem('sld_refresh_token', res.data.refresh_token);
-              {
-                setLocalStorageTime();
-              }
-              localStorage.setItem('user_info', JSON.stringify({ user_name: res.data.vendorName, vendorMobile: res.data.vendorMobile }));
-              if (res.state == 267) {
-                //登录的时候初始化入驻状态
-                if (res.data.applyState == 0) {
-                  //未入驻
-                  saveSettleData('state', '');
-                  saveSettleData('cur_step', 0);
-                  router.push('/apply/settled_protocol');
-                } else {
-                  saveSettleData('cur_step', 3);
-                  router.push('/apply/open_up');
-                }
+      Object.keys(values).forEach(key => {
+        values[key] = values[key] ? values[key].replace(/\s/g, '') : ''
+      })
+      const { username, password, verifyCode } = values;
+      if (!username) {
+        return failTip(`${sldComLanguage('用户名不能为空')}`);
+      }
+      if (!password) {
+        return failTip(`${sldComLanguage('密码不能为空')}`);
+      } 
+      if (!verifyCode) {
+        return failTip(`${sldComLanguage('验证码不能为空')}`);
+      }
+      //用户登录
+      values.verifyKey = this.login_captcha;
+      const { dispatch } = this.props;
+      this.setState({loginLoading: true})
+      dispatch({
+        type: 'login/login',
+        payload: { ...values },
+        callback: (res) => {
+          if (res.state == 200 || res.state == 267) {
+            localStorage.setItem('sld_token', res.data.access_token);
+            localStorage.setItem('sld_refresh_token', res.data.refresh_token);
+            {
+              setLocalStorageTime();
+            }
+            localStorage.setItem('user_info', JSON.stringify({ user_name: res.data.vendorName, vendorMobile: res.data.vendorMobile }));
+            if (res.state == 267) {
+              //登录的时候初始化入驻状态
+              if (res.data.applyState == 0) {
+                //未入驻
+                saveSettleData('state', '');
+                saveSettleData('cur_step', 0);
+                router.push('/apply/settled_protocol');
               } else {
-                // dispatch({ type: 'global/get_site_list_data' });
+                saveSettleData('cur_step', 3);
+                router.push('/apply/open_up');
               }
             } else {
-              failTip(res.msg);
-              this.getCaptcha('login_captcha');
+              // dispatch({ type: 'global/get_site_list_data' });
             }
-            this.setState({loginLoading: false})
-          },
-        });
-      }
+          } else {
+            failTip(res.msg);
+            this.getCaptcha('login_captcha');
+          }
+          this.setState({loginLoading: false})
+        },
+      });
     });
   };
 
@@ -654,31 +661,8 @@ export default class LoginPage extends Component {
 
   };
 
-  //获取短信验证码
-  getSmsCode(type) {
-    if (this.state.countDownC) {
-      return;
-    } else if (this.state.countDownM) {
-      return;
-    }
-    let mobile = this.props.form.getFieldValue('vendorMobile');
-    let captcha = this.props.form.getFieldValue('verifyCode');//图形验证码
-    if (mobile == undefined || (mobile != undefined && !mobile)) {
-      this.setState({
-        is_show_phone_err: true,
-        phone_error_info: `${sldComLanguage('请输入手机号')}`,
-      });
-    } else if (!sldCheckMobile(mobile)) {
-      this.setState({
-        is_show_phone_err: true,
-        phone_error_info: `${sldComLanguage('请输入正确的手机号')}`,
-      });
-    } else if (type == 'register' && (captcha == undefined || (captcha != undefined && !captcha))) {
-      this.setState({
-        is_show_code_err: true,
-        code_error_info: `${sldComLanguage('请输入图形验证码')}`,
-      });
-    } else {
+  // 获取验证码操作
+  getSmsCodeAction = ({ mobile, type, captcha }) => {
       const { dispatch } = this.props;
       let _this = this;
       let param = {};
@@ -713,7 +697,49 @@ export default class LoginPage extends Component {
           }
         },
       });
+  }
+
+  //获取短信验证码前的校验
+  getSmsCode(type) {
+    if (this.state.countDownC) {
+      return;
+    } else if (this.state.countDownM) {
+      return;
     }
+    let mobile = this.props.form.getFieldValue('vendorMobile');
+    let captcha = this.props.form.getFieldValue('verifyCode');//图形验证码
+    if (mobile == undefined || (mobile != undefined && !mobile)) {
+      this.setState({
+        is_show_phone_err: true,
+        phone_error_info: `${sldComLanguage('请输入手机号')}`,
+      });
+    } else if (!sldCheckMobile(mobile)) {
+      this.setState({
+        is_show_phone_err: true,
+        phone_error_info: `${sldComLanguage('请输入正确的手机号')}`,
+      });
+    } else if (type == 'register' && (captcha == undefined || (captcha != undefined && !captcha))) {
+      this.setState({
+        is_show_code_err: true,
+        code_error_info: `${sldComLanguage('请输入图形验证码')}`,
+      });
+    } else if (type === 'retrieve'){
+      this.setState({visibleModalVerify: true})
+    } else {
+      this.getSmsCodeAction({ mobile, type, captcha })
+    }
+  }
+
+  handleCancelVeriyModal = () => {
+    this.setState({visibleModalVerify: false})
+  }
+
+  verifySuccess = () => {
+    message.success(sldComLanguage('验证成功'));
+    const mobile = this.props.form.getFieldValue('vendorMobile');
+    const captcha = this.props.form.getFieldValue('verifyCode');
+    this.setState({visibleModalVerify: false})
+    this.getSmsCodeAction({ mobile, type: 'retrieve', captcha })
   }
 
   render() {
@@ -728,6 +754,7 @@ export default class LoginPage extends Component {
       title, 
       visibleModal, 
       visibleModalSuccess, 
+      visibleModalVerify,
       register_error_info, 
       is_show_registe_err, 
       countDownM,
@@ -1111,6 +1138,18 @@ export default class LoginPage extends Component {
                     onClick={this.handleSuccessBtn}>{sldComLanguage('点击入驻')}</Button>
           </div>
         </Modal>
+
+        { /* 人机验证 */ }
+        <Modal
+          className={styles.verifyModal}
+          title={'滑动验证'}
+          visible={visibleModalVerify}
+          footer={false}
+          onCancel={this.handleCancelVeriyModal}
+          width={500}
+        >
+          {visibleModalVerify &&  <SlideVerify w={450} h={220} onSuccess={this.verifySuccess}/> }
+        </Modal>
       </div>
     );
   }

+ 24 - 0
xinkeaboard-seller/src/pages/User/Login.less

@@ -322,3 +322,27 @@
     color: #fff;
   }
 }
+
+.verifyModal {
+  :global {
+    .ant-modal-header {
+      height: 50px;
+      border-bottom: none;
+      background-color: transparent !important;
+
+      .ant-modal-title {
+        text-align: center;
+        color: rgba(0, 0, 0, 0.85) !important;
+      }
+    }
+
+    .ant-modal-body {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+    .ant-modal-close-x svg{
+      color: rgba(0, 0, 0, 0.85) !important;
+    }
+  }
+}

+ 12 - 0
xinkeaboard-seller/src/utils/regex.js

@@ -0,0 +1,12 @@
+export const emojiRegex = new RegExp(
+  [
+    "[\u{1F600}-\u{1F64F}]", // 😀-🙏 表情
+    "[\u{1F300}-\u{1F5FF}]", // 🌐-🗿 符号&象形文字
+    "[\u{1F680}-\u{1F6FF}]", // 🚀-🛺 交通工具
+    "[\u{2600}-\u{26FF}]", // ☀-⛿ 杂项符号
+    "[\u{2700}-\u{27BF}]", // ✀-➿ 装饰符号
+    "[\u{1F900}-\u{1F9FF}]", // 🤰-🦿 补充符号
+    "[\u{1FA70}-\u{1FAFF}]", // 🪀-🪿 扩展符号
+  ].join("|"),
+  "gu"
+);

+ 1 - 1
xinkeaboard-seller/src/utils/utils.js

@@ -1379,7 +1379,7 @@ export function getSldStatYTitle() {
  * */
 export function sldComRequest(method, url, params, data_type = '') {
   const state = window.g_app._store.getState();
-  const currentSite = state.global.currentSite;
+  const currentSite = state.global.currentSite || localStorage.getItem('currentSite');
   const currentPath = state.routing.location.pathname;
   if (!currentPath.includes('/apply') && !currentPath.includes('/user/login')) {
     params = Object.assign({}, params ?? {}, { webSite: currentSite })

+ 5 - 0
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/CommonConst.java

@@ -15,4 +15,9 @@ public class CommonConst {
      */
     public static final String WX_ACCESS_TOKEN = "wx_access_token";
 
+    /**
+     * 默认的网站
+     */
+    public static final String DEFAULT_WEBSITE = "1";
+
 }

+ 12 - 0
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/RedisConst.java

@@ -80,17 +80,29 @@ public class RedisConst {
 
     public static final String SLD_PC_EMAIL_VERIFY_CODE_LIMIT="sld_pc_verify_code_limit:email::";
 
+    public static final String SLD_PC_MOBILE_VERIFY_CODE_LIMIT="sld_pc_verify_code_limit:mobile::";
+
     /**
      * reids中保存邮箱用户注册,key=前缀+email
      */
     public static final String SLD_PC_NEW_REGISTER_USER_EMAIL = "sld_pc_new_register_user:email::";
 
     /**
+     * reids中保存手机用户注册,key=前缀+mobile
+     */
+    public static final String SLD_PC_NEW_REGISTER_USER_MOBILE = "sld_pc_new_register_user:mobile::";
+
+    /**
      * reids中保存邮箱用户忘记密码,key=前缀+email
      */
     public static final String SLD_PC_FORGET_PWD_USER_EMAIL = "sld_pc_forget_pwd_user:email::";
 
     /**
+     * reids中保存手机用户忘记密码,key=前缀+mobile
+     */
+    public static final String SLD_PC_FORGET_PWD_USER_MOBILE = "sld_pc_forget_pwd_user:mobile::";
+
+    /**
      * reids中保存邮箱用户忘记密码,key=前缀+email
      */
     public static final String TIME = "sld_pc_forget_pwd_user:email::";

+ 9 - 0
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/constant/StoreConst.java

@@ -18,6 +18,15 @@ public class StoreConst {
     public static final int STORE_STATE_CLOSE = 2;
     public static final int STORE_STATE_DELETE = 3;
 
+
+    /**
+     * 店铺经营状态 1 资质审核 2装修筹备 3经营中4 暂停经营
+     */
+    public static final int STORE_BUSINESS_STATE_TO_AUDIT = 1;
+    public static final int STORE_BUSINESS_STATE_DECORATION = 2;
+    public static final int STORE_BUSINESS_STATE_OPEN = 3;
+    public static final int STORE_BUSINESS_STATE_CLOSE = 4;
+
     /**
      * 店铺入驻信查重字段类型:1-公司名称;2-店铺名称
      */

+ 6 - 0
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/util/WebUtil.java

@@ -38,6 +38,12 @@ public class WebUtil {
     }
 
 
+    public static String getWebSite(HttpServletRequest request) {
+        String webSite = request.getHeader("Web-Site");
+        return webSite == null ? CommonConst.DEFAULT_WEBSITE : webSite;
+    }
+
+
 
 
     /**

+ 5 - 2
xinkeaboard-server/b2b2c-core/src/main/resources/i18n_en.properties

@@ -1809,7 +1809,7 @@ admin账号不可删除=admin account can not be deleted
 更新直播和短视频设置表失败,请重试=Live updates and short video settings table failed, please try again
 退出成功=exit successfully
 用户名或密码错误=wrong user name or password
-会员邮箱或密码错误=wrong member email or password
+会员账号或密码错误=wrong member email or password
 系统开小差了=System deserted
 账号已被冻结=Account has been frozen
 账号不可用=Account unavailable
@@ -2523,6 +2523,7 @@ pc端注册页面logo=
 榜单分类不存在=
 该邮箱已注册,请登录=This email has been registered, please log in
 邮件不能为空=Email cannot be empty
+手机号码不能为空=Phone number cannot be empty
 验证码不能为空=Verification cannot be empty
 请勿频繁操作,请1分钟后重试=Please do not operate frequently, please retry in 1 minute
 验证码发送失败,请重试=Failed to send verification code, please try again
@@ -2535,9 +2536,11 @@ pc端注册页面logo=
 注册链接不正确,请重新注册=The registration link is incorrect, please register again
 密码不一致,请重新输入=Passwords do not match. Please reenter
 会员邮箱不存在,请重新注册=Member email does not exist, please re register
-会员邮箱已激活,无需重复注册,请登录=Member email has been activated, no need to re register, please log in
+会员手机号不存在,请重新注册=Member phone number does not exist, please re register
+会员账号已激活,无需重复注册,请登录=Member account has been activated, no need to re register, please log in
 注册链接激活码已失效,请重新注册=The registration link activation code has expired, please re register
 会员邮箱账户激活成功=Member email account activated successfully
+会员手机号激活成功=Member phone number activation successful
 注册链接已失效,请重新注册=The registration link has expired, please register again
 发送重置密码邮件失败,请重试=Failed to send the reset password email. Please try again
 该邮箱未激活,请先激活=This mail is not activated, please activate it first

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/dto/FriendLinkAddDTO.java

@@ -13,6 +13,9 @@ public class FriendLinkAddDTO implements Serializable {
 
     private static final long serialVersionUID = -2123262648171965455L;
 
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty(value = "链接名称",required = true)
     private String linkName;
 

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/dto/FriendLinkUpdateDTO.java

@@ -16,6 +16,9 @@ public class FriendLinkUpdateDTO implements Serializable {
     @ApiModelProperty(value = "链接id",required = true)
     private Integer linkId;
 
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty("链接名称")
     private String linkName;
 

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/example/FriendLinkExample.java

@@ -26,6 +26,11 @@ public class FriendLinkExample implements Serializable {
     private Integer linkId;
 
     /**
+     * 站点
+     */
+    private String webSite;
+
+    /**
      * 链接名称
      */
     private String linkName;

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/cms/pojo/FriendLink.java

@@ -14,6 +14,9 @@ public class FriendLink implements Serializable {
     @ApiModelProperty("链接id")
     private Integer linkId;
 
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty("链接名称")
     private String linkName;
 

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/dto/SearchConditionDTO.java

@@ -57,4 +57,7 @@ public class SearchConditionDTO implements Serializable {
 
     @ApiModelProperty("商品新价格")
     private String goodsMoney;
+
+    @ApiModelProperty("商品站点")
+    private String webSite;
 }

+ 6 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/example/GoodsSearchWordsExample.java

@@ -28,6 +28,12 @@ public class GoodsSearchWordsExample implements Serializable {
      */
     private Long wordsId;
 
+
+    /**
+     * 站点
+     */
+    private String webSite;
+
     /**
      * 高频词内容
      */

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/pojo/GoodsSearchWords.java

@@ -16,6 +16,9 @@ public class GoodsSearchWords implements Serializable {
     @ApiModelProperty("高频词id")
     private Long wordsId;
 
+    @ApiModelProperty("网站")
+    private String webSite;
+
     @ApiModelProperty("高频词内容")
     private String wordsContent;
 

+ 1 - 1
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/member/pojo/Member.java

@@ -124,7 +124,7 @@ public class Member implements Serializable {
     @ApiModelProperty("更新时间")
     private Date updateTime;
 
-    @ApiModelProperty("会员邮箱是否激活:0未激活,1已激活")
+    @ApiModelProperty("会员邮箱/手机是否激活:0未激活,1已激活")
     private Integer isEmailActive;
 
     @ApiModelProperty("gp系统用户uid")

+ 5 - 2
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/OwnStoreAddDTO.java

@@ -16,8 +16,8 @@ public class OwnStoreAddDTO implements Serializable {
     @ApiModelProperty(value = "店铺名称",required = true)
     private String storeName;
 
-    @ApiModelProperty(value = "国内店铺名称",required = true)
-    private String storeNameCn;
+    @ApiModelProperty(value = "站点",required = true)
+    private String webSite;
 
     @ApiModelProperty(value = "店铺联系人",required = true)
     private String contactName;
@@ -52,4 +52,7 @@ public class OwnStoreAddDTO implements Serializable {
     @ApiModelProperty(value = "结算日期字符串,以逗号隔开")
     private String billDays;
 
+    @ApiModelProperty("店铺经营状态 1 资质审核 2装修筹备 3经营中4 暂停经营")
+    private Integer businessState;
+
 }

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/OwnStoreUpdateDTO.java

@@ -42,4 +42,7 @@ public class OwnStoreUpdateDTO implements Serializable {
 
     @ApiModelProperty(value = "结算日期字符串,以逗号隔开")
     private String billDays;
+
+    @ApiModelProperty("店铺经营状态 1 资质审核 2装修筹备 3经营中4 暂停经营")
+    private Integer businessState;
 }

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/dto/StoreBusinessVO.java

@@ -19,4 +19,7 @@ public class StoreBusinessVO {
 
     @ApiModelProperty("店铺等级名称")
     private String storeGradeName;
+
+    @ApiModelProperty("店铺经营状态")
+    private Integer businessState;
 }

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreCompanyShowListExample.java

@@ -315,6 +315,11 @@ public class StoreCompanyShowListExample {
             return (Criteria) this;
         }
 
+        public Criteria andWebSiteEqualTo(String value) {
+            addCriterion("web_site =", value, "webSite");
+            return (Criteria) this;
+        }
+
         public Criteria andNameIsNull() {
             addCriterion("name is null");
             return (Criteria) this;

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreExample.java

@@ -147,6 +147,11 @@ public class StoreExample implements Serializable {
     private Integer stateNotEquals;
 
     /**
+     * 店铺经营状态
+     */
+    private Integer businessState;
+
+    /**
      * 自营店铺1-自营店铺,2-入驻店铺
      */
     private Integer isOwnStore;

+ 11 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/example/StoreSiteInfoExample.java

@@ -4,6 +4,7 @@ import com.slodon.b2b2c.core.response.PagerInfo;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 @Data
 public class StoreSiteInfoExample implements Serializable {
@@ -21,6 +22,16 @@ public class StoreSiteInfoExample implements Serializable {
     private Long storeId;
 
     /**
+     *
+     */
+    private List<Long> storeIdIn;
+
+    /**
+     * 店铺经营状态
+     */
+    private Integer businessState;
+
+    /**
      * 站点
      */
     private String webSite;

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/pojo/Store.java

@@ -72,6 +72,9 @@ public class Store implements Serializable {
     @ApiModelProperty("店铺状态 1、开启;2、关闭")
     private Integer state;
 
+    @ApiModelProperty("店铺经营状态 1 资质审核 2装修筹备 3经营中4 暂停经营")
+    private Integer businessState;
+
     @ApiModelProperty("自营店铺1-自营店铺,2-入驻店铺")
     private Integer isOwnStore;
 

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/pojo/StoreSiteInfo.java

@@ -18,6 +18,9 @@ public class StoreSiteInfo implements Serializable {
     @ApiModelProperty("店铺id")
     private Long storeId;
 
+    @ApiModelProperty("经营状态")
+    private Integer businessState;
+
     @ApiModelProperty("站点")
     private String webSite;
 

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/dto/EnquiryAddDTO.java

@@ -14,6 +14,9 @@ public class EnquiryAddDTO implements Serializable {
 
     private static final long serialVersionUID = 3737927129030215710L;
 
+    @ApiModelProperty(value = "站点")
+    private String webSite;
+
     @ApiModelProperty(value = "用户名")
     private String name;
 

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/NavigationExample.java

@@ -24,6 +24,11 @@ public class NavigationExample implements Serializable {
     private Integer navId;
 
     /**
+     * 站点
+     */
+    private String webSite;
+
+    /**
      * 导航名称
      */
     private String navName;

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/PcFirstAdvExample.java

@@ -24,6 +24,11 @@ public class PcFirstAdvExample implements Serializable {
     private Integer advId;
 
     /**
+     * 站点
+     */
+    private String webSite;
+
+    /**
      * 弹层广告数据
      */
     private String data;

+ 5 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/example/SearchLogExample.java

@@ -25,6 +25,11 @@ public class SearchLogExample implements Serializable {
     private Integer logId;
 
     /**
+     * 站点
+     */
+    private String webSite;
+
+    /**
      * 搜索词
      */
     private String keyword;

+ 10 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/Enquiry.java

@@ -12,6 +12,8 @@ public class Enquiry {
      */
     private Long id;
 
+    private String webSite;
+
     /**
      *
      * This field was generated by MyBatis Generator.
@@ -639,4 +641,12 @@ public class Enquiry {
     public void setQuantity(Integer quantity) {
         this.quantity = quantity;
     }
+
+    public String getWebSite() {
+        return webSite;
+    }
+
+    public void setWebSite(String webSite) {
+        this.webSite = webSite;
+    }
 }

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/Navigation.java

@@ -14,6 +14,9 @@ public class Navigation implements Serializable {
     @ApiModelProperty("导航id")
     private Integer navId;
 
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty("导航名称")
     private String navName;
 

+ 7 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/PcFirstAdv.java

@@ -11,6 +11,13 @@ import java.io.Serializable;
 @Data
 public class PcFirstAdv implements Serializable {
     private static final long serialVersionUID = -8097888524748390485L;
+
+    @ApiModelProperty("id")
+    private Integer id;
+
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty("广告id")
     private Integer advId;
 

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/SearchLog.java

@@ -24,6 +24,9 @@ public class SearchLog implements Serializable {
     @ApiModelProperty("用户不登录存0")
     private Integer memberId;
 
+    @ApiModelProperty("站点")
+    private String webSite;
+
     @ApiModelProperty("创建时间")
     private Date createTime;
 }

+ 1 - 1
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/system/pojo/TplPcMallData.java

@@ -15,7 +15,7 @@ public class TplPcMallData implements Serializable {
     @ApiModelProperty("装修模板数据id")
     private Integer dataId;
 
-    @ApiModelProperty("装修模板数据站点")
+    @ApiModelProperty("装修模板数据站点")
     private String  webSite;
 
     @ApiModelProperty("装修模板id")

+ 3 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/admin/AdminFriendLinkController.java

@@ -39,14 +39,16 @@ public class AdminFriendLinkController {
 
     @ApiOperation("合作伙伴列表")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点", paramType = "query"),
             @ApiImplicitParam(name = "linkName", value = "合作伙伴名称", paramType = "query"),
             @ApiImplicitParam(name = "pageSize", value = "分页大小", defaultValue = "20", paramType = "query"),
             @ApiImplicitParam(name = "current", value = "当前页面位置", defaultValue = "1", paramType = "query")
     })
     @GetMapping("list")
-    public JsonResult<PageVO<FriendLinkVO>> getList(HttpServletRequest request, @RequestParam(value = "linkName", required = false) String linkName) {
+    public JsonResult<PageVO<FriendLinkVO>> getList(HttpServletRequest request, @RequestParam(value = "webSite", required = false) String webSite, @RequestParam(value = "linkName", required = false) String linkName) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         FriendLinkExample example = new FriendLinkExample();
+        example.setWebSite(webSite);
         example.setLinkNameLike(linkName);
         List<FriendLink> list = friendLinkModel.getFriendLinkList(example, pager);
         ArrayList<FriendLinkVO> vos = new ArrayList<>();

+ 2 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/front/FrontArticleController.java

@@ -9,6 +9,7 @@ import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.PagerInfo;
 import com.slodon.b2b2c.core.response.SldResponse;
 import com.slodon.b2b2c.core.util.StringUtil;
+import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.model.cms.ArticleCategoryModel;
 import com.slodon.b2b2c.model.cms.ArticleModel;
 import com.slodon.b2b2c.vo.cms.ArticleVO;
@@ -50,6 +51,7 @@ public class FrontArticleController {
             articlePager = new PagerInfo(articleSize, 1);
         }
         ArticleCategoryExample example = new ArticleCategoryExample();
+        example.setWebSite(WebUtil.getWebSite(request));
         example.setIsShow(ArticleConst.STATE_YES);
         example.setOrderBy("sort asc, create_time desc");
         List<ArticleCategory> list = articleCategoryModel.getArticleCategoryList(example, pager);

+ 2 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/cms/front/FrontFriendLinkController.java

@@ -5,6 +5,7 @@ import com.slodon.b2b2c.cms.pojo.FriendLink;
 import com.slodon.b2b2c.core.constant.FriendLinkConst;
 import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.SldResponse;
+import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.model.cms.FriendLinkModel;
 import com.slodon.b2b2c.vo.cms.FriendLinkVO;
 import io.swagger.annotations.Api;
@@ -31,6 +32,7 @@ public class FrontFriendLinkController {
     @GetMapping("list")
     public JsonResult<List<FriendLinkVO>> getList(HttpServletRequest request) {
         FriendLinkExample example = new FriendLinkExample();
+        example.setWebSite(WebUtil.getWebSite(request));
         example.setState(FriendLinkConst.STATE_YES);
         example.setOrderBy("sort asc, create_time desc");
         List<FriendLink> friendLinkList = friendLinkModel.getFriendLinkList(example, null);

+ 17 - 15
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/FrontGoodsCategoryController.java

@@ -70,9 +70,9 @@ public class FrontGoodsCategoryController extends BaseController {
     @GetMapping("topCategory")
     public JsonResult<List<FrontGoodsCategoryVO>> topCategory(HttpServletRequest request) {
         List<FrontGoodsCategoryVO> vos = new ArrayList<>();
-
+        String webSite = WebUtil.getWebSite(request);
         //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {
@@ -96,9 +96,9 @@ public class FrontGoodsCategoryController extends BaseController {
     @GetMapping("bottomCategory")
     public JsonResult<List<FrontGoodsCategoryVO>> bottomCategory(HttpServletRequest request, Integer categoryId1) {
         List<FrontGoodsCategoryVO> vos = new ArrayList<>();
-
+        String webSite = WebUtil.getWebSite(request);
         //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {
@@ -150,9 +150,9 @@ public class FrontGoodsCategoryController extends BaseController {
                                                             @RequestParam(value = "grade", defaultValue = "1") Integer grade) {
         List<FrontGoodsCategoryVO> vos = new ArrayList<>();
 
-
+        String webSite = WebUtil.getWebSite(request);
                 //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {
@@ -166,7 +166,7 @@ public class FrontGoodsCategoryController extends BaseController {
                     vo.setGrade(jsonObject.getInteger("grade"));
 
                     SysSeoVO  sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                            Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                            Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY,webSite);
                     vo.setSeoInfo(sysSeoVO);
                     if (categoryId1.equals(categoryId)) {
                         JSONArray array = JSONArray.parseArray(jsonObject.getString("children"));
@@ -181,7 +181,7 @@ public class FrontGoodsCategoryController extends BaseController {
                                 categoryVO.setGrade(jsonObject1.getInteger("grade"));
                                 categoryVO.setChildren(null);
                                 sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                                        Integer.valueOf(categoryVO.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                                        Integer.valueOf(categoryVO.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY, webSite);
                                 categoryVO.setSeoInfo(sysSeoVO);
                                 children.add(categoryVO);
                             }
@@ -202,7 +202,7 @@ public class FrontGoodsCategoryController extends BaseController {
                                 vo.setPid(object.getInteger("pid"));
                                 vo.setGrade(object.getInteger("grade"));
                                 SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                                        Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                                        Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY,webSite);
                                 vo.setSeoInfo(sysSeoVO);
                                 JSONArray array3 = JSONArray.parseArray(object.getString("children"));
                                 if (!CollectionUtils.isEmpty(array3)) {
@@ -216,7 +216,7 @@ public class FrontGoodsCategoryController extends BaseController {
                                         categoryVO.setGrade(jsonObject1.getInteger("grade"));
                                         categoryVO.setChildren(null);
                                         sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                                                Integer.valueOf(categoryVO.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                                                Integer.valueOf(categoryVO.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY,webSite);
                                         categoryVO.setSeoInfo(sysSeoVO);
                                         children.add(categoryVO);
                                     }
@@ -244,7 +244,7 @@ public class FrontGoodsCategoryController extends BaseController {
                                         vo.setGrade(jsonObject1.getInteger("grade"));
                                         vo.setChildren(null);
                                         SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                                                Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                                                Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY,webSite);
                                         vo.setSeoInfo(sysSeoVO);
                                         vos.add(vo);
                                     }
@@ -269,11 +269,11 @@ public class FrontGoodsCategoryController extends BaseController {
     public JsonResult<GoodsCategoryTreeVO> list(HttpServletRequest request, Integer categoryId1) {
         Member member = UserUtil.getUser(request, Member.class);
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
-
+        String webSite = WebUtil.getWebSite(request);
         List<GoodsCategoryTreeVO.CategoryInfoVO> categoryList = new ArrayList<>();
         List<GoodsListVO> goodsList = new ArrayList<>();
         //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {
@@ -295,6 +295,7 @@ public class FrontGoodsCategoryController extends BaseController {
                             //查询当前一级分类下的商品列表
                             SearchConditionDTO qc = new SearchConditionDTO();
                             qc.setCategoryIds(categoryId1.toString());
+                            qc.setWebSite(webSite);
                             goodsList = esGoodsModel.searchGoodsByES(qc, pager, member);
                         }
                     }
@@ -407,9 +408,10 @@ public class FrontGoodsCategoryController extends BaseController {
      */
     @GetMapping("getSecondCategory")
     public JsonResult<List<FrontGoodsCategoryVO>> getSecondCategory(HttpServletRequest request) {
+        String webSite = WebUtil.getWebSite(request);
         List<FrontGoodsCategoryVO> vos = new ArrayList<>();
         //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {
@@ -426,7 +428,7 @@ public class FrontGoodsCategoryController extends BaseController {
                             vo.setGrade(object.getInteger("grade"));
                             vo.setHomeShow(object.getInteger("homeShow"));
                             SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(
-                                    Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY);
+                                    Integer.valueOf(vo.getCategoryId()).longValue(), SeoTypeConstant.SEO_TYPE_GOODS_CATEGORY,webSite);
                             vo.setSeoInfo(sysSeoVO);
                             vos.add(vo);
                         }

+ 20 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/GoodsListController.java

@@ -79,6 +79,8 @@ public class GoodsListController extends BaseController {
     public JsonResult<PageVO<GoodsListVO>> goodsList(HttpServletRequest request, SearchConditionDTO qc) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         Member member = UserUtil.getUser(request, Member.class);
+        String webSite = WebUtil.getWebSite(request);
+        qc.setWebSite(webSite);
         if (!StringUtils.isEmpty(qc.getKeyword())) {
             String keyword = qc.getKeyword();
             //搜索词不为空,记录搜索日志
@@ -91,6 +93,7 @@ public class GoodsListController extends BaseController {
                 searchLog.setKeyword(keyword);
                 searchLog.setIp(WebUtil.getRealIp(request));
                 searchLog.setMemberId(memberId);
+                searchLog.setWebSite(webSite);
                 searchLog.setCreateTime(new Date());
                 searchLogModel.saveSearchLog(searchLog);
             }
@@ -98,7 +101,7 @@ public class GoodsListController extends BaseController {
         List<GoodsListVO> vos = esGoodsModel.searchGoodsByES(qc, pager, member);
         if (!StringUtils.isEmpty(qc.getKeyword())) {
             //关键字搜索,记录热搜词,异步执行,不影响商品列表
-            goodsSearchWordsModel.recordSearchWords(qc.getKeyword(), pager.getRowsCount());
+            goodsSearchWordsModel.recordSearchWords(qc.getKeyword(),qc.getWebSite(), pager.getRowsCount());
         }
         return SldResponse.success(new PageVO<>(vos, pager));
     }
@@ -111,6 +114,7 @@ public class GoodsListController extends BaseController {
     })
     @GetMapping("recommendList")
     public JsonResult<PageVO<GoodsRecommendVO>> recommendList(HttpServletRequest request, String queryType, Long productId, Integer categoryId3) {
+        String webSite = WebUtil.getWebSite(request);
         Member member = UserUtil.getUser(request, Member.class);
         List<GoodsRecommendVO> vos = new ArrayList<>();
         if ("cart".equals(queryType)) {
@@ -137,6 +141,7 @@ public class GoodsListController extends BaseController {
             }
             qc.setSort(1);
             qc.setStore(1);
+            qc.setWebSite(webSite);
             List<GoodsListVO> goodsList = esGoodsModel.searchGoodsByES(qc, pager, member);
             if (!CollectionUtils.isEmpty(goodsList)) {
                 goodsList.forEach(goodsListVO -> {
@@ -163,6 +168,7 @@ public class GoodsListController extends BaseController {
                 SearchConditionDTO conditionDTO = new SearchConditionDTO();
                 conditionDTO.setSort(1);
                 conditionDTO.setStore(1);
+                conditionDTO.setWebSite(webSite);
                 List<GoodsListVO> list = esGoodsModel.searchGoodsByES(conditionDTO, pager1, member);
                 if (!CollectionUtils.isEmpty(list)) {
                     list.forEach(goods1 -> {
@@ -238,7 +244,7 @@ public class GoodsListController extends BaseController {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
 
         //根据品牌首字母分组查询
-        List<GoodsBrandFrontVO> vos = goodsBrandModel.getGoodsBrandListBy(pager);
+        List<GoodsBrandFrontVO> vos = goodsBrandModel.getGoodsBrandListBy(pager,WebUtil.getWebSite(request));
         return SldResponse.success(new PageVO<>(vos, pager));
     }
 
@@ -252,6 +258,8 @@ public class GoodsListController extends BaseController {
     public JsonResult<PageVO<StoreNewGoodsVO>> newGoods(HttpServletRequest request, @RequestParam("storeId") Long storeId) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
 
+        String webSite = WebUtil.getWebSite(request);
+
         SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
         //获取30天之前的时间
         Calendar calendar = Calendar.getInstance();
@@ -263,6 +271,7 @@ public class GoodsListController extends BaseController {
         String timeFields = "LEFT(online_time,10) onTime";
         GoodsExample goodsExample = new GoodsExample();
         goodsExample.setStoreId(storeId);
+        goodsExample.setWebSite(webSite);
         goodsExample.setState(GoodsConst.GOODS_STATE_UPPER);
         goodsExample.setOnlineTimeLikeAfter(dayDate);
         goodsExample.setGroupBy("onTime");
@@ -276,6 +285,7 @@ public class GoodsListController extends BaseController {
             GoodsExample goodsExampleByOnlineTime = new GoodsExample();
             goodsExampleByOnlineTime.setOnlineTimeLike(goodsTime);
             goodsExampleByOnlineTime.setStoreId(storeId);
+            goodsExampleByOnlineTime.setWebSite(webSite);
             goodsExampleByOnlineTime.setState(GoodsConst.GOODS_STATE_UPPER);
             List<Goods> goodsList = goodsModel.getGoodsList(goodsExampleByOnlineTime, null);
             List<GoodsVO> vos = new ArrayList();
@@ -303,6 +313,7 @@ public class GoodsListController extends BaseController {
     public JsonResult<PageVO<GoodsListVO>> goCollectOrder(HttpServletRequest request, Integer promotionId) {
         GoodsPromotion goodsPromotion = goodsPromotionModel.getGoodsPromotionByPromotionId(promotionId);
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
+        String webSite = WebUtil.getWebSite(request);
         SearchConditionDTO qc = new SearchConditionDTO();
         //待修改
         if (goodsPromotion.getPromotionGrade() == PromotionConst.PROMOTION_GRADE_1 && !StringUtil.isNullOrZero(goodsPromotion.getGoodsId())) {
@@ -313,6 +324,7 @@ public class GoodsListController extends BaseController {
             qc.setCategoryIds(goodsPromotion.getGoodsCategoryId3().toString());
         }
         qc.setSort(1);
+        qc.setWebSite(webSite);
         List<GoodsListVO> vos = esGoodsModel.searchGoodsByES(qc, pager, null);
         return SldResponse.success(new PageVO<>(vos, pager));
     }
@@ -326,8 +338,10 @@ public class GoodsListController extends BaseController {
     @GetMapping("storeGoods")
     public JsonResult<PageVO<RecommendGoodsVO>> sellerGoods(HttpServletRequest request, Long storeId) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
+        String webSite = WebUtil.getWebSite(request);
         GoodsExample example = new GoodsExample();
         example.setStoreId(storeId);
+        example.setWebSite(webSite);
         example.setStoreIsRecommend(GoodsConst.IS_RECOMMEND_YES);
         example.setState(GoodsConst.GOODS_STATE_UPPER);
         example.setStoreState(GoodsConst.STORE_STATE_1);
@@ -353,8 +367,10 @@ public class GoodsListController extends BaseController {
         AssertUtil.notNullOrZero(storeId, "请选择店铺id");
 
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
+        String webSite = WebUtil.getWebSite(request);
         GoodsExample example = new GoodsExample();
         example.setStoreId(storeId);
+        example.setWebSite(webSite);
         example.setGoodsNameLike(keyword);
         example.setState(GoodsConst.GOODS_STATE_UPPER);
         List<Goods> list = goodsModel.getGoodsList(example, pager);
@@ -374,8 +390,10 @@ public class GoodsListController extends BaseController {
      */
     @GetMapping("new/list")
     public JsonResult<PageVO<GoodsVO>> getNewGoodsList(HttpServletRequest request) {
+        String webSite = WebUtil.getWebSite(request);
         GoodsExample example = new GoodsExample();
         //默认显示在售商品
+        example.setWebSite(webSite);
         example.setState(GoodsConst.GOODS_STATE_UPPER);
         example.setIsDelete(GoodsConst.GOODS_IS_DELETE_NO);
         example.setOrderBy("online_time DESC");

+ 3 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/front/GoodsSearchWordsController.java

@@ -5,6 +5,7 @@ import com.slodon.b2b2c.core.controller.BaseController;
 import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.PagerInfo;
 import com.slodon.b2b2c.core.response.SldResponse;
+import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.goods.example.GoodsSearchWordsExample;
 import com.slodon.b2b2c.goods.pojo.GoodsSearchWords;
 import com.slodon.b2b2c.model.goods.GoodsSearchWordsModel;
@@ -39,9 +40,10 @@ public class GoodsSearchWordsController extends BaseController {
     public JsonResult<List<GoodsSearchWords>> list(HttpServletRequest request,
                                                    @RequestParam(value = "keyWord") String keyWord,
                                                    @RequestParam(value = "size",required = false,defaultValue = "10") Integer size) {
-
+        String webSite = WebUtil.getWebSite(request);
         PagerInfo pager = new PagerInfo(size,1);
         GoodsSearchWordsExample example = new GoodsSearchWordsExample();
+        example.setWebSite(webSite);
         example.setWordsContentOrPyLike(keyWord);
         example.setSearchGoodsNumGte(1);
         example.setOrderBy("search_frequency desc,search_goods_num desc,create_time desc");

+ 1 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/seller/GoodsCategorySellerController.java

@@ -203,8 +203,7 @@ public class GoodsCategorySellerController {
         Vendor vendor = UserUtil.getUser(request, Vendor.class);
         //店铺申请经营类目和商户入驻选择经营类目用到此接口
         GoodsCategoryExample example = new GoodsCategoryExample();
-        //TODO: 2025/07/31 临时处理,待完善
-//      example.setWebSite(webSite);
+        example.setWebSite(webSite);
         example.setState(GoodsCategoryConst.CATEGORY_STATE_1);
         example.setGrade(GoodsCategoryConst.CATEGORY_GRADE_3);
         List<GoodsCategory> list = goodsCategoryModel.getGoodsCategoryList(example, null);

+ 37 - 7
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/admin/AdminEnquiryController.java

@@ -1,6 +1,7 @@
 package com.slodon.b2b2c.controller.member.admin;
 
 import com.slodon.b2b2c.core.constant.AdminConst;
+import com.slodon.b2b2c.core.constant.VendorConst;
 import com.slodon.b2b2c.core.controller.BaseController;
 import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.PageVO;
@@ -20,17 +21,22 @@ import com.slodon.b2b2c.model.seller.StoreModel;
 import com.slodon.b2b2c.model.seller.StoreNameModel;
 import com.slodon.b2b2c.model.seller.VendorModel;
 import com.slodon.b2b2c.model.system.AdminModel;
+import com.slodon.b2b2c.model.system.SystemResourceModel;
 import com.slodon.b2b2c.seller.example.StoreExample;
 import com.slodon.b2b2c.seller.example.StoreNameExample;
+import com.slodon.b2b2c.seller.example.VendorExample;
 import com.slodon.b2b2c.seller.pojo.Store;
 import com.slodon.b2b2c.seller.pojo.StoreName;
 import com.slodon.b2b2c.seller.pojo.Vendor;
 import com.slodon.b2b2c.system.example.AdminExample;
+import com.slodon.b2b2c.system.example.SystemResourceExample;
 import com.slodon.b2b2c.system.pojo.Admin;
+import com.slodon.b2b2c.system.pojo.SystemResource;
 import com.slodon.b2b2c.vo.business.OrderEnquiryTrackVO;
 import com.slodon.b2b2c.vo.member.EnquiryVendorVO;
 import com.slodon.b2b2c.vo.member.OrderEnquiryVO;
 import com.slodon.b2b2c.vo.seller.StoreVO;
+import com.slodon.b2b2c.vo.system.SystemRoleVO;
 import io.swagger.annotations.Api;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.redis.core.StringRedisTemplate;
@@ -75,6 +81,9 @@ public class AdminEnquiryController extends BaseController {
     @Resource
     private StoreNameModel storeNameModel;
 
+    @Resource
+    private SystemResourceModel systemResourceModel;
+
     /**
      * 询盘管理列表
      *
@@ -115,14 +124,35 @@ public class AdminEnquiryController extends BaseController {
      * @return
      */
     @GetMapping("sub/list")
-    public JsonResult<PageVO<EnquiryVendorVO>> getSubAdminList(HttpServletRequest request) {
-        AdminExample adminExample = new AdminExample();
-        adminExample.setState(AdminConst.ADMIN_STATE_NORM);
-        List<Admin> adminList = adminModel.getAdminList(adminExample, null);
+    public JsonResult<PageVO<EnquiryVendorVO>> getSubAdminList(HttpServletRequest request, Long storeId) {
         ArrayList<EnquiryVendorVO> vos = new ArrayList<>();
-        adminList.forEach(admin -> {
-            vos.add(new EnquiryVendorVO(admin));
-        });
+        if (storeId != null && storeId == 0) {
+            AdminExample adminExample = new AdminExample();
+            adminExample.setState(AdminConst.ADMIN_STATE_NORM);
+            List<Admin> adminList = adminModel.getAdminList(adminExample, null);
+            adminList.forEach(admin -> {
+                //查询角色资源对应表,获取该角色拥有的资源列表
+                SystemResourceExample resourceExample = new SystemResourceExample();
+                resourceExample.setRoleId(admin.getRoleId());
+                resourceExample.setGrade(AdminConst.RESOURCE_GRADE_3);
+                resourceExample.setContent("询盘管理");
+                resourceExample.setOrderBy("resource_id asc");
+                List<SystemResource> resourceRoleList = systemResourceModel.getSystemResourceList(resourceExample, null);
+                if (!CollectionUtils.isEmpty(resourceRoleList)) {
+                    vos.add(new EnquiryVendorVO(admin));
+                }
+            });
+        } else {
+            VendorExample vendorExample = new VendorExample();
+            vendorExample.setStoreId(storeId);
+            vendorExample.setIsStoreAdmin(VendorConst.IS_STORE_ADMIN_1);
+            vendorExample.setIsAllowLogin(VendorConst.IS_ALLOW_LOGIN);
+            List<Vendor> vendorList = vendorModel.getVendorList(vendorExample, null);
+            vendorList.forEach(vendor -> {
+                EnquiryVendorVO vo = new EnquiryVendorVO(vendor);
+                vos.add(vo);
+            });
+        }
         return SldResponse.success(new PageVO<>(vos, null));
     }
 

+ 4 - 4
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/MemberPasswordController.java

@@ -5,10 +5,7 @@ import com.slodon.b2b2c.core.controller.BaseController;
 import com.slodon.b2b2c.core.i18n.Language;
 import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.SldResponse;
-import com.slodon.b2b2c.core.util.AssertUtil;
-import com.slodon.b2b2c.core.util.Md5;
-import com.slodon.b2b2c.core.util.StringUtil;
-import com.slodon.b2b2c.core.util.UserUtil;
+import com.slodon.b2b2c.core.util.*;
 import com.slodon.b2b2c.member.dto.MemberAddLoginPwdDTO;
 import com.slodon.b2b2c.member.dto.MemberAddPayPwdDTO;
 import com.slodon.b2b2c.member.dto.MemberUpdateLoginPwdDTO;
@@ -92,6 +89,7 @@ public class MemberPasswordController extends BaseController {
 
         // 查询该手机号是否被其它账号绑定(若有解除绑定)
         MemberExample example = new MemberExample();
+        example.setWebSite(member1.getWebSite());
         example.setMemberMobile(memberMobile);
         example.setMemberIdNotEquals(member.getMemberId());
         List<Member> memberList = memberModel.getMemberList(example, null);
@@ -167,6 +165,7 @@ public class MemberPasswordController extends BaseController {
 
         //查询邮箱是否被绑定
         MemberExample example = new MemberExample();
+        example.setWebSite(member1.getWebSite());
         example.setMemberIdNotEquals(member.getMemberId());
         example.setMemberEmail(memberEmail);
         List<Member> memberList = memberModel.getMemberList(example, null);
@@ -210,6 +209,7 @@ public class MemberPasswordController extends BaseController {
         AssertUtil.isTrue(!Md5.getMd5String(memberUpdateLoginPwdDTO.getOldLoginPwd()).equalsIgnoreCase(memberDb.getLoginPwd()), Language.translate("原密码不对,请重新输入",Language.EN_LANGUAGE_TYPE));
 
         memberModel.editLoginPwd(memberUpdateLoginPwdDTO, member.getMemberId());
+        stringRedisTemplate.delete(memberUpdateLoginPwdDTO.getMemberEmail());
         return SldResponse.success(Language.translate("修改登录密码成功",Language.EN_LANGUAGE_TYPE));
     }
 

+ 367 - 61
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEmailActiveController.java

@@ -12,6 +12,7 @@ import com.slodon.b2b2c.core.util.StringUtil;
 import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.dao.read.member.MemberReadMapper;
 import com.slodon.b2b2c.dao.write.member.MemberWriteMapper;
+import com.slodon.b2b2c.enums.WebSiteConstant;
 import com.slodon.b2b2c.member.example.MemberExample;
 import com.slodon.b2b2c.member.pojo.Member;
 import com.slodon.b2b2c.model.member.MemberModel;
@@ -31,10 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -69,11 +67,18 @@ public class MemberEmailActiveController extends BaseController {
 
     private static final Map<Integer, String> EMAIL_KEY_MAP = new HashMap<>();
 
+    private static final Map<Integer, String> MOBILE_KEY_MAP = new HashMap<>();
+
     static {
         EMAIL_KEY_MAP.put(1, RedisConst.SLD_PC_NEW_REGISTER_USER_EMAIL);
         EMAIL_KEY_MAP.put(2, RedisConst.SLD_PC_FORGET_PWD_USER_EMAIL);
     }
 
+    static {
+        MOBILE_KEY_MAP.put(1, RedisConst.SLD_PC_NEW_REGISTER_USER_MOBILE);
+        MOBILE_KEY_MAP.put(2, RedisConst.SLD_PC_FORGET_PWD_USER_MOBILE);
+    }
+
 //    /**
 //     * @param request
 //     * @param email
@@ -160,38 +165,87 @@ public class MemberEmailActiveController extends BaseController {
      * @param email
      * @param source
      * @param type
-     * @param webSite
+     * @param mobile
      * @return
      */
     @PostMapping("/verification/code")
-    public JsonResult<Object> getMemberEmailVerificationCode(HttpServletRequest request, String email, Integer source, Integer type, @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite) {
-        log.info("getMemberEmailVerificationCode - email:{},source:{},type:{},webSite:{}", email, source, type, webSite);
+    public JsonResult<Object> getMemberEmailVerificationCode(HttpServletRequest request, String email, Integer source, Integer type, String mobile) {
+        log.info("getMemberEmailVerificationCode - email:{},source:{},type:{},mobile:{}", email, source, type, mobile);
+        String webSite = WebUtil.getWebSite(request);
+
+        // 根据站点类型进行不同的处理
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            return handleVerificationCodeForOversea(webSite, email, mobile, source, type);
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            return handleVerificationCodeForDistributor(webSite, email, mobile, source, type);
+        }
+
+        return SldResponse.success(Language.translate("验证码发送成功", Language.EN_LANGUAGE_TYPE));
+    }
+
+    /**
+     * 处理海外站点验证码发送
+     */
+    private JsonResult<Object> handleVerificationCodeForOversea(String webSite, String email, String mobile, Integer source, Integer type) {
         if (StringUtil.isEmpty(email)) {
             return SldResponse.fail(Language.translate("邮件不能为空", Language.EN_LANGUAGE_TYPE));
         }
         AssertUtil.emailCheck(email);
 
+        return sendAndLimitVerificationCode(webSite, email, mobile, source, type,
+                RedisConst.SLD_PC_EMAIL_VERIFY_CODE_LIMIT + email + ":type::" + type);
+    }
+
+    /**
+     * 处理分销商站点验证码发送
+     */
+    private JsonResult<Object> handleVerificationCodeForDistributor(String webSite, String email, String mobile, Integer source, Integer type) {
+        if (StringUtil.isEmpty(mobile)) {
+            return SldResponse.fail(Language.translate("手机号码不能为空", Language.EN_LANGUAGE_TYPE));
+        }
+        AssertUtil.mobileCheck(mobile);
+
+        return sendAndLimitVerificationCode(webSite, email, mobile, source, type,
+                RedisConst.SLD_PC_MOBILE_VERIFY_CODE_LIMIT + mobile + ":type::" + type);
+    }
+
+    /**
+     * 发送验证码并设置频率限制
+     */
+    private JsonResult<Object> sendAndLimitVerificationCode(String webSite, String email, String mobile, Integer source,
+                                                            Integer type, String redisKey) {
         // 1. 判断是否在1分钟内已发送过验证码
-        String redisKey = RedisConst.SLD_PC_EMAIL_VERIFY_CODE_LIMIT + email + ":type::" + type + ":webSite::" + webSite;
         if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(redisKey))) {
             return SldResponse.fail(Language.translate("请勿频繁操作,请1分钟后重试", Language.EN_LANGUAGE_TYPE));
         }
 
         int count;
         if (type == 1) {
-            count = memberRegisterActiveModel.sendRegisterUserEmailVerificationCode(email, source, webSite);
+            count = memberRegisterActiveModel.sendRegisterUserVerificationCode(webSite, email, mobile, source);
             AssertUtil.isTrue((count == 0), Language.translate("验证码发送失败,请重试", Language.EN_LANGUAGE_TYPE));
-            AssertUtil.isTrue((count == 2), Language.translate("该邮箱已注册,请登录", Language.EN_LANGUAGE_TYPE));
+
+            if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+                AssertUtil.isTrue((count == 2), Language.translate("该邮箱已注册,请登录", Language.EN_LANGUAGE_TYPE));
+            } else {
+                AssertUtil.isTrue((count == 2), Language.translate("该手机号已注册,请登录", Language.EN_LANGUAGE_TYPE));
+            }
         } else {
-            count = memberRegisterActiveModel.checkMemberUserInfo(email, webSite);
+            count = memberRegisterActiveModel.checkMemberUserInfo(webSite, email, mobile);
             AssertUtil.isTrue((count == 0), Language.translate("验证码发送失败,请重试", Language.EN_LANGUAGE_TYPE));
-            AssertUtil.isTrue((count == 2), Language.translate("该邮箱未激活,请先激活", Language.EN_LANGUAGE_TYPE));
-            AssertUtil.isTrue((count == 3), Language.translate("该邮箱未注册,请先注册", Language.EN_LANGUAGE_TYPE));
+
+            if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+                AssertUtil.isTrue((count == 2), Language.translate("该邮箱未激活,请先激活", Language.EN_LANGUAGE_TYPE));
+                AssertUtil.isTrue((count == 3), Language.translate("该邮箱未注册,请先注册", Language.EN_LANGUAGE_TYPE));
+            } else {
+                AssertUtil.isTrue((count == 2), Language.translate("该手机号未激活,请先激活", Language.EN_LANGUAGE_TYPE));
+                AssertUtil.isTrue((count == 3), Language.translate("该手机号未注册,请先注册", Language.EN_LANGUAGE_TYPE));
+            }
         }
+
         // 2. 设置 Redis 标记,1分钟内不可重复发送
         stringRedisTemplate.opsForValue().set(redisKey, "1", 60, TimeUnit.SECONDS);
-        return SldResponse.success(Language.translate("验证码发送成功", Language.EN_LANGUAGE_TYPE));
 
+        return SldResponse.success(Language.translate("验证码发送成功", Language.EN_LANGUAGE_TYPE));
     }
 
 
@@ -202,26 +256,62 @@ public class MemberEmailActiveController extends BaseController {
      * @param email
      * @param type
      * @param verificationCode
-     * @param webSite
+     * @param mobile
      * @return
      */
     @PostMapping("/check/verification/code")
-    public JsonResult<Object> checkMemberEmailVerificationCode(HttpServletRequest request, String email, Integer type, String verificationCode, @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite) {
-        log.info("checkMemberEmailVerificationCode - email:{},type:{},verificationCode:{},webSite:{}", email, type, verificationCode, webSite);
-        if (StringUtil.isEmpty(email)) {
-            return SldResponse.fail(Language.translate("邮件不能为空", Language.EN_LANGUAGE_TYPE));
+    public JsonResult<Object> checkMemberEmailVerificationCode(HttpServletRequest request, String email, Integer type, String verificationCode, String mobile) {
+        log.info("checkMemberEmailVerificationCode - email:{},type:{},verificationCode:{},mobile:{}", email, type, verificationCode, mobile);
+        String webSite = WebUtil.getWebSite(request);
+
+        // 参数校验
+        ValidationResult validation = validateVerificationParams(webSite, email, mobile, verificationCode);
+        if (!validation.isValid()) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL, validation.getErrorMessage());
         }
-        if (StringUtil.isEmpty(verificationCode)) {
-            return SldResponse.fail(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));
+
+        // 根据站点类型进行验证码校验
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            return verifyCodeByEmail(email, type, verificationCode);
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            return verifyCodeByMobile(mobile, type, verificationCode);
         }
-        AssertUtil.emailCheck(email);
 
+        return SldResponse.success(Language.translate("验证码校验成功", Language.EN_LANGUAGE_TYPE));
+    }
+
+
+    /**
+     * 通过邮箱验证验证码
+     */
+    private JsonResult<Object> verifyCodeByEmail(String email, Integer type, String verificationCode) {
         String baseKey = EMAIL_KEY_MAP.get(type);
         if (baseKey == null) {
             return SldResponse.fail(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));
         }
 
-        String redisKey = baseKey + email + ":webSite::" + webSite;
+        String redisKey = baseKey + email;
+        return verifyCodeFromRedis(redisKey, verificationCode);
+    }
+
+    /**
+     * 通过手机号验证验证码
+     */
+    private JsonResult<Object> verifyCodeByMobile(String mobile, Integer type, String verificationCode) {
+        String baseKey = MOBILE_KEY_MAP.get(type);
+        if (baseKey == null) {
+            return SldResponse.fail(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));
+        }
+
+        String redisKey = baseKey + mobile;
+        return verifyCodeFromRedis(redisKey, verificationCode);
+    }
+
+
+    /**
+     * 从Redis中验证验证码
+     */
+    private JsonResult<Object> verifyCodeFromRedis(String redisKey, String verificationCode) {
         if (!stringRedisTemplate.hasKey(redisKey)) {
             return SldResponse.fail(Language.translate("验证码已过期,请重新获取", Language.EN_LANGUAGE_TYPE));
         }
@@ -230,12 +320,37 @@ public class MemberEmailActiveController extends BaseController {
         if (!verificationCode.equals(storedCode)) {
             return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("验证码校验失败", Language.EN_LANGUAGE_TYPE));
         }
-//        stringRedisTemplate.delete(redisKey);
+
         return SldResponse.success(Language.translate("验证码校验成功", Language.EN_LANGUAGE_TYPE));
     }
 
 
     /**
+     * 验证参数
+     */
+    private ValidationResult validateVerificationParams(String webSite, String email, String mobile, String verificationCode) {
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            if (StringUtil.isEmpty(email)) {
+                return ValidationResult.invalid(Language.translate("邮件不能为空", Language.EN_LANGUAGE_TYPE));
+            }
+            if (StringUtil.isEmpty(verificationCode)) {
+                return ValidationResult.invalid(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));
+            }
+            AssertUtil.emailCheck(email);
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            if (StringUtil.isEmpty(mobile)) {
+                return ValidationResult.invalid(Language.translate("手机不能为空", Language.EN_LANGUAGE_TYPE));
+            }
+            if (StringUtil.isEmpty(verificationCode)) {
+                return ValidationResult.invalid(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));
+            }
+            AssertUtil.mobileCheck(mobile);
+        }
+        return ValidationResult.valid();
+    }
+
+
+    /**
      * 注册
      *
      * @param request
@@ -243,51 +358,126 @@ public class MemberEmailActiveController extends BaseController {
      * @param nickName
      * @param password
      * @param confirmPassword
-     * @param webSite
+     * @param mobile
      * @return
      */
     @PostMapping("/register")
-    public JsonResult<Object> activeMemberEmailInfo(HttpServletRequest request, String email, String nickName, String password, String confirmPassword, @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite) {
-        log.info("activeMemberEmailInfo - email:{},nickName:{},password:{},confirmPassword:{},webSite:{}", email, nickName, password, confirmPassword, webSite);
-        if (StringUtil.isEmpty(email)) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("邮件不能为空", Language.EN_LANGUAGE_TYPE));
+    public JsonResult<Object> activeMemberEmailInfo(HttpServletRequest request, String email, String nickName, String password, String confirmPassword, String mobile) {
+        log.info("activeMemberEmailInfo - email:{},nickName:{},password:{},confirmPassword:{},mobile:{}", email, nickName, password, confirmPassword, mobile);
+        String webSite = WebUtil.getWebSite(request);
+        // 参数校验和密码一致性检查
+        ValidationResult validation = validateRegistrationParams(webSite, email, mobile, password, confirmPassword);
+        if (!validation.isValid()) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL, validation.getErrorMessage());
+        }
+
+        // 查找会员信息
+        Member memberInfo = findMemberInfo(webSite, email, mobile);
+        if (memberInfo == null) {
+            String errorMsg = WebSiteConstant.MEMBER_OVERSEA.equals(webSite)
+                    ? "会员邮箱不存在,请重新注册"
+                    : "会员手机号不存在,请重新注册";
+            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate(errorMsg, Language.EN_LANGUAGE_TYPE));
+        }
+
+        // 检查账户是否已激活
+        if (isMemberAlreadyActive(memberInfo)) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL,
+                    Language.translate("会员账号已激活,无需重复注册,请登录", Language.EN_LANGUAGE_TYPE));
+        }
+
+        // 更新用户信息
+        updateMemberInfo(request, memberInfo, nickName, password);
+
+        // 发送成功通知
+        return sendSuccessNotification(webSite, email, mobile, nickName);
+    }
+
+    /**
+     * 验证注册参数
+     */
+    private ValidationResult validateRegistrationParams(String webSite, String email, String mobile,
+                                                        String password, String confirmPassword) {
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            if (StringUtil.isEmpty(email)) {
+                return ValidationResult.invalid("邮件不能为空");
+            }
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            if (StringUtil.isEmpty(mobile)) {
+                return ValidationResult.invalid("手机不能为空");
+            }
+            AssertUtil.mobileCheck(mobile);
         }
+
         if (!password.equals(confirmPassword)) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("密码不一致,请重新输入", Language.EN_LANGUAGE_TYPE));
+            return ValidationResult.invalid("密码不一致,请重新输入");
         }
+
         AssertUtil.passwordCheck(password);
+        return ValidationResult.valid();
+    }
+
+    /**
+     * 查找会员信息
+     */
+    private Member findMemberInfo(String webSite, String email, String mobile) {
         MemberExample memberExample = new MemberExample();
-        memberExample.setMemberEmail(email.toLowerCase());
         memberExample.setWebSite(webSite);
-        List<Member> memberList = memberReadMapper.listByExample(memberExample);
-        if (CollectionUtils.isEmpty(memberList)) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("会员邮箱不存在,请重新注册", Language.EN_LANGUAGE_TYPE));
-        }
 
-        Member memberInfo = memberList.get(0);
-        if (memberInfo.getIsEmailActive() != null && memberInfo.getIsEmailActive() == 1) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("会员邮箱已激活,无需重复注册,请登录", Language.EN_LANGUAGE_TYPE));
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            memberExample.setMemberEmail(email.toLowerCase());
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            memberExample.setMemberMobile(mobile.toLowerCase());
         }
 
-        // 更新用户邮箱激活状态
+        List<Member> memberList = memberReadMapper.listByExample(memberExample);
+        return CollectionUtils.isEmpty(memberList) ? null : memberList.get(0);
+    }
+
+    /**
+     * 检查会员是否已激活
+     */
+    private boolean isMemberAlreadyActive(Member member) {
+        return member.getIsEmailActive() != null && member.getIsEmailActive() == 1;
+    }
+
+    /**
+     * 更新会员信息
+     */
+    private Member updateMemberInfo(HttpServletRequest request, Member memberInfo, String nickName, String password) {
         Member memberNew = new Member();
         memberNew.setMemberId(memberInfo.getMemberId());
         memberNew.setIsEmailActive(1);
         memberNew.setUpdateTime(new Date());
         memberNew.setMemberNickName(nickName);
         memberNew.setLoginPwd(Md5.getMd5String(password));
+
         String ip = WebUtil.getRealIp(request);
         CountryAreaApiDto countryAreaApiDto = memberEnquiryModel.getCountryAndAreaByIp(ip);
         memberNew.setCountry(countryAreaApiDto.getCountryIsoCode());
         memberNew.setCity(countryAreaApiDto.getCityIsoCode());
+
         memberModel.updateMember(memberNew);
+        return memberNew;
+    }
 
-        // 发送账户注册成功邮件
-        memberRegisterActiveModel.sendRegisterSuccessEmail(email, nickName);
-        return SldResponse.success(Language.translate("会员邮箱账户激活成功", Language.EN_LANGUAGE_TYPE));
+    /**
+     * 发送成功通知
+     */
+    private JsonResult<Object> sendSuccessNotification(String webSite, String email, String mobile, String nickName) {
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            // 发送账户注册成功邮件
+            memberRegisterActiveModel.sendRegisterSuccessEmail(email, nickName);
+            return SldResponse.success(Language.translate("会员邮箱账户激活成功", Language.EN_LANGUAGE_TYPE));
+        } else {
+            // 发送账户注册成功短信
+            memberRegisterActiveModel.sendRegisterSuccessSms(mobile);
+            return SldResponse.success(Language.translate("会员手机号激活成功", Language.EN_LANGUAGE_TYPE));
+        }
     }
 
 
+
     /**
      * 用户邮箱重置忘记密码
      *
@@ -296,39 +486,128 @@ public class MemberEmailActiveController extends BaseController {
      * @param verificationCode
      * @param loginPwd
      * @param confirmPassWord
-     * @param webSite
+     * @param mobile
      * @return
      */
     @PostMapping("/email/reset/pwdNew")
-    public JsonResult<Object> emailResetPwdNew(HttpServletRequest request, String email, String verificationCode, String loginPwd, String confirmPassWord, @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite) {
-        log.info("emailResetPwd - email:{},verificationCode:{},loginPwd:{},confirmPassWord:{},webSite:{}", email, verificationCode, loginPwd, confirmPassWord, webSite);
-        if (StringUtil.isEmpty(email)) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("邮件不能为空", Language.EN_LANGUAGE_TYPE));
+    public JsonResult<Object> emailResetPwdNew(HttpServletRequest request, String email, String verificationCode,
+                                               String loginPwd, String confirmPassWord, String mobile) {
+        log.info("emailResetPwd - email:{},verificationCode:{},loginPwd:{},confirmPassWord:{},mobile:{}",
+                email, verificationCode, loginPwd, confirmPassWord, mobile);
+
+        String webSite = WebUtil.getWebSite(request);
+
+        // 参数校验
+        ValidationResult validation = validateResetPasswordParams(webSite, email, mobile, loginPwd, confirmPassWord);
+        if (!validation.isValid()) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL, validation.getErrorMessage());
         }
-        MemberExample memberExample = new MemberExample();
-        memberExample.setMemberEmail(email.toLowerCase());
-        memberExample.setWebSite(webSite);
-        List<Member> memberList = memberReadMapper.listByExample(memberExample);
 
-        if (CollectionUtils.isEmpty(memberList)) {
+        // 密码强度校验
+        AssertUtil.passwordCheck(loginPwd);
+
+        // 根据站点类型处理密码重置
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            return resetPasswordByEmail(webSite, email, verificationCode, loginPwd);
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            return resetPasswordByMobile(webSite, mobile, verificationCode, loginPwd);
+        }
+
+        return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("不支持的站点类型", Language.EN_LANGUAGE_TYPE));
+    }
+
+    /**
+     * 验证重置密码参数
+     */
+    private ValidationResult validateResetPasswordParams(String webSite, String email, String mobile,
+                                                         String loginPwd, String confirmPassWord) {
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            if (StringUtil.isEmpty(email)) {
+                return ValidationResult.invalid("邮件不能为空");
+            }
+        } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            if (StringUtil.isEmpty(mobile)) {
+                return ValidationResult.invalid("手机不能为空");
+            }
+            AssertUtil.mobileCheck(mobile);
+        }
+
+        if (!loginPwd.equals(confirmPassWord)) {
+            return ValidationResult.invalid("密码不一致,请重新输入");
+        }
+
+        return ValidationResult.valid();
+    }
+
+    /**
+     * 通过邮箱重置密码
+     */
+    private JsonResult<Object> resetPasswordByEmail(String webSite, String email, String verificationCode, String loginPwd) {
+        // 查找会员信息
+        Member memberInfo = findMemberByEmail(webSite, email);
+        if (memberInfo == null) {
             return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("该邮箱不存在,请先注册", Language.EN_LANGUAGE_TYPE));
         }
 
-        Member memberInfo = memberList.get(0);
+        // 检查邮箱是否已激活
         if (memberInfo.getIsEmailActive() != null && memberInfo.getIsEmailActive() == 0) {
             return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("该邮箱未激活,请先激活", Language.EN_LANGUAGE_TYPE));
         }
 
-        if (!loginPwd.equals(confirmPassWord)) {
-            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("密码不一致,请重新输入", Language.EN_LANGUAGE_TYPE));
+        // 验证验证码并重置密码
+        String forgetPwdEmailKey = RedisConst.SLD_PC_FORGET_PWD_USER_EMAIL + email;
+        return verifyCodeAndResetPassword(forgetPwdEmailKey, verificationCode, memberInfo, loginPwd);
+    }
+
+    /**
+     * 通过手机号重置密码
+     */
+    private JsonResult<Object> resetPasswordByMobile(String webSite, String mobile, String verificationCode, String loginPwd) {
+        // 查找会员信息
+        Member memberInfo = findMemberByMobile(webSite, mobile);
+        if (memberInfo == null) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("该手机号不存在,请先注册", Language.EN_LANGUAGE_TYPE));
         }
 
-        AssertUtil.passwordCheck(loginPwd);
+        // 检查手机号是否已激活
+        if (memberInfo.getIsEmailActive() != null && memberInfo.getIsEmailActive() == 0) {
+            return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("该手机号未激活,请先激活", Language.EN_LANGUAGE_TYPE));
+        }
 
-        String forgetPwdEmailKey = RedisConst.SLD_PC_FORGET_PWD_USER_EMAIL + email + ":webSite::" + webSite;
-        log.info("forgetPwdEmailKey:{}", forgetPwdEmailKey);
-        if (stringRedisTemplate.hasKey(forgetPwdEmailKey)) {
-            String verifyNumber = stringRedisTemplate.opsForValue().get(forgetPwdEmailKey);
+        // 验证验证码并重置密码
+        String forgetPwdMobileKey = RedisConst.SLD_PC_FORGET_PWD_USER_MOBILE + mobile;
+        return verifyCodeAndResetPassword(forgetPwdMobileKey, verificationCode, memberInfo, loginPwd);
+    }
+
+    /**
+     * 根据邮箱查找会员
+     */
+    private Member findMemberByEmail(String webSite, String email) {
+        MemberExample memberExample = new MemberExample();
+        memberExample.setMemberEmail(email.toLowerCase());
+        memberExample.setWebSite(webSite);
+        List<Member> memberList = memberReadMapper.listByExample(memberExample);
+        return CollectionUtils.isEmpty(memberList) ? null : memberList.get(0);
+    }
+
+    /**
+     * 根据手机号查找会员
+     */
+    private Member findMemberByMobile(String webSite, String mobile) {
+        MemberExample memberExample = new MemberExample();
+        memberExample.setMemberMobile(mobile.toLowerCase());
+        memberExample.setWebSite(webSite);
+        List<Member> memberList = memberReadMapper.listByExample(memberExample);
+        return CollectionUtils.isEmpty(memberList) ? null : memberList.get(0);
+    }
+
+    /**
+     * 验证验证码并重置密码
+     */
+    private JsonResult<Object> verifyCodeAndResetPassword(String redisKey, String verificationCode, Member memberInfo, String loginPwd) {
+        log.info("forgetPwdKey:{}", redisKey);
+        if (stringRedisTemplate.hasKey(redisKey)) {
+            String verifyNumber = stringRedisTemplate.opsForValue().get(redisKey);
             log.info("verifyNumber:{}", verifyNumber);
             if (!verificationCode.equals(verifyNumber)) {
                 return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("验证码校验失败", Language.EN_LANGUAGE_TYPE));
@@ -341,7 +620,8 @@ public class MemberEmailActiveController extends BaseController {
             memberNew.setUpdateTime(new Date());
             memberModel.updateMember(memberNew);
 
-            stringRedisTemplate.delete(forgetPwdEmailKey);
+            // 删除Redis中的验证码
+            stringRedisTemplate.delete(redisKey);
 
             return SldResponse.success(Language.translate("重置登录密码成功", Language.EN_LANGUAGE_TYPE));
         }
@@ -496,4 +776,30 @@ public class MemberEmailActiveController extends BaseController {
         }
         return SldResponse.fail(ResponseConst.STATE_FAIL, Language.translate("重置密码链接已失效,请重新获取", Language.EN_LANGUAGE_TYPE));
     }
+
+    private static class ValidationResult {
+        private final boolean valid;
+        private final String errorMessage;
+
+        private ValidationResult(boolean valid, String errorMessage) {
+            this.valid = valid;
+            this.errorMessage = errorMessage;
+        }
+
+        static ValidationResult valid() {
+            return new ValidationResult(true, null);
+        }
+
+        static ValidationResult invalid(String errorMessage) {
+            return new ValidationResult(false, Language.translate(errorMessage, Language.EN_LANGUAGE_TYPE));
+        }
+
+        public boolean isValid() {
+            return valid;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+    }
 }

+ 20 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEnquiryController.java

@@ -2,6 +2,7 @@ package com.slodon.b2b2c.controller.member.front.advich;
 
 import com.alibaba.fastjson.JSON;
 import com.slodon.b2b2c.core.constant.EnquiryConst;
+import com.slodon.b2b2c.core.constant.MemberConst;
 import com.slodon.b2b2c.core.controller.BaseController;
 import com.slodon.b2b2c.core.i18n.Language;
 import com.slodon.b2b2c.core.response.JsonResult;
@@ -11,6 +12,7 @@ import com.slodon.b2b2c.core.response.SldResponse;
 import com.slodon.b2b2c.core.util.StringUtil;
 import com.slodon.b2b2c.core.util.UserUtil;
 import com.slodon.b2b2c.core.util.WebUtil;
+import com.slodon.b2b2c.enums.WebSiteConstant;
 import com.slodon.b2b2c.goods.example.GoodsExample;
 import com.slodon.b2b2c.goods.pojo.Goods;
 import com.slodon.b2b2c.member.example.MemberEnquiryExample;
@@ -20,7 +22,10 @@ import com.slodon.b2b2c.model.goods.GoodsModel;
 import com.slodon.b2b2c.model.member.advich.CountryModel;
 import com.slodon.b2b2c.model.member.advich.MemberEnquiryModel;
 import com.slodon.b2b2c.model.seller.StoreModel;
+import com.slodon.b2b2c.model.seller.StoreNameModel;
+import com.slodon.b2b2c.seller.example.StoreNameExample;
 import com.slodon.b2b2c.seller.pojo.Store;
+import com.slodon.b2b2c.seller.pojo.StoreName;
 import com.slodon.b2b2c.system.dto.EnquiryAddDTO;
 import com.slodon.b2b2c.system.example.CountryExample;
 import com.slodon.b2b2c.system.pojo.Country;
@@ -63,6 +68,9 @@ public class MemberEnquiryController extends BaseController {
     private StoreModel storeModel;
 
     @Resource
+    private StoreNameModel storeNameModel;
+
+    @Resource
     private CountryModel countryModel;
 
     /**
@@ -84,6 +92,7 @@ public class MemberEnquiryController extends BaseController {
         if (enquiryAddDTO.getQuantity() != null && (enquiryAddDTO.getQuantity() > Integer.MAX_VALUE || enquiryAddDTO.getQuantity() < Integer.MIN_VALUE)) {
             return SldResponse.fail(Language.translate("数量超出范围,请重试", Language.EN_LANGUAGE_TYPE));
         }
+        enquiryAddDTO.setWebSite(WebUtil.getWebSite(request));
         Integer key = memberEnquiryModel.saveEnquiry(request, enquiryAddDTO);
         return SldResponse.success(Language.translate("提交成功",Language.EN_LANGUAGE_TYPE),key);
     }
@@ -107,6 +116,7 @@ public class MemberEnquiryController extends BaseController {
         if (enquiryAddDTO.getQuantity() != null && (enquiryAddDTO.getQuantity() > Integer.MAX_VALUE || enquiryAddDTO.getQuantity() < Integer.MIN_VALUE)) {
             return SldResponse.fail(Language.translate("数量超出范围,请重试", Language.EN_LANGUAGE_TYPE));
         }
+        enquiryAddDTO.setWebSite(WebUtil.getWebSite(request));
         Integer key = memberEnquiryModel.saveEnquiry(request, enquiryAddDTO);
         return SldResponse.success(Language.translate("提交成功",Language.EN_LANGUAGE_TYPE),key);
     }
@@ -119,11 +129,12 @@ public class MemberEnquiryController extends BaseController {
     @GetMapping("list")
     public JsonResult<PageVO<MemberEnquiryVO>> getList(HttpServletRequest request, String keyword) {
         Member member = UserUtil.getUser(request, Member.class);
-
+        String webSite = WebUtil.getWebSite(request);
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         MemberEnquiryExample example = new MemberEnquiryExample();
         example.setCreateUid(member.getMemberId());
         example.setKeyword(keyword);
+        example.setWebSite(webSite);
         example.setPager(pager);
         List<MemberEnquiry> list = memberEnquiryModel.getEnquiryList(example, pager);
         ArrayList<MemberEnquiryVO> vos = new ArrayList<>();
@@ -141,6 +152,14 @@ public class MemberEnquiryController extends BaseController {
                 if (EnquiryConst.ENQUIRY_ITEM_TYPE_SHOP.equals(memberEnquiry.getItemType())) {
                     Store store = storeModel.getStoreByStoreId(memberEnquiry.getStoreId());
                     itemName = store.getStoreName();
+                    if (!WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+                        StoreNameExample storeNameExample = new StoreNameExample();
+                        storeNameExample.setStoreId(store.getStoreId());
+                        storeNameExample.setWebSite(webSite);
+                        StoreName storeName = storeNameModel.getStoreNameByExample(storeNameExample);
+                        itemName = storeName != null ? storeName.getStoreName() : store.getStoreName();
+                    }
+
                 }
                 memberEnquiry.setItemName(itemName);
                 vos.add(new MemberEnquiryVO(memberEnquiry));

+ 1 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/msg/seller/SellerVerifyController.java

@@ -148,7 +148,7 @@ public class SellerVerifyController extends BaseController {
         smsCodeModel.saveSmsCode(code);
 
         //将随机数存在redis中
-        stringRedisTemplate.opsForValue().set(mobile, smsResponse.getVerifyCode(), 60L * 10, TimeUnit.SECONDS);
+        stringRedisTemplate.opsForValue().set(mobile, smsResponse.getVerifyCode(), 60L * 5, TimeUnit.SECONDS);
         return SldResponse.success("发送成功");
     }
 

+ 2 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminCateAuditController.java

@@ -96,7 +96,8 @@ public class AdminCateAuditController {
                     VendorExample vendorExample = new VendorExample();
                     vendorExample.setStoreId(category.getStoreId());
                     vendorExample.setIsStoreAdmin(VendorConst.IS_STORE_ADMIN_1);
-                    vendor = vendorModel.getVendorList(vendorExample, null).get(0);
+                    List<Vendor> vendorList = vendorModel.getVendorList(vendorExample, null);
+                    vendor = !CollectionUtils.isEmpty(vendorList) ? vendorList.get(0) : new Vendor();
                     vendor.setStore(store);
                     vendorMap.put(category.getStoreId(), vendor);
                 }

+ 34 - 19
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminOwnStoreController.java

@@ -13,20 +13,11 @@ import com.slodon.b2b2c.core.util.CommonUtil;
 import com.slodon.b2b2c.core.util.UserUtil;
 import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.enums.WebSiteConstant;
-import com.slodon.b2b2c.model.seller.StoreCertificateModel;
-import com.slodon.b2b2c.model.seller.StoreModel;
-import com.slodon.b2b2c.model.seller.StoreNameModel;
-import com.slodon.b2b2c.model.seller.VendorModel;
+import com.slodon.b2b2c.model.seller.*;
 import com.slodon.b2b2c.seller.dto.OwnStoreAddDTO;
 import com.slodon.b2b2c.seller.dto.OwnStoreUpdateDTO;
-import com.slodon.b2b2c.seller.example.StoreCertificateExample;
-import com.slodon.b2b2c.seller.example.StoreExample;
-import com.slodon.b2b2c.seller.example.StoreNameExample;
-import com.slodon.b2b2c.seller.example.VendorExample;
-import com.slodon.b2b2c.seller.pojo.Store;
-import com.slodon.b2b2c.seller.pojo.StoreCertificate;
-import com.slodon.b2b2c.seller.pojo.StoreName;
-import com.slodon.b2b2c.seller.pojo.Vendor;
+import com.slodon.b2b2c.seller.example.*;
+import com.slodon.b2b2c.seller.pojo.*;
 import com.slodon.b2b2c.system.pojo.Admin;
 import com.slodon.b2b2c.vo.seller.OwnStoreDetailVO;
 import com.slodon.b2b2c.vo.seller.OwnStoreVO;
@@ -43,6 +34,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @author slodon
@@ -57,6 +49,8 @@ public class AdminOwnStoreController extends BaseController {
     @Resource
     private StoreNameModel storeNameModel;
     @Resource
+    private StoreSiteInfoModel storeSiteInfoModel;
+    @Resource
     private VendorModel vendorModel;
     @Resource
     private StoreCertificateModel storeCertificateModel;
@@ -75,12 +69,14 @@ public class AdminOwnStoreController extends BaseController {
     public JsonResult<PageVO<OwnStoreVO>> getList(HttpServletRequest request,
                                                   @RequestParam(value = "webSite", required = false,defaultValue = "1") String webSite,
                                                   @RequestParam(value = "storeName", required = false) String storeName,
-                                                  @RequestParam(value = "state", required = false) Integer state) {
+                                                  @RequestParam(value = "state", required = false) Integer state,
+                                                  @RequestParam(value = "businessState", required = false) Integer businessState) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
 
         StoreExample storeExample = new StoreExample();
         if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             storeExample.setStoreNameLike(storeName);
+            storeExample.setBusinessState(businessState);
         }
         storeExample.setState(state);
         storeExample.setStateNotEquals(StoreConst.STORE_STATE_DELETE);
@@ -88,14 +84,19 @@ public class AdminOwnStoreController extends BaseController {
         storeExample.setPager(pager);
         List<Store> storeList = storeModel.getStoreList(storeExample, pager);
         List<StoreName> storeNameList = Collections.emptyList();
+        List<StoreSiteInfo> storeSiteInfoList = Collections.emptyList();
         if (!WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             StoreNameExample storeNameExample = new StoreNameExample();
             storeNameExample.setStoreNameLike(storeName);
             storeNameExample.setWebSite(webSite);
             storeNameList = storeNameModel.getStoreNameList(new StoreNameExample(), null);
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setBusinessState(businessState);
+            storeSiteInfoExample.setStoreIdIn(storeNameList.stream().map(StoreName::getStoreId).collect(Collectors.toList()));
+            storeSiteInfoList = storeSiteInfoModel.getStoreSiteInfoList(storeSiteInfoExample, null);
         }
         List<OwnStoreVO> vos = new ArrayList<>();
-        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite) && CollectionUtils.isEmpty(storeSiteInfoList)) {
             return SldResponse.success(new PageVO<>(vos, new PagerInfo(10, 1)));
         }
         if (!CollectionUtils.isEmpty(storeList)) {
@@ -108,6 +109,10 @@ public class AdminOwnStoreController extends BaseController {
                             .findFirst()
                             .map(StoreName::getStoreName)
                             .orElse(""));
+                   StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+                   storeSiteInfoExample.setStoreId(store.getStoreId());
+                   StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(storeSiteInfoExample);
+                   vo.setBusinessState(storeSiteInfo != null ? storeSiteInfo.getBusinessState() : StoreConst.STORE_BUSINESS_STATE_DECORATION);
                 }
                 //根据店铺id获取商户账号
                 VendorExample vendorExample = new VendorExample();
@@ -144,7 +149,8 @@ public class AdminOwnStoreController extends BaseController {
     })
     @GetMapping("detail")
     public JsonResult<OwnStoreDetailVO> getDetail(HttpServletRequest request,
-                                                  @RequestParam("storeId") Long storeId) {
+                                                  @RequestParam("storeId") Long storeId,
+                                                  @RequestParam("webSite") String webSite) {
         //根据店铺id获取店铺信息
         Store store = storeModel.getStoreByStoreId(storeId);
 
@@ -159,10 +165,19 @@ public class AdminOwnStoreController extends BaseController {
         StoreCertificate storeCertificate = storeCertificateModel.getStoreCertificateList(storeCertificateExample, null).get(0);
         OwnStoreDetailVO vo = new OwnStoreDetailVO(store, storeCertificate);
 
-        StoreNameExample storeNameExample = new StoreNameExample();
-        storeNameExample.setStoreId(storeId);
-        StoreName storeName = storeNameModel.getStoreNameByExample(storeNameExample);
-        vo.setStoreNameCn(storeName.getStoreName());
+        if(WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)){
+            StoreNameExample storeNameExample = new StoreNameExample();
+            storeNameExample.setStoreId(storeId);
+            storeNameExample.setWebSite(webSite);
+            StoreName storeName = storeNameModel.getStoreNameByExample(storeNameExample);
+            vo.setStoreName(storeName != null ? storeName.getStoreName() : "");
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setStoreId(storeId);
+            storeSiteInfoExample.setWebSite(webSite);
+            StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(storeSiteInfoExample);
+            vo.setBusinessState(storeSiteInfo != null ? storeSiteInfo.getBusinessState() : 2);
+        }
+
         return SldResponse.success(vo);
     }
 

+ 8 - 6
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminStoreAuditController.java

@@ -89,9 +89,9 @@ public class AdminStoreAuditController {
         StoreApplyExample example = new StoreApplyExample();
         if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             example.setStoreNameLike(storeName);
+            example.setStoreGradeId(storeGradeId);
         }
         example.setVendorNameLike(vendorName);
-        example.setStoreGradeId(storeGradeId);
         example.setStoreType(StoreConst.NO_OWN_STORE);
         example.setPager(pager);
         example.setOrderBy("submit_time desc");
@@ -102,14 +102,19 @@ public class AdminStoreAuditController {
         }
         List<StoreApply> storeApplyList = storeApplyModel.getStoreApplyList(example, pager);
         List<StoreName> storeNameList = Collections.emptyList();
+        List<StoreSiteInfo> storeSiteInfoList = Collections.emptyList();
         if (!WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             StoreNameExample storeNameExample = new StoreNameExample();
             storeNameExample.setStoreNameLike(storeName);
             storeNameExample.setWebSite(webSite);
             storeNameList = storeNameModel.getStoreNameList(new StoreNameExample(), null);
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setStoreGradeId(storeGradeId);
+            storeSiteInfoExample.setStoreIdIn(storeNameList.stream().map(StoreName::getStoreId).collect(Collectors.toList()));
+            storeSiteInfoList = storeSiteInfoModel.getStoreSiteInfoList(storeSiteInfoExample, null);
         }
         List<StoreApplyVO> vos = new ArrayList<>();
-        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite) && CollectionUtils.isEmpty(storeSiteInfoList)) {
             return SldResponse.success(new PageVO<>(vos, new PagerInfo(10, 1)));
         }
         if (!CollectionUtils.isEmpty(storeApplyList)) {
@@ -131,10 +136,7 @@ public class AdminStoreAuditController {
                     storeSiteInfoExample.setStoreId(storeApply.getStoreId());
                     storeSiteInfoExample.setWebSite(webSite);
                     StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(storeSiteInfoExample);
-                    if (storeSiteInfo != null) {
-                        vo.setStoreGradeName(storeSiteInfo.getStoreGradeName());
-                    }
-
+                    vo.setStoreGradeName(storeSiteInfo != null ? storeSiteInfo.getStoreGradeName() : vo.getStoreGradeName());
                 }
 
                 //获取联系人名称和电话

+ 20 - 3
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/admin/AdminStoreController.java

@@ -88,30 +88,38 @@ public class AdminStoreController extends BaseController {
                                                @RequestParam(value = "storeName", required = false) String storeName,
                                                @RequestParam(value = "vendorName", required = false) String vendorName,
                                                @RequestParam(value = "storeGradeId", required = false) Integer storeGradeId,
-                                               @RequestParam(value = "state", required = false) Integer state) {
+                                               @RequestParam(value = "state", required = false) Integer state,
+                                               @RequestParam(value = "businessState", required = false) Integer businessState) {
 
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
 
         StoreExample storeExample = new StoreExample();
         if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             storeExample.setStoreNameLike(storeName);
+            storeExample.setBusinessState(businessState);
+            storeExample.setStoreGradeId(storeGradeId);
         }
         storeExample.setVendorNameLike(vendorName);
-        storeExample.setStoreGradeId(storeGradeId);
         storeExample.setState(state);
         storeExample.setStateNotEquals(StoreConst.STORE_STATE_DELETE);
         storeExample.setIsOwnStore(StoreConst.NO_OWN_STORE);
         storeExample.setPager(pager);
         List<Store> storeList = storeModel.getStoreList(storeExample, pager);
         List<StoreName> storeNameList = Collections.emptyList();
+        List<StoreSiteInfo> storeSiteInfoList = Collections.emptyList();
         if (!WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             StoreNameExample storeNameExample = new StoreNameExample();
             storeNameExample.setStoreNameLike(storeName);
             storeNameExample.setWebSite(webSite);
             storeNameList = storeNameModel.getStoreNameList(new StoreNameExample(), null);
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setBusinessState(businessState);
+            storeSiteInfoExample.setStoreGradeId(storeGradeId);
+            storeSiteInfoExample.setStoreIdIn(storeNameList.stream().map(StoreName::getStoreId).collect(Collectors.toList()));
+            storeSiteInfoList = storeSiteInfoModel.getStoreSiteInfoList(storeSiteInfoExample, null);
         }
         List<StoreVO> vos = new ArrayList<>();
-        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+        if (CollectionUtils.isEmpty(storeNameList) && !WebSiteConstant.MEMBER_OVERSEA.equals(webSite) && CollectionUtils.isEmpty(storeSiteInfoList)) {
             return SldResponse.success(new PageVO<>(vos, new PagerInfo(10, 1)));
         }
         if (!CollectionUtils.isEmpty(storeList)) {
@@ -124,6 +132,13 @@ public class AdminStoreController extends BaseController {
                             .findFirst()
                             .map(StoreName::getStoreName)
                             .orElse(""));
+                    StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+                    storeSiteInfoExample.setStoreId(store.getStoreId());
+                    StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(storeSiteInfoExample);
+                    vo.setStoreGradeName(storeSiteInfo != null ? storeSiteInfo.getStoreGradeName() : store.getStoreGradeName());
+                    vo.setBusinessState(storeSiteInfo != null ? storeSiteInfo.getBusinessState() : StoreConst.STORE_BUSINESS_STATE_DECORATION);
+                    vo.setCreateTime(storeSiteInfo != null ? storeSiteInfo.getCreateTime() : store.getCreateTime());
+                    vo.setStoreExpireTime(storeSiteInfo != null ? storeSiteInfo.getStoreExpireTime() : store.getStoreExpireTime());
                 }
                 //根据店铺id获取商户账号
                 VendorExample vendorExample = new VendorExample();
@@ -179,6 +194,7 @@ public class AdminStoreController extends BaseController {
         storeBusinessVO.setOpenTime(vo.getOpenTime());
         storeBusinessVO.setStoreGradeId(vo.getStoreGradeId());
         storeBusinessVO.setStoreGradeName(vo.getStoreGradeName());
+        storeBusinessVO.setBusinessState(vo.getBusinessState());
         storeBusinessVOList.add(storeBusinessVO);
 
         StoreNameExample storeNameExample = new StoreNameExample();
@@ -192,6 +208,7 @@ public class AdminStoreController extends BaseController {
         storeBusinessVO.setOpenTime(storeCn != null ? storeCn.getOpenTime() : null);
         storeBusinessVO.setStoreGradeId(storeCn != null ? storeCn.getStoreGradeId() : null);
         storeBusinessVO.setStoreGradeName(storeCn != null ? storeCn.getStoreGradeName() : null);
+        storeBusinessVO.setBusinessState(storeCn != null ? storeCn.getBusinessState() : null);
         storeBusinessVOList.add(storeBusinessVO);
 
         vo.setStoreBusinessVOList(storeBusinessVOList);

+ 2 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/front/FrontCategoryController.java

@@ -39,9 +39,11 @@ public class FrontCategoryController extends BaseController {
     @GetMapping("list")
     public JsonResult<List<StoreCategoryTreeVO>> getList(HttpServletRequest request) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
+        String webSite = WebUtil.getWebSite(request);
 
         List<StoreCategoryTreeVO> tree = new ArrayList<>();
         StoreInnerLabelExample storeInnerLabelExample = new StoreInnerLabelExample();
+        storeInnerLabelExample.setWebSite(webSite);
         storeInnerLabelExample.setParentInnerLabelId(0);
         storeInnerLabelExample.setIsShow(StoreCateConst.STORE_LABEL_IS_SHOW);
         List<StoreInnerLabel> storeInnerLabelList = storeInnerLabelModel.getStoreInnerLabelList(storeInnerLabelExample, pager);

+ 79 - 16
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/front/FrontStoreController.java

@@ -22,6 +22,7 @@ import com.slodon.b2b2c.core.util.TimeUtil;
 import com.slodon.b2b2c.core.util.UserUtil;
 import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.enums.SeoTypeConstant;
+import com.slodon.b2b2c.enums.WebSiteConstant;
 import com.slodon.b2b2c.goods.dto.SearchProductDTO;
 import com.slodon.b2b2c.member.example.MemberFollowStoreExample;
 import com.slodon.b2b2c.member.pojo.Member;
@@ -31,10 +32,7 @@ import com.slodon.b2b2c.model.goods.GoodsModel;
 import com.slodon.b2b2c.model.goods.StoreCertificateNewListModel;
 import com.slodon.b2b2c.model.member.MemberFollowStoreModel;
 import com.slodon.b2b2c.model.seller.*;
-import com.slodon.b2b2c.seller.example.StoreCertificateExample;
-import com.slodon.b2b2c.seller.example.StoreExample;
-import com.slodon.b2b2c.seller.example.StoreInnerLabelExample;
-import com.slodon.b2b2c.seller.example.VendorExample;
+import com.slodon.b2b2c.seller.example.*;
 import com.slodon.b2b2c.seller.pojo.*;
 import com.slodon.b2b2c.system.pojo.SysSeo;
 import com.slodon.b2b2c.vo.goods.SysSeoVO;
@@ -61,6 +59,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author slodon
@@ -74,6 +73,10 @@ public class FrontStoreController {
     @Resource
     private StoreModel storeModel;
     @Resource
+    private StoreNameModel storeNameModel;
+    @Resource
+    private StoreSiteInfoModel storeSiteInfoModel;
+    @Resource
     private VendorModel vendorModel;
     @Resource
     private StoreCertificateModel storeCertificateModel;
@@ -128,7 +131,11 @@ public class FrontStoreController {
         StoreExample storeExample = new StoreExample();
         storeExample.setState(StoreConst.STORE_STATE_OPEN);
 //        storeExample.setStoreIdIn(storeIds.substring(1));
-        storeExample.setStoreNameLike(keyword);
+        String webSite = WebUtil.getWebSite(request);
+        if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
+            storeExample.setStoreNameLike(keyword);
+            storeExample.setBusinessState(StoreConst.STORE_BUSINESS_STATE_OPEN);
+        }
         if (sort == 2) {
             storeExample.setOrderBy("store_look_volume DESC");
         } else {
@@ -136,6 +143,28 @@ public class FrontStoreController {
         }
 
         List<Store> storeList = storeModel.getStoreList(storeExample, pager);
+        List<StoreName> storeNameList = new ArrayList<>();
+        List<StoreSiteInfo> storeSiteInfoList = new ArrayList<>();
+        if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            StoreNameExample storeNameExample = new StoreNameExample();
+            storeNameExample.setStoreNameLike(keyword);
+            storeNameExample.setWebSite(webSite);
+            storeNameList = storeNameModel.getStoreNameList(storeNameExample, null);
+            if (CollectionUtils.isEmpty(storeNameList)) {
+                //没有满足条件的店铺
+                return SldResponse.success(new PageVO<>(vos, pager));
+            }
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setStoreIdIn(storeNameList.stream().map(StoreName::getStoreId).collect(Collectors.toList()));
+            storeSiteInfoExample.setWebSite(webSite);
+            storeSiteInfoExample.setBusinessState(StoreConst.STORE_BUSINESS_STATE_OPEN);
+            storeSiteInfoList = storeSiteInfoModel.getStoreSiteInfoList(storeSiteInfoExample, null);
+            if (CollectionUtils.isEmpty(storeSiteInfoList)) {
+                //没有满足条件的店铺
+                return SldResponse.success(new PageVO<>(vos, pager));
+            }
+        }
+
         if (CollectionUtils.isEmpty(storeList)) {
             //没有满足条件的店铺
             return SldResponse.success(new PageVO<>(vos, pager));
@@ -219,6 +248,27 @@ public class FrontStoreController {
 //            vo.setNewGoodsListVOS(storeGoodsOnlineList);
             vos.add(vo);
         }
+        for (StoreSiteInfo storeSiteInfo : storeSiteInfoList) {
+            Store store = storeModel.getStoreByStoreId(storeSiteInfo.getStoreId());
+            if (store != null) {
+                store.setStoreName(storeNameList.stream()
+                        .filter(storeNameWebSite -> storeNameWebSite.getStoreId().equals(storeSiteInfo.getStoreId()))
+                        .findFirst()
+                        .map(StoreName::getStoreName)
+                        .orElse(""));
+                store.setStoreLogo(storeSiteInfo.getStoreLogo());
+                //默认店铺logo
+                if (StringUtils.isEmpty(store.getStoreLogo())) {
+                    store.setStoreLogo(stringRedisTemplate.opsForValue().get("default_image_store_logo"));
+                }
+                //默认店铺背景图片(取移动端横幅)
+                if (StringUtils.isEmpty(store.getStoreBannerMobile())) {
+                    store.setStoreBannerMobile(stringRedisTemplate.opsForValue().get("default_image_store_backdrop"));
+                }
+                FrontStoreListVO vo = new FrontStoreListVO(store);
+                vos.add(vo);
+            }
+        }
 
         return SldResponse.success(new PageVO<>(vos, pager));
     }
@@ -231,9 +281,19 @@ public class FrontStoreController {
     @GetMapping("detail")
     public JsonResult<FrontStoreVO> detail(HttpServletRequest request, @RequestParam("storeId") Long storeId) throws IOException, WriterException {
         Member member = UserUtil.getUser(request, Member.class);
-
+        String webSite = WebUtil.getWebSite(request);
         Store store = storeModel.getStoreByStoreId(storeId);
-        if (store.getState() != StoreConst.STORE_STATE_OPEN) {
+        if(WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)){
+            store = storeSiteInfoModel.getStoreByStoreIdAndWebSite(storeId, webSite);
+            if (!StringUtils.isEmpty(store.getStoreId())) {
+                StoreNameExample storeNameExample = new StoreNameExample();
+                storeNameExample.setStoreId(store.getStoreId());
+                storeNameExample.setWebSite(webSite);
+                StoreName storeName = storeNameModel.getStoreNameByExample(storeNameExample);
+                store.setStoreName(storeName != null ? storeName.getStoreName() : null);
+            }
+        }
+        if (store.getState() != StoreConst.STORE_STATE_OPEN && store.getBusinessState() != StoreConst.STORE_BUSINESS_STATE_OPEN) {
             throw new MallException("店铺已关闭", ResponseConst.STATE_STORE_CLOSE);
         }
         //默认店铺logo
@@ -268,22 +328,22 @@ public class FrontStoreController {
         }
 
         //店铺荣誉资质信息(区别于上面的StoreCertificate老表)
-        List<StoreCertificateList> storeCertificateList = storeCertificateNewListModel.getStoreCertificateByStoreId(storeId);
+        List<StoreCertificateList> storeCertificateList = storeCertificateNewListModel.getStoreCertificateByStoreId(storeId, webSite);
         vo.setStoreCertificateList(storeCertificateList);
 
         //店铺简介图片信息
-        List<StoreProfileList> storeProfileList = storeProfileModel.getStoreProfileByStoreIdAndStatus(storeId);
+        List<StoreProfileList> storeProfileList = storeProfileModel.getStoreProfileByStoreIdAndStatus(storeId, webSite);
         vo.setStoreProfileList(storeProfileList);
         //店铺简介的内容信息
-        StoreProfileTextList storeProfileTextList = storeProfileTextListModel.getList(storeId, "1");
+        StoreProfileTextList storeProfileTextList = storeProfileTextListModel.getList(storeId, webSite);
         vo.setStoreProfileTextList(storeProfileTextList);
 
         //店铺工厂图片信息
-        List<StoreCompanyShowList> storeCompanyShowList = sellerStoreCompanyShowModel.getStoreCompanyShowByStoreIdAndStatus(storeId);
+        List<StoreCompanyShowList> storeCompanyShowList = sellerStoreCompanyShowModel.getStoreCompanyShowByStoreIdAndStatus(storeId, webSite);
         vo.setStoreCompanyShowList(storeCompanyShowList);
 
         //seo
-        SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(storeId, SeoTypeConstant.SEO_TYPE_SHOP);
+        SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(storeId, SeoTypeConstant.SEO_TYPE_SHOP, webSite);
         vo.setSeoInfo(sysSeoVO);
 
         //店铺二维码
@@ -316,15 +376,17 @@ public class FrontStoreController {
     })
     @GetMapping("storeCategory")
     public JsonResult<Object> storeCategory(HttpServletRequest request, @RequestParam("storeId") Long storeId) {
+        String webSite = WebUtil.getWebSite(request);
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         List<StoreCategoryTreeVO> tree = new ArrayList<>();
         StoreInnerLabelExample storeInnerLabelExample = new StoreInnerLabelExample();
+        storeInnerLabelExample.setWebSite(webSite);
         storeInnerLabelExample.setParentInnerLabelId(0);
         storeInnerLabelExample.setStoreId(storeId);
         storeInnerLabelExample.setOrderBy("inner_label_sort ASC");
         storeInnerLabelExample.setIsShow(StoreCateConst.STORE_LABEL_IS_SHOW);
         List<StoreInnerLabel> storeInnerLabelList = storeInnerLabelModel.getStoreInnerLabelList(storeInnerLabelExample, pager);
-        generateTree(tree, storeInnerLabelList, 2);
+        generateTree(tree, storeInnerLabelList, 2, webSite);
 
         return SldResponse.success(tree);
     }
@@ -336,7 +398,7 @@ public class FrontStoreController {
      * @param data     data
      * @return 返回列表
      */
-    private List<StoreCategoryTreeVO> generateTree(List<StoreCategoryTreeVO> treeList, List<StoreInnerLabel> data, Integer grade) {
+    private List<StoreCategoryTreeVO> generateTree(List<StoreCategoryTreeVO> treeList, List<StoreInnerLabel> data, Integer grade, String webSite) {
         if (grade > 0) {
             for (StoreInnerLabel storeInnerLabel : data) {
                 StoreCategoryTreeVO tree = new StoreCategoryTreeVO();
@@ -350,13 +412,14 @@ public class FrontStoreController {
 
 
                 StoreInnerLabelExample storeInnerLabelExample = new StoreInnerLabelExample();
+                storeInnerLabelExample.setWebSite(webSite);
                 storeInnerLabelExample.setParentInnerLabelId(storeInnerLabel.getInnerLabelId());
                 storeInnerLabelExample.setIsShow(StoreCateConst.STORE_LABEL_IS_SHOW);
                 storeInnerLabelExample.setOrderBy("inner_label_sort ASC");
                 tree.setChildren(generateTree(new ArrayList<>(),
-                        storeInnerLabelModel.getStoreInnerLabelList(storeInnerLabelExample, null), grade - 1));
+                        storeInnerLabelModel.getStoreInnerLabelList(storeInnerLabelExample, null), grade - 1,webSite));
                 SysSeoVO sysSeoVO = storeModel.getRecordByTargetIdAndTypeForStoreDetail(Integer.valueOf(tree.getInnerLabelId()).longValue(),
-                        SeoTypeConstant.SEO_TYPE_SHOP_CATEGORY);
+                        SeoTypeConstant.SEO_TYPE_SHOP_CATEGORY,webSite);
                 tree.setSeoInfo(sysSeoVO);
 
                 treeList.add(tree);

+ 20 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/seller/SellerStoreController.java

@@ -91,8 +91,12 @@ public class SellerStoreController extends BaseController {
                 store.setServicePhone(null);
                 store.setAddress(null);
                 store.setEmail(null);
+                store.setOpenTime(null);
+                store.setStoreGradeId(null);
+                store.setStoreGradeName(null);
                 store.setStoreMapInfo(null);
                 store.setStoreMapInfoW(null);
+                store.setBusinessState(StoreConst.STORE_BUSINESS_STATE_TO_AUDIT);
             }
             StoreNameExample storeNameExample = new StoreNameExample();
             storeNameExample.setStoreId(vendor.getStoreId());
@@ -217,8 +221,7 @@ public class SellerStoreController extends BaseController {
             }
         } else {
             store = storeSiteInfoModel.getStoreByStoreIdAndWebSite(vendor.getStoreId(), webSite);
-            store.setStoreGradeId(storeModel.getStoreByStoreId(vendor.getStoreId()).getStoreGradeId());
-            store.setStoreGradeName(storeModel.getStoreByStoreId(vendor.getStoreId()).getStoreGradeName());
+            store.setBusinessState(store.getBusinessState() == null ? StoreConst.STORE_BUSINESS_STATE_TO_AUDIT : store.getBusinessState());
             SysSeo seoInfo = storeModel.getRecordByTargetIdAndType(vendor.getStoreId(), SeoTypeConstant.SEO_TYPE_SHOP + "_" + webSite);
             if (seoInfo != null) {
                 store.setStoreSeoTitle(seoInfo.getTitle());
@@ -242,6 +245,7 @@ public class SellerStoreController extends BaseController {
     @ApiOperation("编辑店铺设置接口")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "webSite", value = "站点", paramType = "query"),
+            @ApiImplicitParam(name = "businessState", value = "经营状态", paramType = "query"),
             @ApiImplicitParam(name = "mainBusiness", value = "店铺主营商品名称,用','分隔,例如'男装,女装,童装'"),
             @ApiImplicitParam(name = "storeLogo", value = "店铺logo"),
             @ApiImplicitParam(name = "servicePhone", value = "店铺客服电话"),
@@ -261,6 +265,7 @@ public class SellerStoreController extends BaseController {
     @PostMapping("updateSetting")
     public JsonResult<Integer> updateStoreSetting(HttpServletRequest request,
                                                   @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
+                                                  @RequestParam(value = "businessState", required = false) Integer businessState,
                                                   @RequestParam(value = "mainBusiness", required = false) String mainBusiness,
                                                   @RequestParam(value = "storeLogo", required = false) String storeLogo,
                                                   @RequestParam(value = "servicePhone", required = false) String servicePhone,
@@ -282,6 +287,7 @@ public class SellerStoreController extends BaseController {
         if (WebSiteConstant.MEMBER_OVERSEA.equals(webSite)) {
             Store store = new Store();
             store.setStoreId(vendor.getStoreId());
+            store.setBusinessState(businessState);
             store.setMainBusiness(mainBusiness);
             store.setStoreLogo(storeLogo);
             store.setServicePhone(servicePhone);
@@ -302,6 +308,7 @@ public class SellerStoreController extends BaseController {
             StoreSiteInfo storeSiteInfo = new StoreSiteInfo();
             storeSiteInfo.setStoreId(vendor.getStoreId());
             storeSiteInfo.setWebSite(webSite);
+            storeSiteInfo.setBusinessState(businessState);
             storeSiteInfo.setMainBusiness(mainBusiness);
             storeSiteInfo.setStoreLogo(storeLogo);
             storeSiteInfo.setServicePhone(servicePhone);
@@ -386,6 +393,17 @@ public class SellerStoreController extends BaseController {
             storeNameExample.setStoreId(vendor.getStoreId());
             List<StoreName> storeNameList = storeNameModel.getStoreNameList(storeNameExample, null);
             store.setStoreName(CollectionUtils.isEmpty(storeNameList) ? store.getStoreName() : storeNameList.get(0).getStoreName());
+
+            StoreSiteInfoExample storeSiteInfoExample = new StoreSiteInfoExample();
+            storeSiteInfoExample.setStoreId(vendor.getStoreId());
+            StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(storeSiteInfoExample);
+            if (storeSiteInfo != null) {
+                store.setStoreGradeId(storeSiteInfo.getStoreGradeId());
+                store.setStoreGradeName(storeSiteInfo.getStoreGradeName());
+                store.setStoreExpireTime(storeSiteInfo.getStoreExpireTime());
+                store.setStoreLogo(storeSiteInfo.getStoreLogo());
+                store.setBusinessState(storeSiteInfo.getBusinessState());
+            }
         }
         //店铺默认logo
         if (StringUtils.isEmpty(store.getStoreLogo())) {

+ 1 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/seller/seller/SellerVendorController.java

@@ -270,6 +270,7 @@ public class SellerVendorController extends BaseController {
         vendorUpdate.setVendorId(allVendorList.get(0).getVendorId());
         vendorUpdate.setVendorPassword(Md5.getMd5String(newPwd));
         vendorModel.updateVendor(vendorUpdate);
+        stringRedisTemplate.delete(mobile);
         return SldResponse.success("修改成功");
     }
 

+ 7 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/sso/front/FrontAuthController.java

@@ -101,8 +101,9 @@ public class FrontAuthController {
     })
     @PostMapping("token")
     public JsonResult<Object> doLogin(HttpServletRequest request, @RequestParam(value = "loginType", required = false, defaultValue = "1") Integer loginType,
-                                      String username, String password, String cartInfo, String clientId, String alias, String refresh_token, Integer ssoType,@RequestParam(value = "webSite",required = false, defaultValue = "1") String webSite) {
+                                      String username, String password, String cartInfo, String clientId, String alias, String refresh_token, Integer ssoType) {
         Member member;
+        String webSite = WebUtil.getWebSite(request);
         if (!StringUtils.isEmpty(refresh_token)) {
             //校验token
             String memberId = JWTRSA256Util.validToken(refresh_token);
@@ -126,7 +127,7 @@ public class FrontAuthController {
                         memberList = memberModel.getMemberList(memberExample, null);
                     }
                 } else {
-                    AssertUtil.notEmpty(memberList, Language.translate("会员邮箱或密码错误",Language.EN_LANGUAGE_TYPE));
+                    AssertUtil.notEmpty(memberList, Language.translate("会员账号或密码错误",Language.EN_LANGUAGE_TYPE));
                     if (ssoType != null && ssoType == 1) {
                         AssertUtil.isTrue(!memberList.get(0).getLoginPwd().equals(password), Language.translate("会员邮箱或密码错误",Language.EN_LANGUAGE_TYPE));
                     } else {
@@ -268,8 +269,11 @@ public class FrontAuthController {
     })
     @PostMapping("register")
     public JsonResult<Object> registerMember(HttpServletRequest request, String phone, String code, String verifyCode, String verifyKey, Integer source) {
+       String webSite= WebUtil.getWebSite(request);
+
         //判断会员表中是否有重复的手机号
         MemberExample memberExample = new MemberExample();
+        memberExample.setWebSite(webSite);
         memberExample.setMemberMobile(phone);
         List<Member> memberList = memberModel.getMemberList(memberExample, null);
         AssertUtil.isTrue(!CollectionUtils.isEmpty(memberList), "该手机号已注册");
@@ -296,6 +300,7 @@ public class FrontAuthController {
         Member member = new Member();
         member.setMemberName(GoodsIdGenerator.getMemberName());
         member.setMemberMobile(phone);
+        member.setWebSite(webSite);
         member.setLoginPwd("");
         member.setPayPwd("");
         member.setLastLoginIp("");

+ 19 - 5
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminFlowAnalysisController.java

@@ -55,12 +55,13 @@ public class AdminFlowAnalysisController extends BaseController {
 
     @ApiOperation("流量总览")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "terminalType", value = "终端类型:Android,IOS,pc,H5,xcx 默认全部不传")
     })
     @GetMapping("flowOverview")
-    public JsonResult<FlowOverviewVO> flowOverview(HttpServletRequest request, Date startTime, Date endTime, String terminalType) {
+    public JsonResult<FlowOverviewVO> flowOverview(HttpServletRequest request, String webSite, Date startTime, Date endTime, String terminalType) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         //上期开始时间和结束时间
         Date preStartTime;
@@ -93,13 +94,13 @@ public class AdminFlowAnalysisController extends BaseController {
             }
         } else {
             //终端类型为空,查询平台数据
-            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, startTime, endTime);
+            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType,webSite, startTime, endTime);
             if (!CollectionUtils.isEmpty(list)) {
                 PlatformBase platformBase = list.get(0);
                 //上期数据
                 PlatformBase previousData = null;
                 if (preStartTime != null) {
-                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, preStartTime, preEndTime);
+                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType,webSite, preStartTime, preEndTime);
                     if (!CollectionUtils.isEmpty(previousList)) {
                         previousData = previousList.get(0);
                     }
@@ -189,7 +190,7 @@ public class AdminFlowAnalysisController extends BaseController {
     @GetMapping("goodsFlowRank")
     public JsonResult<List<GoodsRankVO>> goodsFlowRank(HttpServletRequest request, Date startTime, Date endTime,@RequestParam(name = "webSite", required = false,defaultValue = "1") String webSite,Integer sort) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
-        List<? extends GoodsBase> list = statsModelUtil.getGoodsList(timeType, startTime, endTime,webSite , sort, "flow", null);
+        List<? extends GoodsBase> list = statsModelUtil.getGoodsList(timeType, startTime, endTime, webSite, sort, "flow", null);
         List<GoodsRankVO> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(list)) {
             list.forEach(goodsBase -> {
@@ -204,6 +205,7 @@ public class AdminFlowAnalysisController extends BaseController {
 
     @ApiOperation("流量报表(按天)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "type", value = "排序类型;desc-降序;asc-升序;默认类型为降序"),
@@ -213,7 +215,9 @@ public class AdminFlowAnalysisController extends BaseController {
             @ApiImplicitParam(name = "current", value = "当前页面位置", defaultValue = "1", paramType = "query")
     })
     @GetMapping("flowReport")
-    public JsonResult<PageVO<FlowReportVO>> flowReport(HttpServletRequest request, Date startTime, Date endTime,
+    public JsonResult<PageVO<FlowReportVO>> flowReport(HttpServletRequest request,
+                                                       @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
+                                                       Date startTime, Date endTime,
                                                        @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                                        @RequestParam(value = "sort", required = false, defaultValue = "stats_time") String sort) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
@@ -221,6 +225,7 @@ public class AdminFlowAnalysisController extends BaseController {
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
         example.setOrderBy(sort + " " + type);
+        example.setWebSite(webSite);
         List<PlatformDay> list = platformDayModel.getPlatformDayList(example, pager);
         List<FlowReportVO> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(list)) {
@@ -233,6 +238,7 @@ public class AdminFlowAnalysisController extends BaseController {
 
     @ApiOperation("流量报表(按店铺)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "storeName", value = "店铺名称"),
@@ -244,6 +250,7 @@ public class AdminFlowAnalysisController extends BaseController {
     })
     @GetMapping("storeReport")
     public JsonResult<PageVO<AdminFlowReportVO>> storeReport(HttpServletRequest request, Date startTime, Date endTime, String storeName,
+                                                             @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
                                                              @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                                              @RequestParam(value = "sort", required = false, defaultValue = "visitorNum") String sort) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
@@ -251,6 +258,7 @@ public class AdminFlowAnalysisController extends BaseController {
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
         example.setStoreNameLike(storeName);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         List<StoreBase> list = storeDayModel.getStoreList(example, pager);
         List<AdminFlowReportVO> vos = new ArrayList<>();
@@ -264,6 +272,7 @@ public class AdminFlowAnalysisController extends BaseController {
 
     @ApiOperation("导出报表(按天)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "type", value = "排序类型;desc-降序;asc-升序;默认类型为降序"),
@@ -272,11 +281,13 @@ public class AdminFlowAnalysisController extends BaseController {
     })
     @GetMapping("dayExport")
     public JsonResult dayExport(HttpServletRequest request, HttpServletResponse response, Date startTime, Date endTime,
+                                @RequestParam(value = "webSite", required = false, defaultValue = "1")String webSite,
                                 @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                 @RequestParam(value = "sort", required = false, defaultValue = "stats_time") String sort) {
         PlatformDayExample example = new PlatformDayExample();
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         platformDayModel.flowReportExport(request, response, example);
         return null;
@@ -284,6 +295,7 @@ public class AdminFlowAnalysisController extends BaseController {
 
     @ApiOperation("导出报表(按店铺)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "storeName", value = "店铺名称"),
@@ -293,12 +305,14 @@ public class AdminFlowAnalysisController extends BaseController {
     })
     @GetMapping("storeExport")
     public JsonResult storeExport(HttpServletRequest request, HttpServletResponse response, Date startTime, Date endTime, String storeName,
+                                  @RequestParam(value = "webSite", required = false, defaultValue = "1")String webSite,
                                   @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                   @RequestParam(value = "sort", required = false, defaultValue = "visitorNum") String sort) {
         StoreDayExample example = new StoreDayExample();
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
         example.setStoreNameLike(storeName);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         storeDayModel.storeFlowReportExport(request, response, example);
         return null;

+ 15 - 7
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminGoodsAnalysisController.java

@@ -57,26 +57,29 @@ public class AdminGoodsAnalysisController extends BaseController {
 
     @ApiOperation("商品总览(商品总数和品牌总数)")
     @GetMapping("goodsBrandNum")
-    public JsonResult<GoodsBrandNumVO> goodsBrandNum(HttpServletRequest request) {
+    public JsonResult<GoodsBrandNumVO> goodsBrandNum(HttpServletRequest request,String webSite) {
         GoodsBrandNumVO vo = new GoodsBrandNumVO();
         GoodsExample example = new GoodsExample();
         example.setStateNotEquals(GoodsConst.GOODS_STATE_DELETE);
+        example.setWebSite(webSite);
         vo.setGoodsTotalNum(goodsModel.getGoodsCount(example));
         GoodsBrandExample brandExample = new GoodsBrandExample();
         brandExample.setStateNotEquals(GoodsConst.BRAND_STATE_4);
+        brandExample.setWebSite(webSite);
         vo.setBrandTotalNum(goodsBrandModel.getBrandCount(brandExample));
         return SldResponse.success(vo);
     }
 
     @ApiOperation("商品总览")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true)
     })
     @GetMapping("goodsOverview")
-    public JsonResult<GoodsOverviewVO> goodsOverview(HttpServletRequest request, Date startTime, Date endTime) {
+    public JsonResult<GoodsOverviewVO> goodsOverview(HttpServletRequest request, String webSite,Date startTime, Date endTime) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
-        List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, startTime, endTime);
+        List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, webSite, startTime, endTime);
         GoodsOverviewVO vo = new GoodsOverviewVO();
         if (!CollectionUtils.isEmpty(list)) {
             PlatformBase platformBase = list.get(0);
@@ -93,7 +96,7 @@ public class AdminGoodsAnalysisController extends BaseController {
                 preEndTime = StatsTimeType.getEndTime(endTime, timeType);
             }
             if (preStartTime != null) {
-                List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, preStartTime, preEndTime);
+                List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, webSite, preStartTime, preEndTime);
                 if (!CollectionUtils.isEmpty(previousList)) {
                     previousData = previousList.get(0);
                 }
@@ -157,16 +160,17 @@ public class AdminGoodsAnalysisController extends BaseController {
 
     @ApiOperation("品牌销售排行-TOP10")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "sort", value = "排序:1-销售额;2-销量 默认不传按销售额降序")
     })
     @GetMapping("brandSalesRank")
-    public JsonResult<List<BrandRankVO>> brandSalesRank(HttpServletRequest request, Date startTime, Date endTime, Integer sort) {
+    public JsonResult<List<BrandRankVO>> brandSalesRank(HttpServletRequest request,String webSite, Date startTime, Date endTime, Integer sort) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         //默认查询前十条数据
         PagerInfo pager = new PagerInfo(10, 1);
-        List<? extends BrandBase> list = statsModelUtil.getBrandList(timeType, startTime, endTime, sort, pager);
+        List<? extends BrandBase> list = statsModelUtil.getBrandList(timeType, webSite, startTime, endTime, sort, pager);
         List<BrandRankVO> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(list)) {
             list.forEach(brandBase -> {
@@ -222,6 +226,7 @@ public class AdminGoodsAnalysisController extends BaseController {
 
     @ApiOperation("商品报表(按天)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "type", value = "排序类型;desc-降序;asc-升序;默认类型为降序"),
@@ -231,7 +236,9 @@ public class AdminGoodsAnalysisController extends BaseController {
             @ApiImplicitParam(name = "current", value = "当前页面位置", defaultValue = "1", paramType = "query")
     })
     @GetMapping("dayReport")
-    public JsonResult<PageVO<GoodsReportVO>> dayReport(HttpServletRequest request, Date startTime, Date endTime,
+    public JsonResult<PageVO<GoodsReportVO>> dayReport(HttpServletRequest request,
+                                                       String webSite,
+                                                       Date startTime, Date endTime,
                                                        @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                                        @RequestParam(value = "sort", required = false, defaultValue = "stats_time") String sort) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
@@ -239,6 +246,7 @@ public class AdminGoodsAnalysisController extends BaseController {
         PlatformDayExample example = new PlatformDayExample();
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         List<PlatformDay> list = platformDayModel.getPlatformDayList(example, pager);
         if (!CollectionUtils.isEmpty(list)) {

+ 19 - 4
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminMemberAnalysisController.java

@@ -65,14 +65,16 @@ public class AdminMemberAnalysisController extends BaseController {
 
     @ApiOperation("会员总览(会员总数)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "terminalType", value = "终端类型:Android,IOS,pc,H5,xcx 默认全部不传")
     })
     @GetMapping("memberNum")
-    public JsonResult memberNum(HttpServletRequest request, String terminalType) {
+    public JsonResult memberNum(HttpServletRequest request, String webSite,String terminalType) {
         MemberExample example = new MemberExample();
         if (!StringUtil.isEmpty(terminalType)) {
             example.setRegisterChannel(getMemberSource(terminalType));
         }
+        example.setWebSite(webSite);
         Map<String, Integer> map = new HashMap<>();
         map.put("memberNum", memberModel.getMemberCount(example));
         return SldResponse.success(map);
@@ -80,12 +82,13 @@ public class AdminMemberAnalysisController extends BaseController {
 
     @ApiOperation("会员总览")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "terminalType", value = "终端类型:Android,IOS,pc,H5,xcx 默认全部不传")
     })
     @GetMapping("goodsOverview")
-    public JsonResult<MemberOverviewVO> goodsOverview(HttpServletRequest request, Date startTime, Date endTime, String terminalType) {
+    public JsonResult<MemberOverviewVO> goodsOverview(HttpServletRequest request,String webSite, Date startTime, Date endTime, String terminalType) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         MemberOverviewVO vo = new MemberOverviewVO();
         //上期开始时间和结束时间
@@ -116,13 +119,13 @@ public class AdminMemberAnalysisController extends BaseController {
                 }
             }
         } else {
-            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, startTime, endTime);
+            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType,webSite, startTime, endTime);
             if (!CollectionUtils.isEmpty(list)) {
                 PlatformBase platformBase = list.get(0);
                 //上期数据
                 PlatformBase previousData = null;
                 if (preStartTime != null) {
-                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, preStartTime, preEndTime);
+                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, webSite, preStartTime, preEndTime);
                     if (!CollectionUtils.isEmpty(previousList)) {
                         previousData = previousList.get(0);
                     }
@@ -220,6 +223,7 @@ public class AdminMemberAnalysisController extends BaseController {
     @ApiImplicitParams({
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "type", value = "排序类型;desc-降序;asc-升序;默认类型为降序"),
             @ApiImplicitParam(name = "sort", value = "排序:stats_time-时间;new_member_num-新增会员数;recharge_member_num-储值会员数;" +
                     "order_submit_member_num-下单人数;order_pay_member_num-支付人数;默认按时间降序排序"),
@@ -228,12 +232,14 @@ public class AdminMemberAnalysisController extends BaseController {
     })
     @GetMapping("dayReport")
     public JsonResult<PageVO<PlatformMemberReportVO>> dayReport(HttpServletRequest request, Date startTime, Date endTime,
+                                                                @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
                                                                 @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                                                 @RequestParam(value = "sort", required = false, defaultValue = "stats_time") String sort) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         PlatformDayExample example = new PlatformDayExample();
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         List<PlatformDay> list = platformDayModel.getPlatformDayList(example, pager);
         List<PlatformMemberReportVO> vos = new ArrayList<>();
@@ -249,6 +255,7 @@ public class AdminMemberAnalysisController extends BaseController {
     @ApiImplicitParams({
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "memberName", value = "会员名称"),
             @ApiImplicitParam(name = "registerStartTime", value = "注册开始时间"),
             @ApiImplicitParam(name = "registerEndTime", value = "注册结束时间"),
@@ -261,6 +268,7 @@ public class AdminMemberAnalysisController extends BaseController {
     @GetMapping("memberReport")
     public JsonResult<PageVO<MemberReportVO>> memberReport(HttpServletRequest request, Date startTime, Date endTime, String memberName,
                                                            Date registerStartTime, Date registerEndTime,
+                                                           @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
                                                            @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                                            @RequestParam(value = "sort", required = false, defaultValue = "registerTime") String sort) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
@@ -270,6 +278,7 @@ public class AdminMemberAnalysisController extends BaseController {
         example.setMemberNameLike(memberName);
         example.setRegisterTimeAfter(registerStartTime);
         example.setRegisterTimeBefore(registerEndTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         List<MemberBase> list = memberDayModel.getMemberList(example, pager);
         List<MemberReportVO> vos = new ArrayList<>();
@@ -285,17 +294,20 @@ public class AdminMemberAnalysisController extends BaseController {
     @ApiImplicitParams({
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "type", value = "排序类型;desc-降序;asc-升序;默认类型为降序"),
             @ApiImplicitParam(name = "sort", value = "排序:stats_time-时间;new_member_num-新增会员数;recharge_member_num-储值会员数;" +
                     "order_submit_member_num-下单人数;order_pay_member_num-支付人数;默认按时间降序排序")
     })
     @GetMapping("dayExport")
     public JsonResult dayExport(HttpServletRequest request, HttpServletResponse response, Date startTime, Date endTime,
+                                @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
                                 @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                 @RequestParam(value = "sort", required = false, defaultValue = "stats_time") String sort) {
         PlatformDayExample example = new PlatformDayExample();
         example.setStatsTimeAfter(startTime);
         example.setStatsTimeBefore(endTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         platformDayModel.memberReportExport(request, response, example);
         return null;
@@ -305,6 +317,7 @@ public class AdminMemberAnalysisController extends BaseController {
     @ApiImplicitParams({
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "memberName", value = "会员名称"),
             @ApiImplicitParam(name = "registerStartTime", value = "注册开始时间"),
             @ApiImplicitParam(name = "registerEndTime", value = "注册结束时间"),
@@ -315,6 +328,7 @@ public class AdminMemberAnalysisController extends BaseController {
     @GetMapping("memberExport")
     public JsonResult memberExport(HttpServletRequest request, HttpServletResponse response, Date startTime, Date endTime, String memberName,
                                    Date registerStartTime, Date registerEndTime,
+                                   @RequestParam(value = "webSite", required = false, defaultValue = "1") String webSite,
                                    @RequestParam(value = "type", required = false, defaultValue = "desc") String type,
                                    @RequestParam(value = "sort", required = false, defaultValue = "registerTime") String sort) {
         MemberDayExample example = new MemberDayExample();
@@ -323,6 +337,7 @@ public class AdminMemberAnalysisController extends BaseController {
         example.setMemberNameLike(memberName);
         example.setRegisterTimeAfter(registerStartTime);
         example.setRegisterTimeBefore(registerEndTime);
+        example.setWebSite(webSite);
         example.setOrderBy(sort + " " + type);
         memberDayModel.memberReportExport(request, response, example);
         return null;

+ 4 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminOverviewController.java

@@ -450,18 +450,20 @@ public class AdminOverviewController extends BaseController {
 
     @ApiOperation("品牌销售占比")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "sort", value = "排序:1-销售额;2-销量 默认不传按销售额降序")
     })
     @GetMapping("brandSalesPercent")
-    public JsonResult<BrandPercentVO> brandSalesPercent(HttpServletRequest request, Date startTime, Date endTime, Integer sort) {
+    public JsonResult<BrandPercentVO> brandSalesPercent(HttpServletRequest request,String webSite, Date startTime, Date endTime, Integer sort) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         List<? extends BrandBase> list;
         if (timeType.equals(StatsTimeType.DAY)) {
             BrandDayExample example = new BrandDayExample();
             example.setStatsTimeAfter(startTime);
             example.setStatsTimeBefore(endTime);
+            example.setWebSite(webSite);
             if (!StringUtil.isNullOrZero(sort) && sort == 2) {
                 example.setOrderBy("saleNum DESC");
             } else {
@@ -469,7 +471,7 @@ public class AdminOverviewController extends BaseController {
             }
             list = brandDayModel.getBrandList(example, null);
         } else {
-            list = statsModelUtil.getBrandList(timeType, startTime, endTime, sort, null);
+            list = statsModelUtil.getBrandList(timeType, webSite, startTime, endTime, sort, null);
         }
         BrandPercentVO vo = getBrandSalesPercent(list);
         return SldResponse.success(vo);

+ 2 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminPresentAnalysisController.java

@@ -47,7 +47,7 @@ public class AdminPresentAnalysisController {
             DateTime startTime = DateUtil.beginOfDay(endTime);//今日0时开始
 
             //计算实时统计数据
-            AdminPresentDataVO vo = platformPresentDataUtil.calculatePresentData(startTime, endTime,webSite);
+            AdminPresentDataVO vo = platformPresentDataUtil.calculatePresentData(startTime, endTime, webSite);
 
             //缓存数据
             objectRedisTemplate.opsForHash().put(StatsConstant.ADMIN_PRESENT_REDIS_KEY + "_" + webSite, StatsConstant.ADMIN_PRESENT_REDIS_KEY + "_" + webSite, vo);
@@ -63,7 +63,7 @@ public class AdminPresentAnalysisController {
             DateTime startTime = DateUtil.beginOfDay(endTime);//今日0时开始
 
             //计算实时统计数据
-            AdminPresentDataVO vo = platformPresentDataUtil.calculatePresentData(startTime, endTime,webSite);
+            AdminPresentDataVO vo = platformPresentDataUtil.calculatePresentData(startTime, endTime, webSite);
 
             //缓存数据
             objectRedisTemplate.opsForHash().put(StatsConstant.ADMIN_PRESENT_REDIS_KEY + "_" + webSite, StatsConstant.ADMIN_PRESENT_REDIS_KEY + "_" + webSite, vo);

+ 24 - 7
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminStoreAnalysisController.java

@@ -10,11 +10,15 @@ import com.slodon.b2b2c.core.util.StringUtil;
 import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.enums.ProvinceJson;
 import com.slodon.b2b2c.enums.StatsTimeType;
+import com.slodon.b2b2c.enums.WebSiteConstant;
 import com.slodon.b2b2c.model.seller.StoreModel;
+import com.slodon.b2b2c.model.seller.StoreSiteInfoModel;
 import com.slodon.b2b2c.model.statistics.StoreDayModel;
 import com.slodon.b2b2c.seller.dto.StoreStatisticsDTO;
 import com.slodon.b2b2c.seller.example.StoreExample;
+import com.slodon.b2b2c.seller.example.StoreSiteInfoExample;
 import com.slodon.b2b2c.seller.pojo.Store;
+import com.slodon.b2b2c.seller.pojo.StoreSiteInfo;
 import com.slodon.b2b2c.statistics.example.StoreDayExample;
 import com.slodon.b2b2c.statistics.pojo.base.PlatformBase;
 import com.slodon.b2b2c.statistics.pojo.base.StoreBase;
@@ -47,6 +51,8 @@ public class AdminStoreAnalysisController extends BaseController {
     private StatsModelUtil statsModelUtil;
     @Resource
     private StoreModel storeModel;
+    @Resource
+    private StoreSiteInfoModel storeSiteInfoModel;
 
     @ApiOperation("店铺总览(店铺总数)")
     @GetMapping("storeNum")
@@ -60,14 +66,15 @@ public class AdminStoreAnalysisController extends BaseController {
 
     @ApiOperation("店铺总览")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true)
     })
     @GetMapping("storeOverview")
-    public JsonResult<StoreOverviewVO> storeOverview(HttpServletRequest request, Date startTime, Date endTime) {
+    public JsonResult<StoreOverviewVO> storeOverview(HttpServletRequest request,String webSite, Date startTime, Date endTime) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         StoreOverviewVO vo = new StoreOverviewVO();
-        List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, startTime, endTime);
+        List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, webSite, startTime, endTime);
         if (!CollectionUtils.isEmpty(list)) {
             PlatformBase platformBase = list.get(0);
             //上期数据
@@ -83,7 +90,7 @@ public class AdminStoreAnalysisController extends BaseController {
                 preEndTime = StatsTimeType.getEndTime(endTime, timeType);
             }
             if (preStartTime != null) {
-                List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, preStartTime, preEndTime);
+                List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, webSite, preStartTime, preEndTime);
                 if (!CollectionUtils.isEmpty(previousList)) {
                     previousData = previousList.get(0);
                 }
@@ -130,10 +137,10 @@ public class AdminStoreAnalysisController extends BaseController {
 
     @ApiOperation("店铺等级分布占比")
     @GetMapping("gradePercent")
-    public JsonResult<List<StoreGradePercentVO>> gradePercent(HttpServletRequest request) {
+    public JsonResult<List<StoreGradePercentVO>> gradePercent(HttpServletRequest request,String webSite) {
         StoreExample example = new StoreExample();
         List<Store> list = storeModel.getStoreList(example, null);
-        List<StoreGradePercentVO> vos = getStoreGradePercent(list);
+        List<StoreGradePercentVO> vos = getStoreGradePercent(list, webSite);
         return SldResponse.success(vos);
     }
 
@@ -246,7 +253,7 @@ public class AdminStoreAnalysisController extends BaseController {
      * @param list
      * @return
      */
-    public List<StoreGradePercentVO> getStoreGradePercent(List<Store> list) {
+    public List<StoreGradePercentVO> getStoreGradePercent(List<Store> list, String webSite) {
         List<StoreGradePercentVO> result = new ArrayList<>();
         if (CollectionUtils.isEmpty(list)) {
             return result;
@@ -256,13 +263,23 @@ public class AdminStoreAnalysisController extends BaseController {
         //key为等级名称,value为店铺数量
         Map<String, Integer> dataMap = new HashMap<>();
         for (Store store : list) {
-            String gradeName = StringUtil.isEmpty(store.getStoreGradeName()) ? ProvinceJson.defaultProvinceName : store.getStoreGradeName();
+            String gradeName;
+            if(WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)){
+                StoreSiteInfoExample example = new StoreSiteInfoExample();
+                example.setStoreId(store.getStoreId());
+                example.setWebSite(webSite);
+                StoreSiteInfo storeSiteInfo = storeSiteInfoModel.getStoreSiteInfo(example);
+                gradeName = null != storeSiteInfo ? storeSiteInfo.getStoreGradeName() : ProvinceJson.defaultProvinceName;
+            }else {
+               gradeName = StringUtil.isEmpty(store.getStoreGradeName()) ? ProvinceJson.defaultProvinceName : store.getStoreGradeName();
+            }
             if (dataMap.containsKey(gradeName)) {
                 dataMap.put(gradeName, dataMap.get(gradeName) + 1);
             } else {
                 //第一次进来默认1
                 dataMap.put(gradeName, 1);
             }
+
         }
         List<Map.Entry<String, Integer>> mapList = new ArrayList<>(dataMap.entrySet());
         //排序

+ 7 - 4
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/admin/AdminTradeAnalysisController.java

@@ -54,12 +54,13 @@ public class AdminTradeAnalysisController extends BaseController {
 
     @ApiOperation("交易总览")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "startTime", value = "开始时间", required = true),
             @ApiImplicitParam(name = "endTime", value = "结束时间", required = true),
             @ApiImplicitParam(name = "terminalType", value = "终端类型:Android,IOS,pc,H5,xcx 默认全部不传")
     })
     @GetMapping("tradeOverview")
-    public JsonResult<TradeOverviewVO> tradeOverview(HttpServletRequest request, Date startTime, Date endTime, String terminalType) {
+    public JsonResult<TradeOverviewVO> tradeOverview(HttpServletRequest request,String webSite, Date startTime, Date endTime, String terminalType) {
         StatsTimeType timeType = StatsTimeType.checkTimeType(startTime, endTime, false);
         //上期开始时间和结束时间
         Date preStartTime;
@@ -92,13 +93,13 @@ public class AdminTradeAnalysisController extends BaseController {
             }
         } else {
             //终端类型为空,查询平台数据
-            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, startTime, endTime);
+            List<? extends PlatformBase> list = statsModelUtil.getPlatformList(timeType, webSite, startTime, endTime);
             if (!CollectionUtils.isEmpty(list)) {
                 PlatformBase platformBase = list.get(0);
                 //上期数据
                 PlatformBase previousData = null;
                 if (preStartTime != null) {
-                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, preStartTime, preEndTime);
+                    List<? extends PlatformBase> previousList = statsModelUtil.getPlatformList(timeType, webSite, preStartTime, preEndTime);
                     if (!CollectionUtils.isEmpty(previousList)) {
                         previousData = previousList.get(0);
                     }
@@ -113,10 +114,11 @@ public class AdminTradeAnalysisController extends BaseController {
 
     @ApiOperation("近30天变化趋势(与流量分析共用)")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点"),
             @ApiImplicitParam(name = "terminalTypes", value = "终端类型:android,ios,pc,h5,xcx 默认全部")
     })
     @GetMapping("changeTrend")
-    public JsonResult<List<ChangeTrendVO>> changeTrend(HttpServletRequest request, String terminalTypes) {
+    public JsonResult<List<ChangeTrendVO>> changeTrend(HttpServletRequest request, String webSite, String terminalTypes) {
         //获取当前时间30天之前的时间
         Calendar calendar = Calendar.getInstance();
         calendar.add(Calendar.DATE, -30);
@@ -127,6 +129,7 @@ public class AdminTradeAnalysisController extends BaseController {
             PlatformDayExample example = new PlatformDayExample();
             example.setStatsTimeAfter(startTime);
             example.setOrderBy("stats_time ASC");
+            example.setWebSite(webSite);
             List<PlatformDay> list = platformDayModel.getPlatformDayList(example, null);
             if (!CollectionUtils.isEmpty(list)) {
                 list.forEach(platformDay -> {

+ 2 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/statistics/front/FrontMemberBehaviorController.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON;
 import com.slodon.b2b2c.core.response.JsonResult;
 import com.slodon.b2b2c.core.response.SldResponse;
 import com.slodon.b2b2c.core.util.StringUtil;
+import com.slodon.b2b2c.core.util.WebUtil;
 import com.slodon.b2b2c.enums.ProvinceJson;
 import com.slodon.b2b2c.enums.StatsConstant;
 import com.slodon.b2b2c.statistics.pojo.MemberBehavior;
@@ -38,6 +39,7 @@ public class FrontMemberBehaviorController {
         //解码
         String json = Base64.decodeStr(u);
         MemberBehavior memberBehavior = JSON.parseObject(json, MemberBehavior.class);
+        memberBehavior.setWebSite(WebUtil.getWebSite(request));
         if (memberBehavior == null) {
             return SldResponse.success();
         }

+ 16 - 10
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/system/admin/AdminNavigationController.java

@@ -34,17 +34,19 @@ public class AdminNavigationController extends BaseController {
 
     @ApiOperation("导航列表")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点", paramType = "query"),
             @ApiImplicitParam(name = "navName", value = "导航名称", paramType = "query"),
             @ApiImplicitParam(name = "pageSize", value = "分页大小", defaultValue = "20", paramType = "query"),
             @ApiImplicitParam(name = "current", value = "当前页面位置", defaultValue = "1", paramType = "query")
     })
     @GetMapping("list")
-    public JsonResult<PageVO<Navigation>> list(HttpServletRequest request, String navName) {
+    public JsonResult<PageVO<Navigation>> list(HttpServletRequest request, String webSite, String navName) {
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         NavigationExample example = new NavigationExample();
-        if(!StringUtil.isEmpty(navName)){
-            if(navName.contains("&amp;")){
-                navName = navName.replace("&amp;","&");
+        example.setWebSite(webSite);
+        if (!StringUtil.isEmpty(navName)) {
+            if (navName.contains("&amp;")) {
+                navName = navName.replace("&amp;", "&");
             }
         }
         example.setNavNameLike(navName);
@@ -54,6 +56,7 @@ public class AdminNavigationController extends BaseController {
 
     @ApiOperation("添加导航")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点", paramType = "query"),
             @ApiImplicitParam(name = "navName", value = "导航名称", required = true),
             @ApiImplicitParam(name = "sort", value = "排序", required = true),
             @ApiImplicitParam(name = "isShow", value = "是否显示,0:否;1:是"),
@@ -61,10 +64,11 @@ public class AdminNavigationController extends BaseController {
     })
     @OperationLogger(option = "添加导航")
     @PostMapping("add")
-    public JsonResult addNavigation(HttpServletRequest request, String navName, Integer sort, Integer isShow, String data) {
+    public JsonResult addNavigation(HttpServletRequest request, String webSite, String navName, Integer sort, Integer isShow, String data) {
         Navigation navigation = new Navigation();
-        if(navName.contains("&amp;")){
-            navName = navName.replace("&amp;","&");
+        navigation.setWebSite(webSite);
+        if (navName.contains("&amp;")) {
+            navName = navName.replace("&amp;", "&");
         }
         navigation.setNavName(navName);
         navigation.setSort(sort);
@@ -76,6 +80,7 @@ public class AdminNavigationController extends BaseController {
 
     @ApiOperation("修改导航")
     @ApiImplicitParams({
+            @ApiImplicitParam(name = "webSite", value = "站点", paramType = "query"),
             @ApiImplicitParam(name = "navId", value = "导航id", required = true),
             @ApiImplicitParam(name = "navName", value = "导航名称", required = true),
             @ApiImplicitParam(name = "sort", value = "排序", required = true),
@@ -84,11 +89,12 @@ public class AdminNavigationController extends BaseController {
     })
     @OperationLogger(option = "修改导航")
     @PostMapping("update")
-    public JsonResult updateNavigation(HttpServletRequest request, Integer navId, String navName, Integer sort, Integer isShow, String data) {
+    public JsonResult updateNavigation(HttpServletRequest request, String webSite, Integer navId, String navName, Integer sort, Integer isShow, String data) {
         Navigation navigation = new Navigation();
         navigation.setNavId(navId);
-        if(navName.contains("&amp;")){
-            navName = navName.replace("&amp;","&");
+        navigation.setWebSite(webSite);
+        if (navName.contains("&amp;")) {
+            navName = navName.replace("&amp;", "&");
         }
         navigation.setNavName(navName);
         navigation.setSort(sort);

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio