zhb пре 1 месец
родитељ
комит
3346691746
5 измењених фајлова са 1271 додато и 1105 уклоњено
  1. 3 3
      pages/common/chat.vue
  2. 6 6
      pages/common/download.vue
  3. 63 4
      pages/login/index.vue
  4. 1011 959
      pages/login/regist.vue
  5. 188 133
      pages/login/reset.vue

+ 3 - 3
pages/common/chat.vue

@@ -1,12 +1,12 @@
 <template>
-  <cwg-page-wrapper class="webview-page" type="chat">
+  <view class="webview-page" type="chat">
     <view class="page-container">
       <!-- WebView 内容区(自动占满剩余空间,不遮挡导航栏) -->
       <view class="web-view-container">
         <web-view :src="fileUrl" class="web-view" :webview-styles="webviewStyles" />
       </view>
     </view>
-  </cwg-page-wrapper>
+  </view>
 </template>
 
 <script setup>
@@ -27,7 +27,7 @@ const webviewStyles = computed(() => ({
   },
   bounce: 'none',
   scrollIndicator: 'none',
-  top: statusBarHeight.value + 55 + 'px',
+  top: statusBarHeight.value + 'px',
   bottom: '0px'
 }))
 </script>

+ 6 - 6
pages/common/download.vue

@@ -75,11 +75,11 @@
                                 <view class="qr-codes">
                                     <view class="qr-item">
                                         <view class="qr-label">Google Play</view>
-                                        <QrCode :text="mt41" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt41" :key="mt41" :text="mt41" :logoImage="logoImage"></QrCode>
                                     </view>
                                     <view class="qr-item">
                                         <view class="qr-label">MetaTrader .Apk</view>
-                                        <QrCode :text="mt42" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt42" :key="mt42" :text="mt42" :logoImage="logoImage"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -95,7 +95,7 @@
                                 <view class="qr-codes qr-codes-single">
                                     <view class="qr-item">
                                         <view class="qr-label">App Store</view>
-                                        <QrCode :text="mt43" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt43" :key="mt43" :text="mt43" :logoImage="logoImage"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -173,11 +173,11 @@
                                 <view class="qr-codes">
                                     <view class="qr-item">
                                         <view class="qr-label">Google Play</view>
-                                        <QrCode :text="mt51" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt51" :key="mt51" :text="mt51" :logoImage="logoImage"></QrCode>
                                     </view>
                                     <view class="qr-item">
                                         <view class="qr-label">MetaTrader .Apk</view>
-                                        <QrCode :text="mt52" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt52" :key="mt52" :text="mt52" :logoImage="logoImage"></QrCode>
                                     </view>
                                 </view>
                             </view>
@@ -193,7 +193,7 @@
                                 <view class="qr-codes qr-codes-single">
                                     <view class="qr-item">
                                         <view class="qr-label">App Store</view>
-                                        <QrCode :text="mt53" :logoImage="logoImage"></QrCode>
+                                        <QrCode v-if="mt53" :key="mt53" :text="mt53" :logoImage="logoImage"></QrCode>
                                     </view>
                                 </view>
                             </view>

+ 63 - 4
pages/login/index.vue

@@ -12,7 +12,10 @@ import useRouter from '@/hooks/useRouter'
 import { useI18n } from 'vue-i18n'
 import companyLogo from '@/static/images/logo4.png'
 import LoginHeaderGroup from './components/LoginHeaderGroup.vue'
-
+import LiveChatService from '@/utils/liveChat.js'
+import { useWindowWidth } from '@/composables/useWindowWidth'
+const windowWidth = useWindowWidth(300)
+const isMobile = computed(() => windowWidth.value <= 991)
 const router = useRouter()
 const { t } = useI18n()
 const userStore = useUserStore()
@@ -102,7 +105,7 @@ async function getCustomLoginInfo() {
         case 'follow':
           router.reLaunch('/pages/follow/index')
           break;
-      
+
         default:
           break;
       }
@@ -171,12 +174,31 @@ onMounted(() => {
   }
 })
 const inputType = ref('password')
+const isChatIconExpanded = ref(false)
+// 处理聊天图标点击
+const handleChatIconClick = () => {
+  // 如果还没显示 → 先滑出来
+  if (!isChatIconExpanded.value) {
+    isChatIconExpanded.value = true
+    return
+  }
+  if (isMobile.value) {
+    router.push('/pages/common/chat')
+  } else {
+    if (LiveChatService) {
+      LiveChatService.showChat();
+    }
+  }
+  setTimeout(() => {
+    isChatIconExpanded.value = false
+  }, 300)
+}
 </script>
 
 <template>
   <view class="login-page" :isHeaderFixed="true" :isLoginPage="true">
 
-    <view class="fixed"/>
+    <view class="fixed" />
     <view class="main-content">
       <cwg-match-media :min-width="991">
         <view class="global-header-bar pc-header">
@@ -190,7 +212,7 @@ const inputType = ref('password')
       <!-- 移动端顶部栏:悬浮在上方,深色文字 -->
       <cwg-match-media :max-width="991">
         <view class="mobile-header-bar">
-<!--          <view class="fixed"/>-->
+          <!--          <view class="fixed"/>-->
 
           <LoginHeaderGroup text-color="#141d22" icon-color="#141d22" />
         </view>
@@ -303,6 +325,10 @@ const inputType = ref('password')
         </uni-col>
       </uni-row>
     </view>
+    <view class="chat-icon" :class="{ 'chat-icon-expanded': isChatIconExpanded, 'chat-icon-hidden': type == 'chat' }"
+      @click="handleChatIconClick">
+      <cwg-icon name="chat" color="#fff" />
+    </view>
   </view>
 </template>
 
@@ -322,6 +348,39 @@ const inputType = ref('password')
   flex-direction: column;
 }
 
+.chat-icon {
+  width: px2rpx(50);
+  height: px2rpx(50);
+  border-radius: 50%;
+  background-color: #cf1322;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: fixed;
+  bottom: px2rpx(25);
+  right: px2rpx(-25);
+  z-index: 999;
+  cursor: pointer;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 0 px2rpx(8) px2rpx(20) rgba(0, 0, 0, 0.15);
+  will-change: transform;
+}
+
+.chat-icon:hover {
+  transform: scale(1.1);
+}
+
+.chat-icon-expanded {
+  bottom: px2rpx(20);
+  right: px2rpx(20);
+  transform: scale(1.1);
+  box-shadow: 0 px2rpx(12) px2rpx(30) rgba(0, 0, 0, 0.2);
+}
+
+.chat-icon-hidden {
+  display: none;
+}
+
 .fixed {
   width: 100%;
   height: var(--status-bar-height);

+ 1011 - 959
pages/login/regist.vue

@@ -1,6 +1,6 @@
 <template>
   <view class="regist-page" :isHeaderFixed="true" :isLoginPage="true">
-    <view class="fixed"/>
+    <view class="fixed" />
     <view class="main-content">
       <!-- 全局顶部栏:占据一整行,带有占位和背景 -->
       <cwg-match-media :min-width="991">
@@ -21,1108 +21,1160 @@
       </cwg-match-media>
 
       <uni-row class="demo-uni-row">
-      <cwg-match-media :min-width="991">
-        <uni-col :xs="24" :sm="24" :md="12" :lg="14" :xl="16">
-          <view class="left-bg">
-            <view class="left-box">
-              <view class="inner">
-                <view class="section-title">
-                  <text class="bg-secondary-opacity subtitle w-40" v-t="'newLoop.item11'"></text>
-                </view>
-                <view class="title w-700">
-                  <text v-t="'newLoop.item12'"></text>
-                  <text>&nbsp;</text>
-                  <text class="color-white" v-t="'newLoop.item13'"></text>
+        <cwg-match-media :min-width="991">
+          <uni-col :xs="24" :sm="24" :md="12" :lg="14" :xl="16">
+            <view class="left-bg">
+              <view class="left-box">
+                <view class="inner">
+                  <view class="section-title">
+                    <text class="bg-secondary-opacity subtitle w-40" v-t="'newLoop.item11'"></text>
+                  </view>
+                  <view class="title w-700">
+                    <text v-t="'newLoop.item12'"></text>
+                    <text>&nbsp;</text>
+                    <text class="color-white" v-t="'newLoop.item13'"></text>
+                  </view>
+                  <view class="text-white" v-t="'newLoop.item14'"></view>
                 </view>
-                <view class="text-white" v-t="'newLoop.item14'"></view>
-              </view>
-              <image src="/static/images/trust-pilot.png" class="img-fluid mt--10" mode="widthFix"></image>
-              <view class="left-content">
-                <view class="des text-white">
-                  <text v-html="t('newSignin.item12')"></text>
-                  <br />
-                  <text v-html="t('newSignin.item12_1')"></text>
-                  <br />
-                  <text v-html="t('newSignin.item10')"></text>
-                  <br />
-                  <text v-html="t('newSignin.item11')"></text>
-                  <br />
-                  <text v-t="'newSignin.item13'"></text>
-                  <cwg-link type="pdf" :title="'newSignin.item13_1'"
-                    :url="`pdf/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`"
-                    target="_blank"
-                    v-t="'newSignin.item13_1'"
-                    class="doc-link"
-                  />
-                  <text v-t="'newSignin.item13_2'"></text>
-                  <!-- <view v-t="'newSignin.item13_3'"></view>
+                <image src="/static/images/trust-pilot.png" class="img-fluid mt--10" mode="widthFix"></image>
+                <view class="left-content">
+                  <view class="des text-white">
+                    <text v-html="t('newSignin.item12')"></text>
+                    <br />
+                    <text v-html="t('newSignin.item12_1')"></text>
+                    <br />
+                    <text v-html="t('newSignin.item10')"></text>
+                    <br />
+                    <text v-html="t('newSignin.item11')"></text>
+                    <br />
+                    <text v-t="'newSignin.item13'"></text>
+                    <cwg-link type="pdf" :title="'newSignin.item13_1'"
+                      :url="`pdf/Risk-Disclosures-and-Acknowledgements-2020-08.pdf`" target="_blank"
+                      v-t="'newSignin.item13_1'" class="doc-link" />
+                    <text v-t="'newSignin.item13_2'"></text>
+                    <!-- <view v-t="'newSignin.item13_3'"></view>
                   <text v-t="'newSignin.item13_4'"></text> -->
+                  </view>
                 </view>
               </view>
             </view>
-          </view>
-        </uni-col>
-      </cwg-match-media>
-      <uni-col :xs="24" :sm="24" :md="12" :lg="10" :xl="8" class="right-f">
-        <view class="account">
-          <cwg-match-media :max-width="991">
-            <view class="company u-flex-y u-flex-y-center">
-              <image src="/static/images/logo-full.svg" class="company-icon" mode="widthFix"></image>
+          </uni-col>
+        </cwg-match-media>
+        <uni-col :xs="24" :sm="24" :md="12" :lg="10" :xl="8" class="right-f">
+          <view class="account">
+            <cwg-match-media :max-width="991">
+              <view class="company u-flex-y u-flex-y-center">
+                <image src="/static/images/logo-full.svg" class="company-icon" mode="widthFix"></image>
+              </view>
+            </cwg-match-media>
+            <view class="title">
+              <view class="tit1">{{ t('newSignup.item1') }}</view>
+              <view class="tit2">{{ t('newSignup.item2') }}</view>
             </view>
-          </cwg-match-media>
-          <view class="title">
-            <view class="tit1">{{ t('newSignup.item1') }}</view>
-            <view class="tit2">{{ t('newSignup.item2') }}</view>
-          </view>
-          <view>
-            <uni-forms ref="form" :modelValue="formData" :rules="rules" validate-trigger="blur" label-position="top"
-                       label-width="120">
-              <uni-row :gutter="20" class="formContent">
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item name="country" :label="t('newSignup.item3')">
-                    <cwg-combox v-model:value="formData.country" :options="countryOptions" filterable>
-                    </cwg-combox>
-                  </uni-forms-item>
-                </uni-col>
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item name="phone" :label="t('newSignup.item5')">
-                    <uni-easyinput v-model="formData.phone"></uni-easyinput>
-                  </uni-forms-item>
-                </uni-col>
-                <uni-col :xs="24" :md="24">
-                  <cwg-match-media :max-width="991">
-                    <uni-forms-item name="birthDate" :label="t('newSignup.item18')">
-                      <uni-datetime-picker type="date" v-model="formData.birthDate"
-                                           :placeholder="t('newSignup.item19')" @change="checkAge" />
+            <view>
+              <uni-forms ref="form" :modelValue="formData" :rules="rules" validate-trigger="blur" label-position="top"
+                label-width="120">
+                <uni-row :gutter="20" class="formContent">
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item name="country" :label="t('newSignup.item3')">
+                      <cwg-combox v-model:value="formData.country" :options="countryOptions" filterable>
+                      </cwg-combox>
+                    </uni-forms-item>
+                  </uni-col>
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item name="phone" :label="t('newSignup.item5')">
+                      <uni-easyinput v-model="formData.phone"></uni-easyinput>
                     </uni-forms-item>
-                  </cwg-match-media>
-                  <cwg-match-media :min-width="992">
-                    <uni-forms-item name="birthDate" :label="t('newSignup.item18')">
-                      <uni-datetime-picker style="width: 50%;" type="date" v-model="formData.birthDate"
-                                           :placeholder="t('newSignup.item19')" @change="checkAge" />
+                  </uni-col>
+                  <uni-col :xs="24" :md="24">
+                    <cwg-match-media :max-width="991">
+                      <uni-forms-item name="birthDate" :label="t('newSignup.item18')">
+                        <uni-datetime-picker type="date" v-model="formData.birthDate"
+                          :placeholder="t('newSignup.item19')" @change="checkAge" />
+                      </uni-forms-item>
+                    </cwg-match-media>
+                    <cwg-match-media :min-width="992">
+                      <uni-forms-item name="birthDate" :label="t('newSignup.item18')">
+                        <uni-datetime-picker style="width: 50%;" type="date" v-model="formData.birthDate"
+                          :placeholder="t('newSignup.item19')" @change="checkAge" />
+                      </uni-forms-item>
+                    </cwg-match-media>
+                  </uni-col>
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item name="email" :label="t('newSignup.item7')">
+                      <uni-easyinput v-model="formData.email" :placeholder="t('newSignup.item8')"
+                        :disabled="!isAgeValid || !formData.birthDate"></uni-easyinput>
                     </uni-forms-item>
-                  </cwg-match-media>
-                </uni-col>
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item name="email" :label="t('newSignup.item7')">
-                    <uni-easyinput v-model="formData.email"
-                                   :placeholder="t('newSignup.item8')"
-                                   :disabled="!isAgeValid || !formData.birthDate"></uni-easyinput>
-                  </uni-forms-item>
-                </uni-col>
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item name="emailCode" :label="t('newSignup.item9')">
-                    <view style="display: flex; gap: 8px;">
-                      <view style="flex: 1;">
-                        <uni-easyinput :disabled="!isAgeValid || !formData.birthDate"
-                                       v-model="formData.emailCode" :placeholder="t('newSignup.item10')">
-                        </uni-easyinput>
-                      </view>
-                      <view class="btn-code" @click="(!isAgeValid || !formData.birthDate) ? '' : handleGetCode()">
-                        {{ getCodeString }}
+                  </uni-col>
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item name="emailCode" :label="t('newSignup.item9')">
+                      <view style="display: flex; gap: 8px;">
+                        <view style="flex: 1;">
+                          <uni-easyinput :disabled="!isAgeValid || !formData.birthDate" v-model="formData.emailCode"
+                            :placeholder="t('newSignup.item10')">
+                          </uni-easyinput>
+                        </view>
+                        <view class="btn-code" @click="(!isAgeValid || !formData.birthDate) ? '' : handleGetCode()">
+                          {{ getCodeString }}
+                        </view>
                       </view>
-                    </view>
-                  </uni-forms-item>
-                </uni-col>
-                <uni-col :xs="24" :md="24">
-                  <view class="agreemnet9">*{{ t('signup.agreemnet9') }}</view>
-                </uni-col>
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item name="password" :label="t('newSignup.item12')">
-                    <uni-easyinput v-model.trim="formData.password"
-                                   :disabled="!isAgeValid || !formData.birthDate"
-                                   :placeholder="t('newSignup.item13')" type="password"></uni-easyinput>
-                  </uni-forms-item>
+                    </uni-forms-item>
+                  </uni-col>
                   <uni-col :xs="24" :md="24">
-                    <uni-forms-item>
-                      <ul class="pwd">
-                        <li :class="{ fit: rule1 }" v-t="'signup.form.rules.1st'"></li>
-                        <li :class="{ fit: rule2 }" v-t="'signup.form.rules.2nd'"></li>
-                        <li :class="{ fit: rule3 }" v-t="'signup.form.rules.3rd'"></li>
-                      </ul>
+                    <view class="agreemnet9">*{{ t('signup.agreemnet9') }}</view>
+                  </uni-col>
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item name="password" :label="t('newSignup.item12')">
+                      <uni-easyinput v-model.trim="formData.password" :disabled="!isAgeValid || !formData.birthDate"
+                        :placeholder="t('newSignup.item13')" type="password"></uni-easyinput>
+                    </uni-forms-item>
+                    <uni-col :xs="24" :md="24">
+                      <uni-forms-item>
+                        <ul class="pwd">
+                          <li :class="{ fit: rule1 }" v-t="'signup.form.rules.1st'"></li>
+                          <li :class="{ fit: rule2 }" v-t="'signup.form.rules.2nd'"></li>
+                          <li :class="{ fit: rule3 }" v-t="'signup.form.rules.3rd'"></li>
+                        </ul>
+                      </uni-forms-item>
+                    </uni-col>
+                  </uni-col>
+                  <uni-col :xs="24" :md="12">
+                    <uni-forms-item v-if="!isRouteHasId" name="linkValue" :label="t('newSignup.item14')">
+                      <uni-easyinput v-model.trim="formData.linkValue" :disabled="!isAgeValid || !formData.birthDate"
+                        :placeholder="t('newSignup.item15')" @input="limitAgentIdLength"></uni-easyinput>
                     </uni-forms-item>
                   </uni-col>
-                </uni-col>
-                <uni-col :xs="24" :md="12">
-                  <uni-forms-item v-if="!isRouteHasId" name="linkValue" :label="t('newSignup.item14')">
-                    <uni-easyinput v-model.trim="formData.linkValue"
-                                   :disabled="!isAgeValid || !formData.birthDate"
-                                   :placeholder="t('newSignup.item15')"
-                                   @input="limitAgentIdLength"></uni-easyinput>
-                  </uni-forms-item>
-                </uni-col>
-
-              </uni-row>
-              <uni-forms-item name="agree">
-                <view class="check-box" @click="toggleAgree">
-                  <up-checkbox-group v-model="agreeGroup" @change="onAgreeChange">
-                    <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a"
-                                 name="agree"
-                                 class="wcg-checkbox"></up-checkbox>
-                  </up-checkbox-group>
-                  <text class="checkbox-label">{{ t('signup.agree') }}</text>
-                </view>
-              </uni-forms-item>
-              <uni-forms-item name="isSubscribeEmail">
-                <view class="check-box" @click="toggleSubscribeEmail">
-                  <up-checkbox-group v-model="subscribeEmailGroup" @change="onSubscribeEmailChange">
-                    <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a"
-                                 name="subscribeEmail"
-                                 class="wcg-checkbox"></up-checkbox>
-                  </up-checkbox-group>
-                  <text class="checkbox-label">{{ t('signup.agree1') }}</text>
-                </view>
-              </uni-forms-item>
-            </uni-forms>
-          </view>
-          <view>
-            <u-button class="regiset-btn" @click="register">
-              {{ t('signup.button') }}
-            </u-button>
 
+                </uni-row>
+                <uni-forms-item name="agree">
+                  <view class="check-box" @click="toggleAgree">
+                    <up-checkbox-group v-model="agreeGroup" @change="onAgreeChange">
+                      <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a" name="agree"
+                        class="wcg-checkbox"></up-checkbox>
+                    </up-checkbox-group>
+                    <text class="checkbox-label">{{ t('signup.agree') }}</text>
+                  </view>
+                </uni-forms-item>
+                <uni-forms-item name="isSubscribeEmail">
+                  <view class="check-box" @click="toggleSubscribeEmail">
+                    <up-checkbox-group v-model="subscribeEmailGroup" @change="onSubscribeEmailChange">
+                      <up-checkbox size="14" labelSize="14" labelColor="#666666" activeColor="#ea002a"
+                        name="subscribeEmail" class="wcg-checkbox"></up-checkbox>
+                    </up-checkbox-group>
+                    <text class="checkbox-label">{{ t('signup.agree1') }}</text>
+                  </view>
+                </uni-forms-item>
+              </uni-forms>
+            </view>
+            <view>
+              <u-button class="regiset-btn" @click="register">
+                {{ t('signup.button') }}
+              </u-button>
+
+            </view>
+            <view class="login-link">
+              <text>{{ t('newSignup.item16') }}</text>
+              <navigator url="/pages/login/index" class="link" hover-class="none">{{ t('newSignup.item17') }}
+              </navigator>
+            </view>
+            <view class="des-bottom">
+              <text v-t="'signup.agreemnet1'"></text>
+              <a @click="openUrl('pdf/Client_Agreement.pdf')" target="_blank" v-t="'signup.agreemnet2'"></a>
+              <text v-t="'signup.agreemnet3'"></text>
+              <a @click="openUrl('pdf/Terms&Conditions.pdf')" target="_blank" v-t="'signup.agreemnet4'"></a>
+              <text v-t="'signup.agreemnet5'"></text>
+              <a @click="openUrl('pdf/Privacy_Policy.pdf')" target="_blank" v-t="'signup.agreemnet6'"></a>
+              <text v-t="'signup.agreemnet7'"></text>
+            </view>
           </view>
-          <view class="login-link">
-            <text>{{t('newSignup.item16')}}</text>
-            <navigator url="/pages/login/index" class="link" hover-class="none">{{ t('newSignup.item17') }}
-            </navigator>
-          </view>
-          <view class="des-bottom">
-            <text v-t="'signup.agreemnet1'"></text>
-            <a @click="openUrl('pdf/Client_Agreement.pdf')" target="_blank" v-t="'signup.agreemnet2'"></a>
-            <text v-t="'signup.agreemnet3'"></text>
-            <a @click="openUrl('pdf/Terms&Conditions.pdf')" target="_blank" v-t="'signup.agreemnet4'"></a>
-            <text v-t="'signup.agreemnet5'"></text>
-            <a @click="openUrl('pdf/Privacy_Policy.pdf')" target="_blank" v-t="'signup.agreemnet6'"></a>
-            <text v-t="'signup.agreemnet7'"></text>
-          </view>
-        </view>
-      </uni-col>
-    </uni-row>
-  </view>
+        </uni-col>
+      </uni-row>
+    </view>
+    <view class="chat-icon" :class="{ 'chat-icon-expanded': isChatIconExpanded, 'chat-icon-hidden': type == 'chat' }"
+      @click="handleChatIconClick">
+      <cwg-icon name="chat" color="#fff" />
+    </view>
   </view>
 </template>
 <script setup>
-  import { ref, watch, onMounted, computed } from 'vue'
-  import { useI18n } from 'vue-i18n'
-  import { useEmailCountdown } from '@/hooks/useEmailCountdown'
-  import { loginApi } from '@/api/login'
-  import { countryApi } from '@/api/country'
-  import Config from '@/config/index'
-  import { showToast } from '@/utils/toast'
-  import { onLoad } from '@dcloudio/uni-app'
-  import useUserStore from '@/stores/use-user-store'
-  import { userToken } from '@/composables/config'
-  import { userApi } from '@/api/user'
-  import { openLocalPdf } from '@/utils/pdf.js'
-  import ImportModel from './components/ImportModel.vue'
-  import logoImage from '@/static/images/logo3.png'
-  import QrCode from '@/components/QrCode.vue'
-  import LoginHeaderGroup from './components/LoginHeaderGroup.vue'
-
-  const { t } = useI18n()
-  const { Code } = Config
-  const userStore = useUserStore()
-
-  const {
-    time,
-    text: getCodeString,
-    canSend,
-    start,
-    restore,
-  } = useEmailCountdown()
-  const status = ref(false)
-
-  const isRouteHasId = ref(false)
-  const formData = ref({
-    country: 'CN',
-    phone: '',
-    birthDate: '',
-    email: '',
-    code: '',
-    password: '',
-    linkValue: '',
-    agree: 0,
-    isSubscribeEmail: 0,
-    sourceCode: null,
-    w: '',
-    subId: '',
-    oc: '',
-    agentId: null,
-    ibInvalid: null,
-  })
-
-  const rules = {
-    country: { rules: [{ required: true, errorMessage: t('vaildate.country.empty'), trigger: 'blur' }] },
-    email: {
-      rules: [
-        { required: true, errorMessage: t('vaildate.email.empty'), trigger: 'blur' },
-        { pattern: Config.Pattern.Email, errorMessage: t('vaildate.email.format'), trigger: 'blur' },
-      ],
-    },
-    emailCode: { rules: [{ required: true, errorMessage: t('vaildate.code.empty'), trigger: 'blur' }] },
-    password: {
-      rules: [
-        { required: true, errorMessage: t('vaildate.password.format'), trigger: 'blur' },
-        { pattern: Config.Pattern.Password, errorMessage: t('vaildate.password.format'), trigger: 'blur' },
-      ],
-    },
-    agree: {
-      rules: [
-        {
-          validateFunction: (rule, value) => {
-            if (value) return true
-            return t('vaildate.agree.empty')
-          },
-          trigger: 'change',
+import { ref, watch, onMounted, computed } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useEmailCountdown } from '@/hooks/useEmailCountdown'
+import { loginApi } from '@/api/login'
+import { countryApi } from '@/api/country'
+import Config from '@/config/index'
+import { showToast } from '@/utils/toast'
+import { onLoad } from '@dcloudio/uni-app'
+import useUserStore from '@/stores/use-user-store'
+import { userToken } from '@/composables/config'
+import { userApi } from '@/api/user'
+import { openLocalPdf } from '@/utils/pdf.js'
+import ImportModel from './components/ImportModel.vue'
+import logoImage from '@/static/images/logo3.png'
+import QrCode from '@/components/QrCode.vue'
+import LoginHeaderGroup from './components/LoginHeaderGroup.vue'
+import { useWindowWidth } from '@/composables/useWindowWidth'
+const windowWidth = useWindowWidth(300)
+const isMobile = computed(() => windowWidth.value <= 991)
+const { t } = useI18n()
+const { Code } = Config
+const userStore = useUserStore()
+import LiveChatService from '@/utils/liveChat.js'
+const {
+  time,
+  text: getCodeString,
+  canSend,
+  start,
+  restore,
+} = useEmailCountdown()
+const status = ref(false)
+
+const isRouteHasId = ref(false)
+const formData = ref({
+  country: 'CN',
+  phone: '',
+  birthDate: '',
+  email: '',
+  code: '',
+  password: '',
+  linkValue: '',
+  agree: 0,
+  isSubscribeEmail: 0,
+  sourceCode: null,
+  w: '',
+  subId: '',
+  oc: '',
+  agentId: null,
+  ibInvalid: null,
+})
+
+const rules = {
+  country: { rules: [{ required: true, errorMessage: t('vaildate.country.empty'), trigger: 'blur' }] },
+  email: {
+    rules: [
+      { required: true, errorMessage: t('vaildate.email.empty'), trigger: 'blur' },
+      { pattern: Config.Pattern.Email, errorMessage: t('vaildate.email.format'), trigger: 'blur' },
+    ],
+  },
+  emailCode: { rules: [{ required: true, errorMessage: t('vaildate.code.empty'), trigger: 'blur' }] },
+  password: {
+    rules: [
+      { required: true, errorMessage: t('vaildate.password.format'), trigger: 'blur' },
+      { pattern: Config.Pattern.Password, errorMessage: t('vaildate.password.format'), trigger: 'blur' },
+    ],
+  },
+  agree: {
+    rules: [
+      {
+        validateFunction: (rule, value) => {
+          if (value) return true
+          return t('vaildate.agree.empty')
         },
-      ],
-    },
-    phone: {
-      rules: [
-        { required: true, errorMessage: t('vaildate.phone.format'), trigger: 'blur' },
-        { pattern: Config.Pattern.NonNegInt, errorMessage: t('vaildate.phone.format'), trigger: 'blur' },
-      ],
-    },
-    birthDate: { rules: [{ required: true, errorMessage: t('vaildate.birthDate.empty'), trigger: 'change' }] },
+        trigger: 'change',
+      },
+    ],
+  },
+  phone: {
+    rules: [
+      { required: true, errorMessage: t('vaildate.phone.format'), trigger: 'blur' },
+      { pattern: Config.Pattern.NonNegInt, errorMessage: t('vaildate.phone.format'), trigger: 'blur' },
+    ],
+  },
+  birthDate: { rules: [{ required: true, errorMessage: t('vaildate.birthDate.empty'), trigger: 'change' }] },
+}
+
+const agreeGroup = ref([])
+const subscribeEmailGroup = ref([])
+
+watch(() => formData.value.agree, (val) => {
+  agreeGroup.value = val === 1 ? ['agree'] : []
+}, { immediate: true })
+
+watch(() => formData.value.isSubscribeEmail, (val) => {
+  subscribeEmailGroup.value = val === 1 ? ['subscribeEmail'] : []
+}, { immediate: true })
+
+const onAgreeChange = (e) => {
+  formData.value.agree = e && e.length ? 1 : 0
+}
+
+const onSubscribeEmailChange = (e) => {
+  formData.value.isSubscribeEmail = e && e.length ? 1 : 0
+}
+
+const toggleAgree = () => {
+  const next = agreeGroup.value.length ? [] : ['agree']
+  agreeGroup.value = next
+  onAgreeChange(next)
+}
+const isChatIconExpanded = ref(false)
+// 处理聊天图标点击
+const handleChatIconClick = () => {
+  // 如果还没显示 → 先滑出来
+  if (!isChatIconExpanded.value) {
+    isChatIconExpanded.value = true
+    return
   }
-
-  const agreeGroup = ref([])
-  const subscribeEmailGroup = ref([])
-
-  watch(() => formData.value.agree, (val) => {
-    agreeGroup.value = val === 1 ? ['agree'] : []
-  }, { immediate: true })
-
-  watch(() => formData.value.isSubscribeEmail, (val) => {
-    subscribeEmailGroup.value = val === 1 ? ['subscribeEmail'] : []
-  }, { immediate: true })
-
-  const onAgreeChange = (e) => {
-    formData.value.agree = e && e.length ? 1 : 0
+  if (isMobile.value) {
+    router.push('/pages/common/chat')
+  } else {
+    if (LiveChatService) {
+      LiveChatService.showChat();
+    }
   }
-
-  const onSubscribeEmailChange = (e) => {
-    formData.value.isSubscribeEmail = e && e.length ? 1 : 0
+  setTimeout(() => {
+    isChatIconExpanded.value = false
+  }, 300)
+}
+const toggleSubscribeEmail = () => {
+  const next = subscribeEmailGroup.value.length ? [] : ['subscribeEmail']
+  subscribeEmailGroup.value = next
+  onSubscribeEmailChange(next)
+}
+
+const rule1 = computed(() => {
+  if (!formData.value.password) return false
+  return /^.{8,16}$/.test(formData.value.password)
+})
+
+const rule2 = computed(() => {
+  return /^(?=.*?[a-z])(?=.*?[A-Z]).*$/.test(formData.value.password)
+})
+
+const rule3 = computed(() => {
+  return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?!.*([~!@&%$^\(\)#_]).*\1.*\1)[A-Za-z0-9~!@&%$^\(\)#_]{8,16}$/.test(
+    formData.value.password,
+  )
+})
+const openUrl = (url) => {
+  openLocalPdf(url)
+}
+
+// 检查是否满18周岁
+const isAgeValid = computed(() => {
+  if (!formData.value.birthDate) {
+    return false // 如果还没选择日期,不允许继续
   }
-
-  const toggleAgree = () => {
-    const next = agreeGroup.value.length ? [] : ['agree']
-    agreeGroup.value = next
-    onAgreeChange(next)
+  const today = new Date()
+  const birthDate = new Date(formData.value.birthDate)
+  let age = today.getFullYear() - birthDate.getFullYear()
+  const monthDiff = today.getMonth() - birthDate.getMonth()
+  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
+    age--
   }
-
-  const toggleSubscribeEmail = () => {
-    const next = subscribeEmailGroup.value.length ? [] : ['subscribeEmail']
-    subscribeEmailGroup.value = next
-    onSubscribeEmailChange(next)
+  return age >= 18
+})
+
+// 检查年龄并提示
+const checkAge = () => {
+  if (formData.value.birthDate && !isAgeValid.value) {
+    uni.showModal({
+      title: t('Msg.SystemPrompt'),
+      content: t('signup.ageRestriction'),
+      showCancel: false,
+      confirmText: t('Btn.Confirm'),
+      success: function (res) {
+        if (res.confirm) {
+          // 用户点击确认后的操作
+        }
+      },
+    })
   }
-
-  const rule1 = computed(() => {
-    if (!formData.value.password) return false
-    return /^.{8,16}$/.test(formData.value.password)
-  })
-
-  const rule2 = computed(() => {
-    return /^(?=.*?[a-z])(?=.*?[A-Z]).*$/.test(formData.value.password)
-  })
-
-  const rule3 = computed(() => {
-    return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?!.*([~!@&%$^\(\)#_]).*\1.*\1)[A-Za-z0-9~!@&%$^\(\)#_]{8,16}$/.test(
-      formData.value.password,
-    )
-  })
-  const openUrl = (url) => {
-    openLocalPdf(url)
+}
+
+const limitAgentIdLength = (val) => {
+  if (val == null || val === '') return
+  // 推荐码只能输入数字和英文
+  const filtered = val.toString().replace(/[^0-9a-zA-Z]/g, '').slice(0, 10)
+  if (formData.value.linkValue !== filtered) {
+    formData.value.linkValue = filtered
   }
-
-  // 检查是否满18周岁
-  const isAgeValid = computed(() => {
-    if (!formData.value.birthDate) {
-      return false // 如果还没选择日期,不允许继续
-    }
-    const today = new Date()
-    const birthDate = new Date(formData.value.birthDate)
-    let age = today.getFullYear() - birthDate.getFullYear()
-    const monthDiff = today.getMonth() - birthDate.getMonth()
-    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
-      age--
+}
+
+onLoad((options) => {
+  if (options) {
+    formData.value.sourceCode = options.ex || null
+    formData.value.w = options.w || ''
+    formData.value.subId = options.SUBID || ''
+    formData.value.oc = options.oc || ''
+    formData.value.email = options.emailAdvertisement || ''
+
+    console.log(options, '-----')
+
+    if (options.id) {
+      isRouteHasId.value = true
+      formData.value.agentId = Number(options.id)
+      formData.value.linkValue = options.commission || ''
+
+      switch (options.ibInvalid) {
+        case 'B0':
+          formData.value.ibInvalid = 0
+          break
+        case 'B1':
+          formData.value.ibInvalid = 1
+          break
+      }
     }
-    return age >= 18
-  })
-
-  // 检查年龄并提示
-  const checkAge = () => {
-    if (formData.value.birthDate && !isAgeValid.value) {
-      uni.showModal({
-        title: t('Msg.SystemPrompt'),
-        content: t('signup.ageRestriction'),
-        showCancel: false,
-        confirmText: t('Btn.Confirm'),
-        success: function(res) {
-          if (res.confirm) {
-            // 用户点击确认后的操作
-          }
-        },
-      })
+  }
+})
+const ho = ref('')
+
+
+const form = ref(null)
+const value = ref('')
+const mock_options = ref([])
+const countryCode = ref('my')
+const countryOptions = computed(() => {
+  return mock_options.value.map(item => ({
+    text: item.enName,
+    value: item.code,
+    disabled: item.isOpenAccount == 0 || item.isOpenAccount === null ? true : false,
+  }))
+})
+
+// 国家列表
+async function getCountry() {
+  try {
+    let res = await countryApi.Country({})
+    if (res.code == 200) { // Code.StatusOK
+      mock_options.value = res.data
+    } else {
+      showToast(res.msg)
     }
+  } catch (error) {
+    console.error(error)
+  }
+}
+
+//获取当前国家编码
+const getCountryMsg = async () => {
+  let res = await countryApi.CountryGet({})
+  if (res.code == Code.StatusOK) {
+    countryCode.value = res.msg
+  } else {
+    console.log(res)
   }
+}
 
-  const limitAgentIdLength = (val) => {
-    if (val == null || val === '') return
-    // 推荐码只能输入数字和英文
-    const filtered = val.toString().replace(/[^0-9a-zA-Z]/g, '').slice(0, 10)
-    if (formData.value.linkValue !== filtered) {
-      formData.value.linkValue = filtered
-    }
+// 获取验证码按钮点击
+async function handleGetCode() {
+  if (!formData.value.birthDate) {
+    showToast(t('vaildate.birthDate.empty'))
+    return
+  }
+  if (!isAgeValid.value) {
+    showToast(t('signup.ageRestriction'))
+    return
+  }
+  if (!formData.value.country) {
+    showToast(t('vaildate.country.empty'))
+    return
+  }
+  if (!formData.value.email) {
+    showToast(t('vaildate.email.empty'))
+    return
+  }
+  if (!Config.Pattern.Email.test(formData.value.email)) {
+    showToast(t('vaildate.email.format'))
+    return
   }
 
-  onLoad((options) => {
-    if (options) {
-      formData.value.sourceCode = options.ex || null
-      formData.value.w = options.w || ''
-      formData.value.subId = options.SUBID || ''
-      formData.value.oc = options.oc || ''
-      formData.value.email = options.emailAdvertisement || ''
-
-      console.log(options, '-----')
-
-      if (options.id) {
-        isRouteHasId.value = true
-        formData.value.agentId = Number(options.id)
-        formData.value.linkValue = options.commission || ''
-
-        switch (options.ibInvalid) {
-          case 'B0':
-            formData.value.ibInvalid = 0
-            break
-          case 'B1':
-            formData.value.ibInvalid = 1
-            break
-        }
-      }
-    }
-  })
-  const ho = ref('')
-
-
-  const form = ref(null)
-  const value = ref('')
-  const mock_options = ref([])
-  const countryCode = ref('my')
-  const countryOptions = computed(() => {
-    return mock_options.value.map(item => ({
-      text: item.enName,
-      value: item.code,
-      disabled: item.isOpenAccount == 0 || item.isOpenAccount === null ? true : false,
-    }))
-  })
+  if (!canSend.value) return
+  await sendEmailCode()
+}
 
-  // 国家列表
-  async function getCountry() {
-    try {
-      let res = await countryApi.Country({})
-      if (res.code == 200) { // Code.StatusOK
-        mock_options.value = res.data
-      } else {
-        showToast(res.msg)
-      }
-    } catch (error) {
-      console.error(error)
-    }
-  }
 
-  //获取当前国家编码
-  const getCountryMsg = async () => {
-    let res = await countryApi.CountryGet({})
-    if (res.code == Code.StatusOK) {
-      countryCode.value = res.msg
-    } else {
-      console.log(res)
-    }
+// 发送邮箱验证码
+async function sendEmailCode() {
+  const res = await loginApi.Code({
+    ...formData.value,
+  })
+
+  if (res.code === 200) {
+    showToast(t('Msg.CodeSuccess'))
+    start()
+    return true
+  } else {
+    showToast(t('Msg.CodeFail'))
+    return false
   }
+}
 
-  // 获取验证码按钮点击
-  async function handleGetCode() {
-    if (!formData.value.birthDate) {
-      showToast(t('vaildate.birthDate.empty'))
-      return
-    }
-    if (!isAgeValid.value) {
-      showToast(t('signup.ageRestriction'))
-      return
-    }
-    if (!formData.value.country) {
-      showToast(t('vaildate.country.empty'))
-      return
-    }
-    if (!formData.value.email) {
-      showToast(t('vaildate.email.empty'))
-      return
-    }
-    if (!Config.Pattern.Email.test(formData.value.email)) {
-      showToast(t('vaildate.email.format'))
-      return
-    }
+const handleModelConfirm = () => {
+  // 弹窗确认后的处理
+  status.value = false
+}
 
-    if (!canSend.value) return
-    await sendEmailCode()
+const register = async () => {
+  if (countryCode.value == 'MY' || countryCode.value == 'ID') {
+    status.value = true
+    return
   }
+  form.value.validate().then(async (res) => {
+    // 中国(含港澳台)使用 X-System: B,非中国使用 X-System: A
+    const chinaCountryCodes = ['CN']
+    const isChina = chinaCountryCodes.includes(formData.value.country)
+    const xSystemValue = isChina ? 'B' : 'A'
 
 
-  // 发送邮箱验证码
-  async function sendEmailCode() {
-    const res = await loginApi.Code({
-      ...formData.value,
-    })
-
-    if (res.code === 200) {
-      showToast(t('Msg.CodeSuccess'))
-      start()
-      return true
+    let resData = await loginApi.Register(
+      { ...formData.value },
+      { headers: { 'X-System': xSystemValue } },
+    )
+    if (resData.code == 200) { // Code.StatusOK
+      showToast(t('Msg.registerSuc'))
+      login()
     } else {
-      showToast(t('Msg.CodeFail'))
-      return false
+      showToast(resData.msg)
     }
-  }
-
-  const handleModelConfirm = () => {
-    // 弹窗确认后的处理
-    status.value = false
-  }
 
-  const register = async () => {
-    if (countryCode.value == 'MY' || countryCode.value == 'ID') {
-      status.value = true
-      return
-    }
-    form.value.validate().then(async (res) => {
-      // 中国(含港澳台)使用 X-System: B,非中国使用 X-System: A
-      const chinaCountryCodes = ['CN']
-      const isChina = chinaCountryCodes.includes(formData.value.country)
-      const xSystemValue = isChina ? 'B' : 'A'
-
-
-      let resData = await loginApi.Register(
-        { ...formData.value },
-        { headers: { 'X-System': xSystemValue } },
-      )
-      if (resData.code == 200) { // Code.StatusOK
-        showToast(t('Msg.registerSuc'))
-        login()
-      } else {
-        showToast(resData.msg)
-      }
+  }).catch(err => {
+    console.log('表单错误信息:', err)
+    showToast(err.msg)
+    return false
+  })
+}
 
-    }).catch(err => {
-      console.log('表单错误信息:', err)
-      showToast(err.msg)
-      return false
+const login = async () => {
+  try {
+    let res = await userApi.login({
+      loginName: formData.value.email,
+      password: formData.value.password,
     })
-  }
-
-  const login = async () => {
-    try {
-      let res = await userApi.login({
-        loginName: formData.value.email,
-        password: formData.value.password,
-      })
-      if (res.code == 200) { // Code.StatusOK
-        userToken.value = res.data
-        getLoginInfo()
-      } else {
-        showToast(res.msg)
-      }
-    } catch (error) {
-      console.error(error)
+    if (res.code == 200) { // Code.StatusOK
+      userToken.value = res.data
+      getLoginInfo()
+    } else {
+      showToast(res.msg)
     }
+  } catch (error) {
+    console.error(error)
   }
-
-  const getLoginInfo = async () => {
-    try {
-      let res = await userApi.getUserInfo()
-      if (res.code == 200) { // Code.StatusOK
-        userStore.saveUserInfo(res.data)
-        showToast(t('Msg.LoginSuccess'))
-        setTimeout(() => {
-          uni.reLaunch({
-            url: '/pages/customer/index',
-          })
-          // this.$store.commit("isActiveTab", "0"); (可能需要适配相应的逻辑)
-        }, 1000)
-      } else {
-        showToast(t('Msg.SystemError'))
-      }
-    } catch (error) {
-      console.error(error)
+}
+
+const getLoginInfo = async () => {
+  try {
+    let res = await userApi.getUserInfo()
+    if (res.code == 200) { // Code.StatusOK
+      userStore.saveUserInfo(res.data)
+      showToast(t('Msg.LoginSuccess'))
+      setTimeout(() => {
+        uni.reLaunch({
+          url: '/pages/customer/index',
+        })
+        // this.$store.commit("isActiveTab", "0"); (可能需要适配相应的逻辑)
+      }, 1000)
+    } else {
+      showToast(t('Msg.SystemError'))
     }
+  } catch (error) {
+    console.error(error)
   }
+}
 
 
-  onMounted(() => {
-    getCountry()
-    getCountryMsg()
+onMounted(() => {
+  getCountry()
+  getCountryMsg()
 
-    const hostParts = window.location.host.split('.')
-    ho.value = hostParts.length > 1 ? hostParts[1] : ''
-  })
+  const hostParts = window.location.host.split('.')
+  ho.value = hostParts.length > 1 ? hostParts[1] : ''
+})
 
 </script>
 
 
-<style lang="scss">
-  .pwd {
-    list-style: none;
-    padding-left: 0;
-    margin: 0;
+<style lang="scss" scoped>
+.chat-icon {
+  width: px2rpx(50);
+  height: px2rpx(50);
+  border-radius: 50%;
+  background-color: #cf1322;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: fixed;
+  bottom: px2rpx(25);
+  right: px2rpx(-25);
+  z-index: 999;
+  cursor: pointer;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 0 px2rpx(8) px2rpx(20) rgba(0, 0, 0, 0.15);
+  will-change: transform;
+}
+
+.chat-icon:hover {
+  transform: scale(1.1);
+}
+
+.chat-icon-expanded {
+  bottom: px2rpx(20);
+  right: px2rpx(20);
+  transform: scale(1.1);
+  box-shadow: 0 px2rpx(12) px2rpx(30) rgba(0, 0, 0, 0.2);
+}
+
+.chat-icon-hidden {
+  display: none;
+}
+
+.pwd {
+  list-style: none;
+  padding-left: 0;
+  margin: 0;
+
+  li {
+    font-size: px2rpx(12);
+    color: #999;
+    line-height: px2rpx(20);
+    position: relative;
+    padding-left: px2rpx(16);
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 50%;
+      transform: translateY(-50%);
+      width: px2rpx(6);
+      height: px2rpx(6);
+      border-radius: 50%;
+      background-color: #999;
+    }
 
-    li {
-      font-size: px2rpx(12);
-      color: #999;
-      line-height: px2rpx(20);
-      position: relative;
-      padding-left: px2rpx(16);
+    &.fit {
+      color: #67c23a;
 
       &::before {
-        content: '';
-        position: absolute;
-        left: 0;
-        top: 50%;
-        transform: translateY(-50%);
-        width: px2rpx(6);
-        height: px2rpx(6);
-        border-radius: 50%;
-        background-color: #999;
-      }
-
-      &.fit {
-        color: #67c23a;
-
-        &::before {
-          background-color: #67c23a;
-        }
+        background-color: #67c23a;
       }
     }
   }
+}
 </style>
 <style lang="scss" scoped>
-  @import "@/uni.scss";
-
-  :deep(uni-content) {
-    padding-left: 0 !important;
-  }
-
-  .regist-page {
-    height: 100vh;
-    border: none;
-    padding: 0;
-    position: relative;
-    display: flex;
-    flex-direction: column;
-  }
-  .fixed {
-    width: 100%;
-    height: var(--status-bar-height);
-    background-color: var(--color-white);
-    z-index: 9;
+@import "@/uni.scss";
+
+:deep(uni-content) {
+  padding-left: 0 !important;
+}
+
+.regist-page {
+  height: 100vh;
+  border: none;
+  padding: 0;
+  position: relative;
+  display: flex;
+  flex-direction: column;
+}
+
+.fixed {
+  width: 100%;
+  height: var(--status-bar-height);
+  background-color: var(--color-white);
+  z-index: 9;
+}
+
+.global-header-bar {
+  width: 100%;
+  height: px2rpx(60);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  z-index: 100;
+
+  &.pc-header {
+    background-color: transparent;
   }
 
-  .global-header-bar {
+  .header-inner {
     width: 100%;
-    height: px2rpx(60);
+    padding: 0 5%;
     display: flex;
+    justify-content: space-between;
+    /* 两端对齐,可放logo和组件 */
     align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-    z-index: 100;
-    
-    &.pc-header {
-      background-color: transparent;
-    }
-
-    .header-inner {
-      width: 100%;
-      padding: 0 5%;
-      display: flex;
-      justify-content: space-between; /* 两端对齐,可放logo和组件 */
-      align-items: center;
-    }
   }
-
-  .mobile-header-bar {
-    //position: absolute;
-    //top: px2rpx(20);
-    //right: px2rpx(20);
-    z-index: 10;
-    width: 100%;
-    background-color: var(--color-white);
-    display: flex;
-    justify-content: flex-end;
-  }
-
-  .main-content {
-    flex: 1;
-    overflow: hidden;
-    background-image: url(/static/images/login-bg.gif);
-    background-repeat: no-repeat;
-    background-size: cover;
-    background-position: center center;
-  }
-
-  .demo-uni-row {
+}
+
+.mobile-header-bar {
+  //position: absolute;
+  //top: px2rpx(20);
+  //right: px2rpx(20);
+  z-index: 10;
+  width: 100%;
+  background-color: var(--color-white);
+  display: flex;
+  justify-content: flex-end;
+}
+
+.main-content {
+  flex: 1;
+  overflow: hidden;
+  background-image: url(/static/images/login-bg.gif);
+  background-repeat: no-repeat;
+  background-size: cover;
+  background-position: center center;
+}
+
+.demo-uni-row {
+  height: 100%;
+  margin: 0 !important;
+
+  .left-bg {
     height: 100%;
-    margin: 0 !important;
+    min-height: calc(100vh - 120px);
 
-    .left-bg {
-      height: 100%;
-      min-height: calc(100vh - 120px);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
 
+    .left-box {
       display: flex;
       flex-direction: column;
-      align-items: center;
       justify-content: center;
+      align-items: flex-start;
+      width: 60%;
+      //margin-top: px2rpx(0);
+
+      .inner {
+        width: 100%;
+        text-align: start;
+        margin-bottom: px2rpx(20);
 
-      .left-box {
-        display: flex;
-        flex-direction: column;
-        justify-content: center;
-        align-items: flex-start;
-        width: 60%;
-        //margin-top: px2rpx(0);
-
-        .inner {
-          width: 100%;
-          text-align: start;
-          margin-bottom: px2rpx(20);
-
-          .section-title {
-            margin-top: px2rpx(10);
-            margin-bottom: px2rpx(10);
-          }
-
-
-          .title {
-            font-size: px2rpx(50);
-            line-height: 1.3;
-            color: #fff;
-            font-weight: 700;
-            text-align: left;
-          }
-
-          .w-700 {
-            font-weight: 700;
-          }
-
-          .subtitle {
-            width: 45%;
-            font-size: px2rpx(18);
-            letter-spacing: px2rpx(1);
-            display: block;
-            margin-bottom: px2rpx(24);
-            color: #ffffff;
-            line-height: px2rpx(15);
-            font-weight: 500;
-            padding: px2rpx(10) px2rpx(20);
-            border-radius: px2rpx(100);
-            text-transform: uppercase;
-            background-color: #e61f1e;
-            text-align: center;
-          }
-
-          .w-40 {
-            max-width: 40%;
-          }
-
-          .text-white {
-            margin-top: px2rpx(10);
-            font-size: px2rpx(14);
-            line-height: 1.6;
-            color: #fff;
-          }
+        .section-title {
+          margin-top: px2rpx(10);
+          margin-bottom: px2rpx(10);
         }
 
-        .img-fluid {
-          width: 100%;
-          max-width: px2rpx(240);
+
+        .title {
+          font-size: px2rpx(50);
+          line-height: 1.3;
+          color: #fff;
+          font-weight: 700;
+          text-align: left;
         }
 
-        .mt--10 {
-          margin-top: px2rpx(10);
+        .w-700 {
+          font-weight: 700;
         }
 
-        .h1 {
-          // text-align: center;
-          color: #fff;
-          font-size: 30px;
-          margin-top: 30px;
-          line-height: 1.5;
+        .subtitle {
+          width: 45%;
+          font-size: px2rpx(18);
+          letter-spacing: px2rpx(1);
+          display: block;
+          margin-bottom: px2rpx(24);
+          color: #ffffff;
+          line-height: px2rpx(15);
+          font-weight: 500;
+          padding: px2rpx(10) px2rpx(20);
+          border-radius: px2rpx(100);
+          text-transform: uppercase;
+          background-color: #e61f1e;
+          text-align: center;
         }
 
-        .h6 {
-          text-align: start;
-          line-height: 20px;
-          color: #fff;
-          font-size: 14px;
-          margin-top: 10px;
+        .w-40 {
+          max-width: 40%;
         }
 
-        .company {
-          padding: px2rpx(10) 0 px2rpx(10) 0;
-          position: relative;
-          align-items: flex-start !important;
-          width: 100%;
+        .text-white {
+          margin-top: px2rpx(10);
+          font-size: px2rpx(14);
+          line-height: 1.6;
+          color: #fff;
         }
       }
 
-      .left-content {
+      .img-fluid {
         width: 100%;
+        max-width: px2rpx(240);
+      }
 
-        .des {
-          text-align: start;
-          line-height: 24px;
-          color: #fff;
-          font-size: 14px;
-          margin-top: px2rpx(20);
-          padding: 0;
-
-          :nth-child(n) {
-            display: inline;
-            word-break: break-all;
-            word-wrap: break-word;
-          }
-
-          .doc-link {
-            color: var(--color-error);
-            text-decoration: underline;
-            margin: 0 px2rpx(4);
-          }
-        }
+      .mt--10 {
+        margin-top: px2rpx(10);
       }
-    }
 
-    .right-f {
-      background-color: var(--color-white);
-      padding: 0 px2rpx(24);
-      height: 100%;
-      box-sizing: border-box;
+      .h1 {
+        // text-align: center;
+        color: #fff;
+        font-size: 30px;
+        margin-top: 30px;
+        line-height: 1.5;
+      }
 
-      .account {
-        background-color: var(--color-white);
-        position: relative;
-        height: calc(100vh - 120px);
-        overflow-y: auto;
-        display: flex;
-        flex-direction: column;
-        padding: px2rpx(32) 10%;
+      .h6 {
+        text-align: start;
+        line-height: 20px;
+        color: #fff;
+        font-size: 14px;
+        margin-top: 10px;
+      }
 
-        .title {
-          margin: px2rpx(32) 0;
-          font-size: px2rpx(24);
-          font-weight: bolder;
-          color: #e4e4e4;
-          text-align: center;
+      .company {
+        padding: px2rpx(10) 0 px2rpx(10) 0;
+        position: relative;
+        align-items: flex-start !important;
+        width: 100%;
+      }
+    }
 
-          i {
-            margin-right: px2rpx(10);
-          }
-
-          .tit1 {
-            font-size: px2rpx(34);
-            line-height: 1.5;
-            font-weight: bold;
-            color: #000000;
-          }
-
-          .tit2 {
-            font-size: px2rpx(16);
-            line-height: 1.5;
-            color: #cecece;
-            font-weight: 500;
-          }
-        }
+    .left-content {
+      width: 100%;
 
-        .company {
-          padding: px2rpx(50) 0 px2rpx(20) 0;
-          position: relative;
-          align-items: center !important;
+      .des {
+        text-align: start;
+        line-height: 24px;
+        color: #fff;
+        font-size: 14px;
+        margin-top: px2rpx(20);
+        padding: 0;
+
+        :nth-child(n) {
+          display: inline;
+          word-break: break-all;
+          word-wrap: break-word;
         }
 
-        .company-icon {
-          width: px2rpx(234);
+        .doc-link {
+          color: var(--color-error);
+          text-decoration: underline;
+          margin: 0 px2rpx(4);
         }
       }
     }
   }
 
-  .content-wrapper {
-    max-width: px2rpx(1224);
-    width: 100%;
-    margin: 0 auto;
-    padding-top: px2rpx(20);
+  .right-f {
+    background-color: var(--color-white);
+    padding: 0 px2rpx(24);
+    height: 100%;
     box-sizing: border-box;
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    min-height: calc(100vh - 56px);
-  }
 
-  .regist-content {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
+    .account {
+      background-color: var(--color-white);
+      position: relative;
+      height: calc(100vh - 120px);
+      overflow-y: auto;
+      display: flex;
+      flex-direction: column;
+      padding: px2rpx(32) 10%;
 
-  .content {
-    width: px2rpx(650);
-    margin: 0 auto;
-  }
+      .title {
+        margin: px2rpx(32) 0;
+        font-size: px2rpx(24);
+        font-weight: bolder;
+        color: #e4e4e4;
+        text-align: center;
 
-  .regist-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: flex-end;
-    margin: px2rpx(40) 0 px2rpx(20);
-    padding-bottom: px2rpx(10);
-
-    .title {
-      font-size: px2rpx(28);
-      font-weight: bold;
-      color: #141d22;
-      line-height: 1;
-    }
+        i {
+          margin-right: px2rpx(10);
+        }
 
-    .login-link {
-      font-size: px2rpx(14);
-      color: #141d22;
-      display: flex;
-      align-items: center;
-      line-height: 1;
+        .tit1 {
+          font-size: px2rpx(34);
+          line-height: 1.5;
+          font-weight: bold;
+          color: #000000;
+        }
 
-      .text {
-        margin-right: px2rpx(4);
+        .tit2 {
+          font-size: px2rpx(16);
+          line-height: 1.5;
+          color: #cecece;
+          font-weight: 500;
+        }
       }
 
+      .company {
+        padding: px2rpx(50) 0 px2rpx(20) 0;
+        position: relative;
+        align-items: center !important;
+      }
 
+      .company-icon {
+        width: px2rpx(234);
+      }
     }
   }
-
-  .login-link{
-    margin-top: px2rpx(20);
-    text-align: start;
-    display: flex;
-    align-items: center;
-    font-size: px2rpx(16);
-    line-height: 1.6;
-  }
-  .link {
-    color: #e61f1e;
-    padding-bottom: 2px;
-    cursor: pointer;
-    font-size: px2rpx(14);
-  }
-  //display: flex;
-  .logo {
-    width: 100%;
-    margin-top: px2rpx(40);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  .agreemnet9 {
-    text-align: initial;
-    color: #e61f1e;
-  }
-
-  .company-icon {
-    width: px2rpx(234);
+}
+
+.content-wrapper {
+  max-width: px2rpx(1224);
+  width: 100%;
+  margin: 0 auto;
+  padding-top: px2rpx(20);
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  min-height: calc(100vh - 56px);
+}
+
+.regist-content {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.content {
+  width: px2rpx(650);
+  margin: 0 auto;
+}
+
+.regist-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-end;
+  margin: px2rpx(40) 0 px2rpx(20);
+  padding-bottom: px2rpx(10);
+
+  .title {
+    font-size: px2rpx(28);
+    font-weight: bold;
+    color: #141d22;
+    line-height: 1;
   }
 
-  .account-type {
-    width: 100%;
-    margin-top: px2rpx(20);
-    padding: px2rpx(10);
-    background-color: $uni-bg-color-hover;
-    height: px2rpx(60);
-    box-sizing: border-box;
-    border-radius: px2rpx(20);
+  .login-link {
+    font-size: px2rpx(14);
+    color: #141d22;
     display: flex;
     align-items: center;
+    line-height: 1;
 
-    .type-btn {
-      width: 50%;
-      text-align: center;
-      height: px2rpx(40);
-      border-radius: px2rpx(20);
-      line-height: px2rpx(40);
-      font-size: px2rpx(18);
-      cursor: pointer;
-
-      &.active {
-        background-color: var(--primary-color);
-      }
+    .text {
+      margin-right: px2rpx(4);
     }
-  }
 
 
-  .formStyle {
-    height: px2rpx(40);
   }
-
-  .account-tip {
-    width: 100%;
+}
+
+.login-link {
+  margin-top: px2rpx(20);
+  text-align: start;
+  display: flex;
+  align-items: center;
+  font-size: px2rpx(16);
+  line-height: 1.6;
+}
+
+.link {
+  color: #e61f1e;
+  padding-bottom: 2px;
+  cursor: pointer;
+  font-size: px2rpx(14);
+}
+
+//display: flex;
+.logo {
+  width: 100%;
+  margin-top: px2rpx(40);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.agreemnet9 {
+  text-align: initial;
+  color: #e61f1e;
+}
+
+.company-icon {
+  width: px2rpx(234);
+}
+
+.account-type {
+  width: 100%;
+  margin-top: px2rpx(20);
+  padding: px2rpx(10);
+  background-color: $uni-bg-color-hover;
+  height: px2rpx(60);
+  box-sizing: border-box;
+  border-radius: px2rpx(20);
+  display: flex;
+  align-items: center;
+
+  .type-btn {
+    width: 50%;
     text-align: center;
-    margin: px2rpx(30) 0;
-
-    .title {
-      font-size: px2rpx(26);
-      font-weight: bold;
-    }
+    height: px2rpx(40);
+    border-radius: px2rpx(20);
+    line-height: px2rpx(40);
+    font-size: px2rpx(18);
+    cursor: pointer;
 
-    .tip {
-      margin-top: px2rpx(5);
-      color: var(--gray);
+    &.active {
+      background-color: var(--primary-color);
     }
   }
+}
 
-  .formContent {
-    padding: 0 10px;
-  }
 
-  // 修改表单组件高度。
-  :deep(.uni-stat-box) {
-    height: 100%;
-  }
+.formStyle {
+  height: px2rpx(40);
+}
 
-  :deep(.uni-select) {
-    height: 100%;
-  }
-
-  :deep(.uni-easyinput__content) {
-    height: 100%;
-  }
+.account-tip {
+  width: 100%;
+  text-align: center;
+  margin: px2rpx(30) 0;
 
-  :deep(.uni-date-editor) {
-    height: 100%;
+  .title {
+    font-size: px2rpx(26);
+    font-weight: bold;
   }
 
-  :deep(.uni-date-editor--x) {
-    height: 100%;
+  .tip {
+    margin-top: px2rpx(5);
+    color: var(--gray);
   }
-
-  .btn-code {
-    width: 120px;
-    height: px2rpx(37);
-    box-sizing: border-box;
-    background-color: #102047;
-    border: 1px solid rgb(229, 229, 229);
-    color: #fff;
-    text-align: center;
-    line-height: px2rpx(35);
-    border-radius: 4px;
-    cursor: pointer;
-    font-size: 14px;
-    flex-shrink: 0;
+}
+
+.formContent {
+  padding: 0 10px;
+}
+
+// 修改表单组件高度。
+:deep(.uni-stat-box) {
+  height: 100%;
+}
+
+:deep(.uni-select) {
+  height: 100%;
+}
+
+:deep(.uni-easyinput__content) {
+  height: 100%;
+}
+
+:deep(.uni-date-editor) {
+  height: 100%;
+}
+
+:deep(.uni-date-editor--x) {
+  height: 100%;
+}
+
+.btn-code {
+  width: 120px;
+  height: px2rpx(37);
+  box-sizing: border-box;
+  background-color: #102047;
+  border: 1px solid rgb(229, 229, 229);
+  color: #fff;
+  text-align: center;
+  line-height: px2rpx(35);
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 14px;
+  flex-shrink: 0;
+}
+
+.check-box {
+  padding: 0 px2rpx(10);
+  margin-bottom: px2rpx(10);
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+
+  .checkbox-label {
+    font-size: px2rpx(14);
+    color: #666666;
+    margin-left: px2rpx(8);
+    user-select: none;
   }
 
-  .check-box {
-    padding: 0 px2rpx(10);
-    margin-bottom: px2rpx(10);
+  :deep(.u-checkbox) {
     display: flex;
-    align-items: center;
-    cursor: pointer;
-
-    .checkbox-label {
-      font-size: px2rpx(14);
-      color: #666666;
-      margin-left: px2rpx(8);
-      user-select: none;
-    }
-
-    :deep(.u-checkbox) {
-      display: flex;
-      align-items: flex-start;
-    }
-  }
-
-  .regiset-btn {
-    width: 100%;
-    height: px2rpx(40);
-    border-radius: px2rpx(4);
-    background-color: var(--color-error);
-    color: #fff;
-    font-weight: bold;
+    align-items: flex-start;
   }
-
-  .or-title {
-    font-size: px2rpx(16);
-    line-height: 1.5;
-    color: #333;
-    font-weight: 500;
-    text-align: center;
-    margin: px2rpx(20) 0 px2rpx(18) 0;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-
-    .line {
-      flex: 1;
-      height: 1px;
-      background-color: #e4e4e4;
-    }
-
-    .qr-tit2 {
-      margin: 0 px2rpx(12);
-    }
+}
+
+.regiset-btn {
+  width: 100%;
+  height: px2rpx(40);
+  border-radius: px2rpx(4);
+  background-color: var(--color-error);
+  color: #fff;
+  font-weight: bold;
+}
+
+.or-title {
+  font-size: px2rpx(16);
+  line-height: 1.5;
+  color: #333;
+  font-weight: 500;
+  text-align: center;
+  margin: px2rpx(20) 0 px2rpx(18) 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  .line {
+    flex: 1;
+    height: 1px;
+    background-color: #e4e4e4;
   }
 
-  .login-btn {
-    width: 100%;
-    height: px2rpx(40);
-    border-radius: px2rpx(20);
-    background-color: #1EBF42;
-    color: #fff;
-    font-weight: bold;
-    margin-bottom: px2rpx(20);
+  .qr-tit2 {
+    margin: 0 px2rpx(12);
   }
-
-  .code-text {
-    padding-right: px2rpx(20);
+}
+
+.login-btn {
+  width: 100%;
+  height: px2rpx(40);
+  border-radius: px2rpx(20);
+  background-color: #1EBF42;
+  color: #fff;
+  font-weight: bold;
+  margin-bottom: px2rpx(20);
+}
+
+.code-text {
+  padding-right: px2rpx(20);
+}
+
+.des-bottom {
+  margin-top: px2rpx(20);
+  line-height: 20px;
+  color: #000;
+  font-size: 12px;
+
+  a {
+    color: #e61f1e;
   }
-
-  .des-bottom {
-    margin-top: px2rpx(20);
-    line-height: 20px;
-    color: #000;
-    font-size: 12px;
-
-    a {
-      color: #e61f1e;
-    }
+}
+
+.des {
+  width: 100%;
+  box-sizing: border-box;
+  text-align: start;
+  line-height: 20px;
+  color: #000;
+  font-size: 12px;
+  padding: px2rpx(20) px2rpx(30);
+
+  //display: none;
+  :nth-child(n) {
+    display: inline;
+    word-break: break-all;
+    word-wrap: break-word;
   }
 
-  .des {
-    width: 100%;
-    box-sizing: border-box;
-    text-align: start;
-    line-height: 20px;
-    color: #000;
-    font-size: 12px;
-    padding: px2rpx(20) px2rpx(30);
-
-    //display: none;
-    :nth-child(n) {
-      display: inline;
-      word-break: break-all;
-      word-wrap: break-word;
-    }
-
-    a {
-      color: #e61f1e;
-    }
+  a {
+    color: #e61f1e;
   }
+}
 
-  :deep(.u-text__value) {
-    color: #ea002a !important;
-    font-size: px2rpx(14) !important;
-  }
+:deep(.u-text__value) {
+  color: #ea002a !important;
+  font-size: px2rpx(14) !important;
+}
 </style>

+ 188 - 133
pages/login/reset.vue

@@ -17,11 +17,7 @@
             <view class="reset-title">{{ t('pages.login.resetTitle') }}</view>
             <view class="reset-form">
               <view class="form-label">{{ t('newSignup.item7') }}</view>
-              <uni-easyinput
-                v-model="email"
-                :placeholder="t('forget.form')"
-                class="custom-input"
-              >
+              <uni-easyinput v-model="email" :placeholder="t('forget.form')" class="custom-input">
               </uni-easyinput>
 
               <view class="reset-button">
@@ -34,173 +30,232 @@
           </uni-col>
         </uni-row>
       </view>
+      <view class="chat-icon" :class="{ 'chat-icon-expanded': isChatIconExpanded, 'chat-icon-hidden': type == 'chat' }"
+        @click="handleChatIconClick">
+        <cwg-icon name="chat" color="#fff" />
+      </view>
     </view>
   </cwg-page-wrapper>
 </template>
 
 <script setup lang="ts">
-  import { ref } from 'vue'
-  import { useI18n } from 'vue-i18n'
-  import useRouter from '@/hooks/useRouter'
-  import { userApi } from '@/api/user'
-  import config from '@/config'
-  import LoginHeaderGroup from './components/LoginHeaderGroup.vue'
-
-  const { t } = useI18n()
-  const router = useRouter()
-  const loading = ref(false)
-  const email = ref('')
-
-  async function handleReset() {
-    if (!email.value) {
-      uni.showToast({ title: t('vaildate.email.empty'), icon: 'none' })
-      return
-    }
-    if (!config.Pattern.Email.test(email.value)) {
-      uni.showToast({ title: t('vaildate.email.format'), icon: 'none' })
-      return
-    }
+import { ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+import useRouter from '@/hooks/useRouter'
+import { userApi } from '@/api/user'
+import config from '@/config'
+import LoginHeaderGroup from './components/LoginHeaderGroup.vue'
+import { useWindowWidth } from '@/composables/useWindowWidth'
+const windowWidth = useWindowWidth(300)
+const isMobile = computed(() => windowWidth.value <= 991)
+const { t } = useI18n()
+const router = useRouter()
+const loading = ref(false)
+const email = ref('')
+import LiveChatService from '@/utils/liveChat.js'
 
-    loading.value = true
-    try {
-      const res = await userApi.forgetPwd({ email: email.value })
-      uni.showToast({ title: res.msg, icon: 'success' })
-      setTimeout(() => {
-        router.push('/pages/login/index')
-      }, 1000)
-    } catch (error: any) {
-      uni.showToast({ title: error.message, icon: 'none' })
-    } finally {
-      loading.value = false
-    }
+async function handleReset() {
+  if (!email.value) {
+    uni.showToast({ title: t('vaildate.email.empty'), icon: 'none' })
+    return
+  }
+  if (!config.Pattern.Email.test(email.value)) {
+    uni.showToast({ title: t('vaildate.email.format'), icon: 'none' })
+    return
   }
 
-  function handleChange(value: any) {
-    if (value.key == 'email') {
-      email.value = value.value
+  loading.value = true
+  try {
+    const res = await userApi.forgetPwd({ email: email.value })
+    uni.showToast({ title: res.msg, icon: 'success' })
+    setTimeout(() => {
+      router.push('/pages/login/index')
+    }, 1000)
+  } catch (error: any) {
+    uni.showToast({ title: error.message, icon: 'none' })
+  } finally {
+    loading.value = false
+  }
+}
+const isChatIconExpanded = ref(false)
+// 处理聊天图标点击
+const handleChatIconClick = () => {
+  // 如果还没显示 → 先滑出来
+  if (!isChatIconExpanded.value) {
+    isChatIconExpanded.value = true
+    return
+  }
+  if (isMobile.value) {
+    router.push('/pages/common/chat')
+  } else {
+    if (LiveChatService) {
+      LiveChatService.showChat();
     }
   }
-
-  function handleLogin() {
-    router.push('/pages/login/index')
+  setTimeout(() => {
+    isChatIconExpanded.value = false
+  }, 300)
+}
+function handleChange(value: any) {
+  if (value.key == 'email') {
+    email.value = value.value
   }
+}
+
+function handleLogin() {
+  router.push('/pages/login/index')
+}
 </script>
 
 <style scoped lang="scss">
-  @import "@/uni.scss";
+@import "@/uni.scss";
 
-  :deep(uni-content) {
-    padding-left: 0 !important;
-  }
+.chat-icon {
+  width: px2rpx(50);
+  height: px2rpx(50);
+  border-radius: 50%;
+  background-color: #cf1322;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: fixed;
+  bottom: px2rpx(25);
+  right: px2rpx(-25);
+  z-index: 999;
+  cursor: pointer;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 0 px2rpx(8) px2rpx(20) rgba(0, 0, 0, 0.15);
+  will-change: transform;
+}
 
-  .main-content {
-    display: flex;
-    flex-direction: column;
-  }
+.chat-icon:hover {
+  transform: scale(1.1);
+}
 
-  .global-header-bar {
-    width: 100%;
-    height: px2rpx(60);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    flex-shrink: 0;
-    z-index: 100;
+.chat-icon-expanded {
+  bottom: px2rpx(20);
+  right: px2rpx(20);
+  transform: scale(1.1);
+  box-shadow: 0 px2rpx(12) px2rpx(30) rgba(0, 0, 0, 0.2);
+}
 
-    &.pc-header {
-      background-color: transparent;
-      border-bottom: 1px solid rgba(0, 0, 0, 0.05);
-    }
+.chat-icon-hidden {
+  display: none;
+}
 
-    .header-inner {
-      width: 100%;
-      padding: 0 5%;
-      display: flex;
-      justify-content: space-between; /* 两端对齐,可放logo和组件 */
-      align-items: center;
-    }
-  }
+:deep(uni-content) {
+  padding-left: 0 !important;
+}
+
+.main-content {
+  display: flex;
+  flex-direction: column;
+}
 
-  .mobile-header-bar {
-    position: absolute;
-    top: px2rpx(20);
-    right: px2rpx(20);
-    z-index: 10;
+.global-header-bar {
+  width: 100%;
+  height: px2rpx(60);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  z-index: 100;
+
+  &.pc-header {
+    background-color: transparent;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
   }
 
-  .reset-container {
-    margin-top: px2rpx(20);
+  .header-inner {
+    width: 100%;
+    padding: 0 5%;
     display: flex;
-    flex-direction: column;
+    justify-content: space-between;
+    /* 两端对齐,可放logo和组件 */
     align-items: center;
-    justify-content: center;
   }
+}
 
-  .content {
-    width: 100%;
-    margin: 0 auto;
-  }
+.mobile-header-bar {
+  position: absolute;
+  top: px2rpx(20);
+  right: px2rpx(20);
+  z-index: 10;
+}
 
-  .reset-title {
-    font-size: px2rpx(28);
-    font-weight: bold;
-    color: #141d22;
-    margin-bottom: px2rpx(40);
-  }
+.reset-container {
+  margin-top: px2rpx(20);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
 
-  .reset-form {
-    width: 100%;
-  }
+.content {
+  width: 100%;
+  margin: 0 auto;
+}
 
-  .form-label {
-    font-size: px2rpx(14);
-    color: #333;
-    margin-bottom: px2rpx(8);
-  }
+.reset-title {
+  font-size: px2rpx(28);
+  font-weight: bold;
+  color: #141d22;
+  margin-bottom: px2rpx(40);
+}
 
-  .custom-input {
-    margin-bottom: px2rpx(40);
+.reset-form {
+  width: 100%;
+}
 
-    :deep(.uni-easyinput__content) {
-      height: px2rpx(40);
-      border: 1px solid #dcdfe6;
-      border-radius: px2rpx(4);
-    }
+.form-label {
+  font-size: px2rpx(14);
+  color: #333;
+  margin-bottom: px2rpx(8);
+}
+
+.custom-input {
+  margin-bottom: px2rpx(40);
+
+  :deep(.uni-easyinput__content) {
+    height: px2rpx(40);
+    border: 1px solid #dcdfe6;
+    border-radius: px2rpx(4);
   }
+}
 
-  .reset-button {
-    margin-bottom: px2rpx(20);
+.reset-button {
+  margin-bottom: px2rpx(20);
+
+  :deep(button) {
+    width: 100%;
+    height: px2rpx(44);
+    line-height: px2rpx(44);
+    border-radius: px2rpx(4);
+    background-color: var(--color-error); // 主题黄
+    border: none;
+    color: #fff;
+    font-size: px2rpx(16);
+    font-weight: 500;
+    margin: 0;
 
-    :deep(button) {
-      width: 100%;
-      height: px2rpx(44);
-      line-height: px2rpx(44);
-      border-radius: px2rpx(4);
-      background-color: var(--color-error); // 主题黄
+    &::after {
       border: none;
-      color: #fff;
-      font-size: px2rpx(16);
-      font-weight: 500;
-      margin: 0;
-
-      &::after {
-        border: none;
-      }
     }
+  }
 
-    :deep(u-button--loading) {
-      opacity: 0.8;
-    }
+  :deep(u-button--loading) {
+    opacity: 0.8;
   }
+}
 
-  .login-link {
-    text-align: center;
+.login-link {
+  text-align: center;
 
-    .link-text {
-      font-size: px2rpx(14);
-      color: #005bbb;
-      cursor: pointer;
-      text-decoration: none;
-    }
+  .link-text {
+    font-size: px2rpx(14);
+    color: #005bbb;
+    cursor: pointer;
+    text-decoration: none;
   }
+}
 </style>