Parcourir la source

feat:完善个人信息页面

ljc il y a 2 mois
Parent
commit
685ad8774d

+ 2 - 1
components/cwg-file-picker.vue

@@ -4,7 +4,7 @@
         <view v-if="editable" class="upload-wrapper">
         <view v-if="editable" class="upload-wrapper">
             <uni-file-picker :limit="multiple ? limit : 1" :title="title" :file-mediatype="fileMediatype" :mode="mode"
             <uni-file-picker :limit="multiple ? limit : 1" :title="title" :file-mediatype="fileMediatype" :mode="mode"
                 :auto-upload="false" :value="fileList" :disabled="disabled" :readonly="readonly"
                 :auto-upload="false" :value="fileList" :disabled="disabled" :readonly="readonly"
-                :image-styles="imageStyles" :list-styles="listStyles" @select="handleSelect" @delete="handleDelete">
+                :image-styles="imageStyles" :list-styles="listStyles"  :del-icon="showPreviewDelete"             @select="handleSelect" @delete=" handleDelete">
                 <!-- 自定义上传按钮(单张图片且已有图片时显示替换) -->
                 <!-- 自定义上传按钮(单张图片且已有图片时显示替换) -->
                 <template v-if="$slots.default || showCustomButton">
                 <template v-if="$slots.default || showCustomButton">
                     <slot name="default">
                     <slot name="default">
@@ -600,6 +600,7 @@ defineExpose({
 
 
     .upload-wrapper {
     .upload-wrapper {
         width: 100%;
         width: 100%;
+        height: 100%;
 
 
         :deep(.uni-file-picker) {
         :deep(.uni-file-picker) {
             .file-picker__box {
             .file-picker__box {

+ 8 - 8
config/index.ts

@@ -11,14 +11,14 @@ let ho = '44a5c8109e4'; // 默认主域名或可根据实际APP环境配置
 const config = {
 const config = {
 
 
   HostWs: "wss://ws." + ho + ".com",
   HostWs: "wss://ws." + ho + ".com",
-  Host80: ht + "//secure." + ho + ".com",
-  Host00: ht + "//ucard." + ho + ".com",
-  Host85: ht + "//ucard." + ho + ".com",
-  Host04: ht + "//pay." + ho + ".com",
-  // Host80: 'http://192.168.0.21:8000',
-  // Host00: 'http://192.168.0.21:8000',
-  // Host85: 'http://192.168.0.21:8000',
-  // Host04: 'http://192.168.0.21:8004',
+  // Host80: ht + "//secure." + ho + ".com",
+  // Host00: ht + "//ucard." + ho + ".com",
+  // Host85: ht + "//ucard." + ho + ".com",
+  // Host04: ht + "//pay." + ho + ".com",
+  Host80: 'http://192.168.0.21:8000',
+  Host00: 'http://192.168.0.21:8000',
+  Host85: 'http://192.168.0.21:8000',
+  Host04: 'http://192.168.0.21:8004',
   Host90: ht + "//data." + ho + ".com",
   Host90: ht + "//data." + ho + ".com",
   HostShop: ht + "//shopcustom." + ho + ".com",
   HostShop: ht + "//shopcustom." + ho + ".com",
   HostShopImg: ht + "//shopmanager." + ho + ".com",
   HostShopImg: ht + "//shopmanager." + ho + ".com",

+ 2 - 1
locale/cn.json

@@ -15,7 +15,8 @@
     "copy3": "复制失败",
     "copy3": "复制失败",
     "year": "年",
     "year": "年",
     "month": "月",
     "month": "月",
-    "day": "日"
+    "day": "日",
+    "upload": "上传"
   },
   },
   "pages": {
   "pages": {
     "login": {
     "login": {

+ 6 - 0
pages.json

@@ -91,6 +91,12 @@
         "navigationStyle": "custom"
         "navigationStyle": "custom"
       }
       }
     },
     },
+    {
+      "path": "pages/mine/improveImmediately",
+      "style": {
+        "navigationBarTitleText": ""
+      }
+    },
     {
     {
       "path": "pages/login/index",
       "path": "pages/login/index",
       "style": {
       "style": {

+ 1526 - 0
pages/mine/improveImmediately.vue

@@ -0,0 +1,1526 @@
+<template>
+  <cwg-page-wrapper>
+    <view class="page page-shadow">
+      <uni-forms ref="formRef" :model="formData" :rules="rules" labelWidth="200" label-position="top"
+                 class="payment-form">
+        <!-- 第一步:个人信息 -->
+        <view v-show="currentStep === 1" class="form-section">
+          <h3 class="section-title">{{ t('ImproveImmediately.Title.BasicInformation') }}</h3>
+          <uni-row class="demo-uni-row uni-row1">
+            <!-- 客户类型 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item :label="t('ImproveImmediately.Label.CustomerType')">
+                <cwg-combox :clearable="false" v-model:value="formData.customType"
+                            :options="customerTypeOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 公司名称 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="formData.customType == 2">
+              <uni-forms-item :label="t('ImproveImmediately.Label.CompanyName')">
+                <uni-easyinput :clearable="false" v-model="formData.companyName"
+                               :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 姓 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item :label="formData.customType == 2
+                ? t('ImproveImmediately.Label.CorporationLastName')
+                : t('ImproveImmediately.Label.LastName')">
+                <uni-easyinput :clearable="false" v-model="formData.lastName" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 名 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item :label="formData.customType == 2
+                ? t('ImproveImmediately.Label.CorporationName')
+                : t('ImproveImmediately.Label.Name')">
+                <uni-easyinput :clearable="false" v-model="formData.firstName" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 法人中间名 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="lang == 'en'">
+              <uni-forms-item name="middle" :label="t('placeholder.middle')">
+                <uni-easyinput :clearable="false" v-model="formData.middle" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 国家 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="countryOptions.length > 0">
+              <uni-forms-item name="nationality" :label="t('ImproveImmediately.Label.Nationality')">
+                <cwg-combox :clearable="false" :filterable="true"
+                            v-model:value="formData.nationality" :options="countryOptions"
+                            :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 证件类型 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="IdentityType" :label="identityLabel">
+                <cwg-combox :clearable="false" v-model:value="formData.IdentityType"
+                            :options="identityTypes" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 证件号 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="identity" :label="t('ImproveImmediately.Label.IdentityID')">
+                <uni-easyinput :clearable="false" v-model="formData.identity" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 拼音 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="['cn', 'zhHant'].includes(lang)">
+              <uni-forms-item name="nameEn" :label="t('ImproveImmediately.Label.NamePinYin')">
+                <uni-easyinput :clearable="false" v-model="formData.nameEn" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 性别 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="gender" :label="t('ImproveImmediately.Label.Gender')">
+                <cwg-combox :clearable="false" v-model:value="formData.gender" :options="genderOptions"
+                            :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 生日 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="birth" :label="t('ImproveImmediately.Label.Birthday')">
+                <uni-datetime-picker :clear-icon="false" type="date" return-type="timestamp"
+                                     v-model="formData.birth" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :span="24">
+              <view class="crm-title-box">
+                <text class="tit">{{ t('ImproveImmediately.Title.AddressInformation') }}</text>
+                <uni-popup ref="addressTipPopup" type="center">
+                  <view class="popup-content">{{ t('ImproveImmediately.Title.AddressTip') }}</view>
+                </uni-popup>
+                <text class="icon-tip" @click="openAddressTip">ⓘ</text>
+              </view>
+            </uni-col>
+
+            <!-- 国家/地区 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-if="countryOptions.length > 0">
+              <uni-forms-item name="country" :label="t('ImproveImmediately.Label.CountryRegionOfResidence')">
+                <cwg-combox :clearable="false" :filterable="true" v-model:value="formData.country"
+                            :options="countryOptions" :placeholder="t('placeholder.choose')" @change="changeCountry" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 省份/州 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                     v-if="formData.country == 'CN' || formData.country == 'CNX' || formData.country == 'CNA' || formData.country == 'CNT'">
+              <uni-forms-item name="state" :label="t('ImproveImmediately.Label.ProvinceRegion')">
+                <cwg-combox :clearable="false" :filterable="true" v-model:value="formData.state"
+                            :options="stateOptions" :placeholder="t('placeholder.choose')" @change="changeState" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 国外省份/州 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-else>
+              <uni-forms-item name="state" :label="t('ImproveImmediately.Label.ProvinceRegion')">
+                <uni-easyinput :clearable="false" v-model="formData.state" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 城市 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8"
+                     v-if="formData.country == 'CN' || formData.country == 'CNX' || formData.country == 'CNA' || formData.country == 'CNT'">
+              <uni-forms-item name="city" :label="t('ImproveImmediately.Label.City')">
+                <cwg-combox :clearable="false" :filterable="true" v-model:value="formData.city"
+                            :options="cityOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <!-- 国外城市 -->
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8" v-else>
+              <uni-forms-item name="city" :label="t('ImproveImmediately.Label.City')">
+                <uni-easyinput :clearable="false" v-model="formData.city" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="addressLines1" :label="t('ImproveImmediately.Label.DetailedAddress')">
+                <uni-easyinput :clearable="false" v-model="formData.addressLines1"
+                               :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="zipCode" :label="t('ImproveImmediately.Label.ZipCode')">
+                <uni-easyinput :clearable="false" v-model="formData.zipCode" :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="addressLines2" :label="t('ImproveImmediately.Label.DetailedAddressStandby')">
+                <uni-easyinput :clearable="false" v-model="formData.addressLines2"
+                               :placeholder="t('placeholder.input')" />
+              </uni-forms-item>
+            </uni-col>
+          </uni-row>
+        </view>
+        <!-- 第二步:财务背景 -->
+        <view v-show="currentStep === 2" class="form-section">
+          <h3 class="section-title">{{ t('ImproveImmediately.Title.FinancialBackground') }}</h3>
+          <uni-row class="demo-uni-row uni-row1">
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="level" :label="t('ImproveImmediately.Label.Education')">
+                <cwg-combox :clearable="false" v-model:value="formData.level"
+                            :options="educationOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="employmentStatus" :label="t('ImproveImmediately.Label.OnJob')">
+                <cwg-combox :clearable="false" v-model:value="formData.employmentStatus"
+                            :options="employmentOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="tradingObjectives" :label="t('ImproveImmediately.Label.purposeTransaction')">
+                <cwg-combox :clearable="false" v-model:value="formData.tradingObjectives"
+                            :options="transactionPurposeOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="sourceFunding" :label="t('ImproveImmediately.Label.SourceFunds')">
+                <cwg-combox :clearable="false" v-model:value="formData.sourceFunding"
+                            :options="fundSourceOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="grossAnnualIncome" :label="t('ImproveImmediately.Label.TotalAnnualRevenue')">
+                <cwg-combox :clearable="false" v-model:value="formData.grossAnnualIncome"
+                            :options="annualIncomeOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="8" :xl="8">
+              <uni-forms-item name="totalNewWorth" :label="t('ImproveImmediately.Label.TotalNetAssets')">
+                <cwg-combox :clearable="false" v-model:value="formData.totalNewWorth"
+                            :options="netWorthOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+            </uni-col>
+          </uni-row>
+          <h3 class="section-title">{{ t('ImproveImmediately.Title.TradingExperience') }}</h3>
+          <view class="experience">
+            <text class="Trad-experience">{{ t('ImproveImmediately.Content.TradingExperience1') }}</text>
+            <view class="Trad-choose">
+              <uni-data-checkbox v-model="formData.experienceTradingDerivative"
+                                 :localdata="radioList"></uni-data-checkbox>
+            </view>
+          </view>
+          <view class="experience">
+            <text class="Trad-experience">{{ t('ImproveImmediately.Content.TradingExperience2') }}</text>
+            <view class="Trad-choose">
+              <uni-data-checkbox v-model="formData.experienceTradingForex" :localdata="radioList"></uni-data-checkbox>
+            </view>
+          </view>
+          <view class="experience">
+            <text class="Trad-experience">{{ t('ImproveImmediately.Content.TradingExperience3') }}</text>
+            <view class="Trad-choose">
+              <uni-data-checkbox v-model="formData.derivativeProducts" :localdata="radioList"></uni-data-checkbox>
+            </view>
+          </view>
+          <view class="experience">
+            <text class="Trad-experience">{{ t('ImproveImmediately.Content.TradingExperience4') }}</text>
+            <view class="Trad-choose">
+              <uni-data-checkbox v-model="formData.experienceQualification" :localdata="radioList"></uni-data-checkbox>
+            </view>
+          </view>
+        </view>
+        <!-- 第三步:身份证明 -->
+        <view v-show="currentStep === 3" class="form-section">
+          <h3 class="section-title">{{ t('ImproveImmediately.Title.ProofIdentityUpdate') }}</h3>
+          <uni-row class="demo-uni-row uni-row1">
+            <uni-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+              <uni-forms-item name="cardType" :label="t('ImproveImmediately.Label.CardType')">
+                <cwg-combox :clearable="false" v-model:value="formData.cardType"
+                            :options="cardTypeOptions" :placeholder="t('placeholder.choose')" />
+              </uni-forms-item>
+              <uni-row class="demo-uni-row uni-row1">
+                <uni-col :xs="24" :sm="24" :md="10" :lg="10" :xl="10">
+                  <cwg-file-picker
+                    v-if="!fileListID1.path"
+                    v-model="fileListID1.path"
+                    :editable="fileListID1.status != 2"
+                    :limit="1"
+                    :fileMediatype="'all'"
+                    uploadUrl="/custom/file/upload/1"
+                    :baseUrl="updateUrl"
+                    :imageWidth="150"
+                    :imageHeight="150"
+                    :showPreviewDelete="false"
+                    :canDelete="false"
+                    :uploadError="false"
+                    :showProgress="false"
+                    :image-styles="imageStyle"
+                    @update:modelValue="(val) => handleFileUpdate(val, '1')"
+                    customClass="avatar-uploader"
+                  />
+                  <view v-else>
+                    <view class="file-item">
+                      <image
+                        v-if="!isPdf(fileListID1.path)"
+                        class="avatar"
+                        :src="updateUrl + fileListID1.path"
+                      ></image>
+                      <view v-else>
+                        <image class="icon" :src="icon_doc" />
+                      </view>
+
+                    </view>
+                  </view>
+                </uni-col>
+                <uni-col :xs="24" :sm="24" :md="10" :lg="10" :xl="10">
+                  <cwg-file-picker
+                    v-if="!fileListID2.path"
+                    v-model="fileListID2.path"
+                    :editable="fileListID2.status != 2"
+                    :limit="1"
+                    :fileMediatype="'all'"
+                    uploadUrl="/custom/file/upload/2"
+                    :baseUrl="updateUrl"
+                    :imageWidth="150"
+                    :imageHeight="150"
+                    :showPreviewDelete="false"
+                    :canDelete="false"
+                    :uploadError="false"
+                    :showProgress="false"
+                    :image-styles="imageStyle"
+                    @update:modelValue="(val) => handleFileUpdate(val, '2')"
+                    customClass="avatar-uploader"
+                  >
+                  </cwg-file-picker>
+                  <view v-else>
+                    <view class="file-item">
+                      <image
+                        v-if="!isPdf(fileListID2.path)"
+                        class="avatar"
+                        :src="updateUrl + fileListID2.path"
+                      ></image>
+                      <view v-else>
+                        <image class="icon" :src="icon_doc" />
+                      </view>
+                    </view>
+                  </view>
+                </uni-col>
+                <uni-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
+                  <view class="refresh-icon">
+                    <image style="width: 28px;" :src="icon_refresh" />
+                  </view>
+                </uni-col>
+              </uni-row>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+
+            </uni-col>
+          </uni-row>
+          <view class="descending">
+            <p class="title">
+              <span class="dian1">·</span>
+              <span>{{ t('ImproveImmediately.Title.IdentificationStatement') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity4') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity5') }}</span>
+            </p>
+            <p class="des" v-if="['cn', 'zhHant'].indexOf(lang) == -1">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity6') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity1') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity2') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity3') }}</span>
+            </p>
+            <p class="des" v-if="['cn', 'zhHant'].indexOf(lang) == -1">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity7') }}</span>
+            </p>
+            <p class="des" v-if="['cn', 'zhHant'].indexOf(lang) == -1">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofIdentity8') }}</span>
+            </p>
+          </view>
+        </view>
+        <!-- 第四步:地址证明 -->
+        <view v-show="currentStep === 4" class="form-section">
+          <h3 class="section-title">{{ t('ImproveImmediately.Title.ProofAddress') }}</h3>
+          <uni-row class="demo-uni-row uni-row1">
+            <uni-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+              <uni-forms-item name="addressProofUrl" :label="t('ImproveImmediately.Label.AddressProof')">
+                <cwg-input
+                  v-model:value="formData.addressProofUrl"
+                  :required="true"
+                  type="upload"
+                  fkey="addressProofUrl"
+                  rulesKey="addressProofUrl"
+                  :is-upload-d="true"
+                  accept="image/png, image/jpeg, image/jpg"
+                  @change="handleChange">
+                  <view class="cwg-upload">
+                    <cwg-icon name="back-top" />
+                    <view class="name">
+                      {{ t('Btn.Upload') }}
+                    </view>
+                    <view class="back">{{ t('ImproveImmediately.Content.ProofAddress1') }}</view>
+                  </view>
+                </cwg-input>
+              </uni-forms-item>
+            </uni-col>
+            <uni-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+              <uni-forms-item name="otherFiles" :label="t('PersonalManagement.Title.AttachedFile')">
+                <cwg-input
+                  v-model:value="formData.otherFiles"
+                  type="upload"
+                  multiple
+                  fkey="otherFiles"
+                  rulesKey="otherFiles"
+                  :is-upload-d="true"
+                  accept="image/png, image/jpeg, image/jpg, application/pdf"
+                  @change="handleChange">
+                  <view class="cwg-upload">
+                    <cwg-icon name="back-top" />
+                    <view class="name">
+                      {{ t('Btn.Upload') }}
+                    </view>
+                    <view class="back">{{ t('ImproveImmediately.Content.ProofAddress6') }}</view>
+                  </view>
+                </cwg-input>
+              </uni-forms-item>
+            </uni-col>
+          </uni-row>
+          <view class="descending">
+            <p class="title">
+              <span>{{ t('ImproveImmediately.Title.AddressDescription') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress1') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress2') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress3') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian" v-if="['cn', 'zhHant'].indexOf(lang) != -1">·</span>
+              <span class="dian" v-if="lang == 'en'">-</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress4') }}</span>
+            </p>
+            <p class="des">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress6') }}</span>
+            </p>
+            <p class="des" v-if="lang == 'en'">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress7') }}</span>
+            </p>
+            <p class="des" v-if="lang == 'en'">
+              <span class="dian">·</span>
+              <span>{{ t('ImproveImmediately.Content.ProofAddress8') }}</span>
+            </p>
+          </view>
+        </view>
+        <!-- 步骤控制按钮 -->
+        <view>
+          <template v-if="currentStep === 4">
+            <view class="btns">
+              <view class="cwg-button two-btn">
+                <u-button plain block class="prev-btn btn-primary" @click="goStep(3)">
+                  {{ t('Btn.Last') }}
+                </u-button>
+                <u-button type="primary" class="btn-primary" block :loading="loadingStates.submit" @click="Submit">
+                  {{ t('Btn.Submit') }}
+                </u-button>
+              </view>
+            </view>
+          </template>
+          <template v-else-if="currentStep === 3">
+            <view class="btns">
+              <view class="cwg-button two-btn">
+                <u-button plain block class="prev-btn btn-primary" @click="goStep(2)">
+                  {{ t('Btn.Last') }}
+                </u-button>
+                <u-button class="btn-primary" type="primary" block :loading="loadingStates.next" @click="goStep(4)">
+                  {{ t('Btn.Next') }}
+                </u-button>
+              </view>
+            </view>
+          </template>
+          <template v-else-if="currentStep === 2">
+            <view class="btns">
+              <view class="cwg-button two-btn">
+                <u-button plain block class="prev-btn btn-primary" @click="goStep(1)">
+                  {{ t('Btn.Last') }}
+                </u-button>
+                <u-button class="btn-primary" type="primary" block :loading="loadingStates.next" @click="goStep(3)">
+                  {{ t('Btn.Next') }}
+                </u-button>
+              </view>
+            </view>
+          </template>
+          <template v-else-if="currentStep === 1">
+            <view class="btns">
+              <view class="cwg-button">
+                <u-button class="btn-primary" type="primary" block :loading="loadingStates.next" @click="goStep(2)">
+                  {{ t('Btn.Next') }}
+                </u-button>
+              </view>
+            </view>
+          </template>
+        </view>
+      </uni-forms>
+    </view>
+    <view class="form-tab"></view>
+  </cwg-page-wrapper>
+  <!--离开弹出框-->
+  <uni-popup ref="dialogCheck" type="center" :show="dialogCheck">
+    <view class="dia-content" v-if="dialogCheck1">
+      <view class="icon">
+        <i class="iconfont iconjingshi"></i>
+      </view>
+      <view class="des1">{{ t('ImproveImmediately.Content.Leave1') }}</view>
+      <view class="des2">{{ t('ImproveImmediately.Content.Leave2') }}</view>
+      <view class="dialog-footer">
+        <u-button @click="closeDia">{{ t('Btn.TemporarilyNot') }}</u-button>
+        <u-button type="primary" @click="save">{{ t('Btn.Save') }}</u-button>
+      </view>
+    </view>
+    <view class="dia-content" v-if="!dialogCheck1">
+      <view class="icon">
+        <i class="iconfont iconchenggong"></i>
+      </view>
+      <view class="des1">{{ t('ApplicationDialog.Des1') }}</view>
+      <QrCode :text="text1"></QrCode>
+      <view class="dialog-footer">
+        <u-button @click="closeDia">{{ t('Btn.Cancel') }}</u-button>
+        <u-button type="primary" @click="toHome">{{ t('Btn.Home') }}</u-button>
+      </view>
+    </view>
+  </uni-popup>
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, onUnmounted, watch, computed } from 'vue'
+  import { useI18n } from 'vue-i18n'
+  import { onLoad } from '@dcloudio/uni-app'
+  import { personalApi } from '@/service/personal'
+  import Config from '@/config/index'
+  import QrCode from '@/components/QRCode.vue'
+  import { userToken } from '@/composables/config'
+  import useRouter from '@/hooks/useRouter'
+  import { Patterns, Validators } from '@/utils/validators'
+  import { pinyin } from 'pinyin-pro'
+  import config from '@/config/index'
+  import icon_doc from '@/static/icons/crm-document.svg'
+  import icon_refresh from '@/static/icons/crm-refresh.svg'
+
+  const router = useRouter()
+  const { t } = useI18n()
+  const currentStep = ref<number>(3)
+  const formRef = ref()
+  const lang = ref('cn')
+  const dialogCheck = ref(false)
+  const dialogCheck1 = ref(false)
+  const text1 = ref('')
+  const qrCodeStatus = ref(false)
+  const addressTipPopup = ref()
+
+  // 新增的响应式数据
+  const divActiveHelf = ref(false)
+  const divActiveAll = ref(false)
+  const websock = ref(null)
+  const isPC = ref(true)
+  const fileListID1 = ref({ againPath: '', id: null, path: '', status: null, type: null })
+  const fileListID2 = ref({ againPath: '', id: null, path: '', status: null, type: null })
+  const fileListAdd1 = ref({ againPath: '', id: null, path: '', status: null, type: null })
+  const fileListAdd2 = ref({ againPath: '', id: null, path: '', status: null, type: null })
+  const fileListOthers = ref([])
+  const actionID1 = ref('')
+  const actionID2 = ref('')
+  const actionAdd1 = ref('')
+  const actionAdd2 = ref('')
+  const actionOtherAdd = ref('')
+  const flag = ref(false)
+  const pictLoading = ref(false)
+  const pictLoadingImg = ref(false)
+  const isApprove = ref(false)
+  const metaInfo = ref({})
+  const HostWs = ref(Config.HostWs)
+  const cities = ref([])
+  const states = ref([])
+  const countries = ref([])
+  const uploadImage = ref(0)
+  const updateUrl = config.Host80
+
+  const imageStyle = ref({
+    width: 200,
+    height: 150,
+    border: {
+      radius: '5px',
+    },
+  })
+
+  // 验证函数
+  function validateName(a: any, b?: any, c?: any) {
+    const reg = /^[A-Z\s]+$/i
+    if (typeof c === 'function') {
+      const value = b
+      const callback = c
+      const val = String(value ?? '').trim()
+      if (!val) return callback(new Error(t('card.vaildate.v4')))
+      if (!reg.test(val)) return callback(new Error(t('card.vaildate.v38')))
+      if (val.length < 2 || val.length > 23) return callback(new Error(t('card.vaildate.v39')))
+      const firstName = String(formData.value?.firstName ?? '').trim()
+      const lastName = String(formData.value?.lastName ?? '').trim()
+      if (`${firstName} ${lastName}`.length > 23) return callback(new Error(t('card.vaildate.v40')))
+      return callback()
+    }
+    const val = String(a ?? '').trim()
+    if (!val) return t('card.vaildate.v4')
+    if (!reg.test(val)) return t('card.vaildate.v38')
+    if (val.length < 2 || val.length > 23) return t('card.vaildate.v39')
+    const firstName = String(formData.value?.firstName ?? '').trim()
+    const lastName = String(formData.value?.lastName ?? '').trim()
+    if (`${firstName} ${lastName}`.length > 23) return t('card.vaildate.v40')
+    return true
+  }
+
+  function validateBirthday(a: any, b?: any, c?: any) {
+    if (typeof c === 'function') {
+      const value = b
+      const callback = c
+      const val = value
+      if (!val) return callback(new Error(t('card.vaildate.v5')))
+      const today = new Date()
+      const birthDate = new Date(val)
+      let age = today.getFullYear() - birthDate.getFullYear()
+      const month = today.getMonth() - birthDate.getMonth()
+      if (month < 0 || (month === 0 && today.getDate() < birthDate.getDate())) age--
+      if (age < 18) return callback(new Error(t('card.New.n3')))
+      return callback()
+    }
+    const val = a
+    if (!val) return t('card.vaildate.v5')
+    const today = new Date()
+    const birthDate = new Date(val)
+    let age = today.getFullYear() - birthDate.getFullYear()
+    const month = today.getMonth() - birthDate.getMonth()
+    if (month < 0 || (month === 0 && today.getDate() < birthDate.getDate())) age--
+    return age < 18 ? t('card.New.n3') : true
+  }
+
+  function validateAddress(a: any, b?: any, c?: any) {
+    if (typeof c === 'function') {
+      const value = b
+      const callback = c
+      const val = String(value ?? '').trim()
+      if (!val) return callback(new Error(t('card.vaildate.v27')))
+      if (val.length < 2 || val.length > 40) return callback(new Error(t('card.New.n1')))
+      if (!Patterns.address.test(val)) return callback(new Error(t('card.New.n1')))
+      return callback()
+    }
+    const val = String(a ?? '').trim()
+    if (!val) return t('card.vaildate.v27')
+    if (val.length < 2 || val.length > 40) return t('card.New.n1')
+    return Patterns.address.test(val) ? true : t('card.New.n1')
+  }
+
+  const rules = {
+    customType: [Validators.required(t('card.vaildate.v1'))],
+    firstName: [Validators.required(t('card.vaildate.v3')), Validators.custom(validateName)],
+    lastName: [Validators.required(t('card.vaildate.v4')), Validators.custom(validateName)],
+    nationality: [Validators.required(t('card.vaildate.v6'), 'change')],
+    IdentityType: [Validators.required(t('card.vaildate.v1'))],
+    identity: [Validators.required(t('card.vaildate.v4'))],
+    gender: [Validators.required(t('card.vaildate.v9'), 'change')],
+    birth: [
+      Validators.required(t('card.vaildate.v5'), 'change'),
+      Validators.custom(validateBirthday, 'change'),
+    ],
+    country: [Validators.required(t('card.vaildate.v1'))],
+    state: [Validators.required(t('card.vaildate.v1'))],
+    city: [Validators.required(t('card.vaildate.v1'))],
+    addressLines1: [Validators.required(t('card.vaildate.v27')), Validators.custom(validateAddress)],
+    zipCode: [
+      Validators.required(t('card.vaildate.v8')),
+      Validators.pattern(Patterns.postcode, t('card.New.n2')),
+    ],
+    level: [Validators.required(t('card.vaildate.v1'))],
+    employmentStatus: [Validators.required(t('card.vaildate.v1'))],
+    tradingObjectives: [Validators.required(t('card.vaildate.v1'))],
+    sourceFunding: [Validators.required(t('card.vaildate.v1'))],
+    grossAnnualIncome: [Validators.required(t('card.vaildate.v1'))],
+    totalNewWorth: [Validators.required(t('card.vaildate.v1'))],
+    cardType: [Validators.required(t('card.vaildate.v1'))],
+    idFrontUrl: [Validators.required(t('card.vaildate.v1'))],
+    idBackUrl: [Validators.required(t('card.vaildate.v1'))],
+    addressProofUrl: [Validators.required(t('card.vaildate.v1'))],
+  }
+
+  onLoad((options) => {
+    currentStep.value = parseInt(options?.currentStep || '3', 10)
+  })
+
+  function goStep(step: number) {
+    currentStep.value = step
+  }
+
+  // 选项数据
+  const customerTypeOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.CustomerType1') },
+    { value: 2, text: t('ImproveImmediately.Label.CustomerType2') },
+  ]
+
+  const identityTypes = ref([
+    { text: t('ImproveImmediately.Label.IDCard'), value: 2 },
+    { text: t('ImproveImmediately.Label.Passport'), value: 3 },
+  ])
+
+  const genderOptions = [
+    { value: 1, text: t('PersonalManagement.Label.Men') },
+    { value: 2, text: t('PersonalManagement.Label.Women') },
+  ]
+  const radioList = [
+    { value: 1, text: t('ImproveImmediately.Label.Yes') },
+    { value: 0, text: t('ImproveImmediately.Label.No') },
+  ]
+
+  const educationOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.Education1') },
+    { value: 2, text: t('ImproveImmediately.Label.Education2') },
+    { value: 3, text: t('ImproveImmediately.Label.Education3') },
+    { value: 4, text: t('ImproveImmediately.Label.Education4') },
+    { value: 5, text: t('ImproveImmediately.Label.Education5') },
+  ]
+
+  const employmentOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.OnJob1') },
+    { value: 2, text: t('ImproveImmediately.Label.OnJob2') },
+    { value: 3, text: t('ImproveImmediately.Label.OnJob3') },
+    { value: 4, text: t('ImproveImmediately.Label.OnJob4') },
+    { value: 5, text: t('ImproveImmediately.Label.OnJob5') },
+  ]
+
+  const transactionPurposeOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.purposeTransaction1') },
+    { value: 2, text: t('ImproveImmediately.Label.purposeTransaction2') },
+    { value: 3, text: t('ImproveImmediately.Label.purposeTransaction3') },
+    { value: 4, text: t('ImproveImmediately.Label.purposeTransaction4') },
+  ]
+
+  const fundSourceOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.SourceFunds1') },
+    { value: 2, text: t('ImproveImmediately.Label.SourceFunds2') },
+    { value: 3, text: t('ImproveImmediately.Label.SourceFunds3') },
+    { value: 4, text: t('ImproveImmediately.Label.SourceFunds4') },
+    { value: 5, text: t('ImproveImmediately.Label.SourceFunds5') },
+    { value: 6, text: t('ImproveImmediately.Label.SourceFunds6') },
+  ]
+
+  const annualIncomeOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.TotalAnnualRevenue1') },
+    { value: 2, text: t('ImproveImmediately.Label.TotalAnnualRevenue2') },
+    { value: 3, text: t('ImproveImmediately.Label.TotalAnnualRevenue3') },
+    { value: 4, text: t('ImproveImmediately.Label.TotalAnnualRevenue4') },
+    { value: 5, text: t('ImproveImmediately.Label.TotalAnnualRevenue5') },
+  ]
+
+  const netWorthOptions = [
+    { value: 1, text: t('ImproveImmediately.Label.TotalNetAssets1') },
+    { value: 2, text: t('ImproveImmediately.Label.TotalNetAssets2') },
+    { value: 3, text: t('ImproveImmediately.Label.TotalNetAssets3') },
+    { value: 4, text: t('ImproveImmediately.Label.TotalNetAssets4') },
+    { value: 5, text: t('ImproveImmediately.Label.TotalNetAssets5') },
+  ]
+
+  const cardTypeOptions = [
+    { value: 'ID_CARD', text: 'ID Card' },
+    { value: 'PASSPORT', text: 'Passport' },
+    { value: 'DRIVERS', text: 'Driver\'s License' },
+    { value: 'RESIDENCE_PERMIT', text: 'Residence Permit' },
+  ]
+
+  // 表单数据
+  const formData = ref({
+    customType: 1,
+    companyName: undefined,
+    lastName: undefined,
+    firstName: undefined,
+    middle: undefined,
+    nationality: undefined,
+    IdentityType: 1,
+    identity: undefined,
+    nameEn: undefined,
+    gender: undefined,
+    birth: undefined,
+    country: undefined,
+    state: undefined,
+    city: undefined,
+    addressLines1: undefined,
+    addressLines2: undefined,
+    zipCode: undefined,
+    level: undefined,
+    employmentStatus: undefined,
+    tradingObjectives: undefined,
+    sourceFunding: undefined,
+    grossAnnualIncome: undefined,
+    totalNewWorth: undefined,
+    experienceTradingDerivative: 0,
+    experienceTradingForex: 0,
+    derivativeProducts: 0,
+    experienceQualification: 0,
+    cardType: undefined,
+    idFrontUrl: undefined,
+    idBackUrl: undefined,
+    addressProofUrl: undefined,
+    otherFiles: undefined,
+    addressLines: [],
+  })
+
+  // 选项数据
+  const countryOptions = ref<Array<{ text: string; value: string }>>([])
+  const stateOptions = ref<Array<{ text: string; value: string }>>([])
+  const cityOptions = ref<Array<{ text: string; value: string }>>([])
+
+  // 加载状态
+  const loadingStates = ref({
+    next: false,
+    submit: false,
+  })
+
+  // 计算属性
+  const identityLabel = computed(() => {
+    if (formData.value.IdentityType === 2) return t('ImproveImmediately.Label.IDCard')
+    if (formData.value.IdentityType === 3) return t('ImproveImmediately.Label.Passport')
+    return t('ImproveImmediately.Label.IdentityID')
+  })
+
+  // 计算属性:当前选中国籍的 uploadCard 值
+  const currentUploadCard = computed(() => {
+    if (!formData.value.nationality || !countries.value.length) {
+      return 0
+    }
+    const selectedCountry = countries.value.find(
+      (item: any) => item.code === formData.value.nationality,
+    )
+    return selectedCountry ? (selectedCountry.uploadCard || 0) : 0
+  })
+
+  // 计算属性:当前选中国籍的 uploadAddress 值
+  const currentUploadAddress = computed(() => {
+    if (!formData.value.nationality || !countries.value.length) {
+      return 0
+    }
+    const selectedCountry = countries.value.find(
+      (item: any) => item.code === formData.value.nationality,
+    )
+    return selectedCountry ? (selectedCountry.uploadAddress || 0) : 0
+  })
+
+  // 方法
+  function changeCountry(value: any) {
+    // 处理国家选择变化
+    // 清空省份/城市选择//
+    formData.value.state = ''
+    formData.value.city = ''
+    stateOptions.value = []
+    cityOptions.value = []
+    states.value = []
+    cities.value = []
+    let item = {}
+    countries.value.forEach(element => {
+      if (element.code == value) {
+        item = element
+        return
+      }
+    })
+    getStateList(item.id)
+  }
+
+  function handleFileUpdate(value, type) {
+    console.log(value, type, 'uplaod')
+  }
+
+  function changeState(val) {
+    formData.value.city = ''
+    cityOptions.value = []
+    let item = {}
+    states.value.forEach((element) => {
+      if (element.name == val || element.enName == val) {
+        item = element
+        return
+      }
+    })
+    getCityList(item.id)
+  }
+
+  function handleChange(value: any) {
+    formData.value = { ...formData.value, [value.key]: value.value }
+    console.log(value)
+    if (value.key === 'country') {
+      formData.value.state = ''
+      formData.value.city = ''
+      stateOptions.value = []
+      cityOptions.value = []
+      if (value.value) {
+        getStateList(value.value)
+      }
+    } else if (value.key === 'state') {
+      formData.value.city = ''
+      cityOptions.value = []
+      if (value.value) {
+        getCityList(value.value)
+      }
+    }
+  }
+
+  function openAddressTip() {
+    // 打开地址提示弹窗
+    addressTipPopup.value.open()
+  }
+
+  function isPdf(url, image) {
+    let res = !!url
+    if (image) {
+      return res && url.substr(-3, 3) == 'pdf' &&
+        url.substr(-3, 3) == 'PDF'
+    }
+    return res && (url.substr(-3, 3) == 'pdf' ||
+      url.substr(-3, 3) == 'PDF')
+  }
+
+  function cancle() {
+    if (!isApprove.value) {
+      dialogCheck.value = true
+      dialogCheck1.value = true
+    } else {
+      router.push({ path: '/customer/index' })
+    }
+  }
+
+  function closeDia() {
+    dialogCheck.value = false
+  }
+
+  function toHome() {
+    dialogCheck.value = false
+    router.push({ path: '/customer/index' })
+  }
+
+  async function save() {
+    await updateInfo(1)
+  }
+
+  async function Submit() {
+    loadingStates.value.submit = true
+    try {
+      formData.value.addressLines = []
+      if (formData.value.addressLines1) {
+        formData.value.addressLines.push(formData.value.addressLines1)
+      }
+      if (formData.value.addressLines2) {
+        formData.value.addressLines.push(formData.value.addressLines2)
+      }
+      if (!formData.value.addressLines1 && !formData.value.addressLines2) {
+        formData.value.addressLines = []
+      }
+      if (formData.value.customType != 2) {
+        formData.value.companyName = ''
+      }
+      let res = await personalApi.CustomUpdateInfo({
+        ...formData.value,
+      })
+      if (res.code == Config.Code.StatusOK) {
+        await getCustomFileList()
+        await customApply()
+      } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    } finally {
+      loadingStates.value.submit = false
+    }
+  }
+
+  async function updateInfo(save: number) {
+    try {
+      formData.value.addressLines = []
+      if (formData.value.addressLines1) {
+        formData.value.addressLines.push(formData.value.addressLines1)
+      }
+      if (formData.value.addressLines2) {
+        formData.value.addressLines.push(formData.value.addressLines2)
+      }
+      if (!formData.value.addressLines1 && !formData.value.addressLines2) {
+        formData.value.addressLines = []
+      }
+      let res = await personalApi.CustomUpdateInfo({
+        ...formData.value,
+      })
+      if (res.code == Config.Code.StatusOK) {
+        if (save) {
+          dialogCheck.value = false
+          router.push({ path: '/customer/index' })
+        }
+      } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  async function customApply() {
+    try {
+      let res = await personalApi.customApplyReal({})
+      if (res.code == Config.Code.StatusOK) {
+        isApprove.value = true
+        await getLoginInfo()
+        dialogCheck.value = true
+        dialogCheck1.value = false
+      } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  async function getCountryList() {
+    try {
+      let res = await personalApi.Country({})
+      if (res.code == Config.Code.StatusOK) {
+        countryOptions.value = res.data.map((item: any) => ({
+          text: item.enName,
+          value: item.code,
+        }))
+        countries.value = res.data
+        const country = formData.value.country
+        if (country) {
+          countries.value.forEach((item) => {
+            if (item.code == country) {
+              getStateList(item.id)
+            }
+          })
+        }
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  async function getStateList(pid: string) {
+    try {
+      let res = await personalApi.Country({ pid })
+      if (res.code == Config.Code.StatusOK) {
+        stateOptions.value = res.data.map((item: any) => ({
+          text: lang.value === 'en' ? item.enName : item.name,
+          value: lang.value === 'en' ? item.enName : item.name,
+        }))
+        states.value = res.data
+        const state = formData.value.state
+        if (state) {
+          states.value.forEach((item) => {
+            if (
+              item.name == state ||
+              item.enName == state
+            ) {
+              getCityList(item.id)
+            }
+          })
+        }
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  async function getCityList(pid: string) {
+    try {
+      let res = await personalApi.Country({ pid })
+      if (res.code == Config.Code.StatusOK) {
+        cityOptions.value = res.data.map((item: any) => ({
+          text: lang.value === 'en' ? item.enName : item.name,
+          value: lang.value === 'en' ? item.enName : item.name,
+        }))
+        cities.value = res.data
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  async function getLoginInfo() {
+    try {
+      let res = await personalApi.CustomLoginInfo()
+      if (res.code == Config.Code.StatusOK) {
+        formData.value = res.data.customInfo
+        if (formData.value.addressLines != null && formData.value.addressLines.length) {
+          formData.value.addressLines1 = formData.value.addressLines[0]
+          formData.value.addressLines2 = formData.value.addressLines[1]
+        }
+        formData.value.customType = formData.value.customType ? formData.value.customType : 1
+        await getCountryList()
+      } else {
+        uni.showToast({ title: t('Msg.SystemError'), icon: 'none' })
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  // 获取二维码
+  async function getMobileInfo() {
+    try {
+      let res = await personalApi.CustomFileMobileFiles({
+        responseType: 'arraybuffer',
+      })
+      // console.log(res);
+      const mobile = 'data:image/png;base64,' + Buffer.from(res).toString('base64')
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  // 获取上传文件信息
+  async function getCustomFileList() {
+    try {
+      let res = await personalApi.CustomFileList()
+      if (res.code == Config.Code.StatusOK) {
+        let myData = res.data
+        fileListOthers.value = []
+        myData.forEach((item: any) => {
+          if (item.type == 1) {
+            fileListID1.value = item
+          } else if (item.type == 2) {
+            fileListID2.value = item
+          } else if (item.type == 3) {
+            fileListAdd1.value = item
+          } else if (item.type == 4) {
+            fileListAdd2.value = item
+          } else if (item.type == 10) {
+            fileListOthers.value.push(item)
+          }
+        })
+        actionType()
+      } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+        flag.value = false
+      }
+    } catch (error: any) {
+      uni.showToast({ title: error.message || t('Msg.SystemError'), icon: 'none' })
+    }
+  }
+
+  // 请求头
+  function actionType() {
+    if (fileListID1.value.id) {
+      actionID1.value = Config.Host80 + '/custom/file/upload/1/' + fileListID1.value.id
+    } else {
+      actionID1.value = Config.Host80 + '/custom/file/upload/1'
+    }
+    if (fileListID2.value.id) {
+      actionID2.value = Config.Host80 + '/custom/file/upload/2/' + fileListID2.value.id
+    } else {
+      actionID2.value = Config.Host80 + '/custom/file/upload/2'
+    }
+    if (fileListAdd1.value.id) {
+      actionAdd1.value = Config.Host80 + '/custom/file/upload/3/' + fileListAdd1.value.id
+    } else {
+      actionAdd1.value = Config.Host80 + '/custom/file/upload/3'
+    }
+    if (fileListAdd2.value.id) {
+      actionAdd2.value = Config.Host80 + '/custom/file/upload/4/' + fileListAdd2.value.id
+    } else {
+      actionAdd2.value = Config.Host80 + '/custom/file/upload/4'
+    }
+    actionOtherAdd.value = Config.Host80 + '/custom/file/upload/10'
+  }
+
+  // WebSocket
+  function initWebSocket() {
+    // 初始化WebSocket
+    let token = localStorage.getItem('access_token')
+    if (typeof WebSocket == 'undefined') {
+      uni.showToast({ title: t('Msg.socket'), icon: 'none' })
+    } else {
+      const wsUrl = HostWs.value + '/webSocket?Access-Token=' + token
+      websock.value = new WebSocket(wsUrl)
+      websock.value.onmessage = websocketonmessage
+      websock.value.onopen = websocketonopen
+      websock.value.onerror = websocketonerror
+      websock.value.onclose = websocketclose
+    }
+  }
+
+  function websocketonopen() {
+  }
+
+  function websocketonerror() {
+    initWebSocket()
+  }
+
+  function websocketonmessage(e: any) {
+    let data = JSON.parse(e.data)
+    if (data.newsType == 1) {
+      let myData = JSON.parse(e.data)
+      if (myData.type == 1) {
+        fileListID1.value = myData
+      } else if (myData.type == 2) {
+        fileListID2.value = myData
+      } else if (myData.type == 3) {
+        fileListAdd1.value = myData
+      } else if (myData.type == 4) {
+        fileListAdd2.value = myData
+      } else if (myData.type == 10) {
+        if (!fileListOthers.value.length) {
+          fileListOthers.value.push(myData)
+        } else {
+          let flag = true
+          fileListOthers.value.forEach((item: any) => {
+            if (item.id == myData.id) {
+              item = myData
+              flag = false
+            }
+          })
+          if (flag) {
+            fileListOthers.value.push(myData)
+          }
+        }
+      }
+      actionType()
+    }
+  }
+
+  function websocketclose() {
+  }
+
+  // 判断是否为PC端
+  function IsPC() {
+    let userAgentInfo = navigator.userAgent
+    let Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']
+    let flag = true
+    for (let v = 0; v < Agents.length; v++) {
+      if (userAgentInfo.indexOf(Agents[v]) > 0) {
+        flag = false
+        break
+      }
+    }
+    return flag
+  }
+
+  // div大小改变重载
+  function divInit() {
+    // 由于elementResizeDetectorMaker在UniApp中可能不可用,这里简化处理
+    const width = window.innerWidth
+    if (width <= 1100 && width > 800) {
+      divActiveHelf.value = true
+      divActiveAll.value = false
+    } else if (width <= 800) {
+      divActiveAll.value = true
+      divActiveHelf.value = false
+    } else if (1100 < width) {
+      divActiveAll.value = false
+      divActiveHelf.value = false
+    }
+  }
+
+  // 监听表单字段变化
+  watch(
+    () => formData.value.firstName,
+    () => {
+      if (localStorage.getItem('lang') == 'cn' && formData.value.firstName && formData.value.lastName) {
+        formData.value.nameEn = pinyin(`${formData.value.firstName} ${formData.value.lastName}`)
+        pinyin
+      }
+    },
+  )
+
+  watch(
+    () => formData.value.lastName,
+    () => {
+      if (localStorage.getItem('lang') == 'cn' && formData.value.firstName && formData.value.lastName) {
+        formData.value.nameEn = pinyin(`${formData.value.firstName} ${formData.value.lastName}`, {
+          style: 'first',
+          separator: ' ',
+        }).toUpperCase()
+      }
+    },
+  )
+
+  // 生命周期
+  onMounted(async () => {
+    divInit()
+    await getLoginInfo()
+    await getMobileInfo()
+    await getCustomFileList()
+    // WebSocket
+    initWebSocket()
+    isPC.value = IsPC()
+  })
+
+  // 组件销毁时
+  onUnmounted(() => {
+    if (websock.value) {
+      websock.value.close() // 离开路由之后断开WebSocket连接
+    }
+  })
+</script>
+
+<style scoped lang="scss">
+  @import "@/uni.scss";
+
+  .form-tab {
+    height: px2rpx(100);
+  }
+
+  .form-section {
+    margin: px2rpx(8) 0;
+  }
+
+  .section-title {
+    color: #1a1a1a;
+    font-family: Roboto;
+    font-size: px2rpx(22);
+    font-weight: 500;
+    margin: px2rpx(10) 0;
+  }
+
+  :deep(.file-picker__box) {
+    width: px2rpx(200) !important;
+    height: px2rpx(150) !important;
+  }
+
+  :deep(.uni-file-picker) {
+    width: 100%;
+    height: 100%;
+  }
+
+  .avatar-uploader {
+    border: 1px dashed;
+    width: px2rpx(200);
+    height: px2rpx(150);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    /*float: left;*/
+    //overflow: hidden;
+  }
+
+  .file-item {
+    border: 1px dashed;
+    border-radius: px2rpx(5);
+    width: px2rpx(200);
+    height: px2rpx(150);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .icon {
+      width: px2rpx(24);
+      height: px2rpx(24);
+    }
+  }
+
+  .avatar {
+    width: 100%;
+    height: 100%;
+  }
+
+  .custom-upload-btn {
+    width: px2rpx(200);
+    height: px2rpx(150);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    .plus {
+      font-size: px2rpx(24);
+      color: #9ca3af;
+    }
+  }
+
+  .experience {
+    display: flex;
+    margin: px2rpx(10) 0;
+    align-items: center;
+  }
+
+  .Trad-experience {
+    flex: 1;
+    color: #1a1a1a;
+    font-size: px2rpx(16);
+  }
+
+  .Trad-choose {
+    display: flex;
+  }
+
+  .descending {
+    margin: px2rpx(20) 0;
+    padding: px2rpx(20);
+    background-color: #f5f5f5;
+    border-radius: px2rpx(8);
+  }
+
+  .title {
+    font-weight: 500;
+    margin-bottom: px2rpx(10);
+  }
+
+  .des {
+    margin: px2rpx(5) 0;
+    font-size: px2rpx(14);
+    color: #666;
+  }
+
+  .dian1 {
+    font-size: px2rpx(20);
+    margin-right: px2rpx(5);
+  }
+
+  .dian {
+    margin-right: px2rpx(10);
+  }
+
+  .btns {
+    margin-top: px2rpx(30);
+  }
+
+  .cwg-button {
+    display: flex;
+    flex-direction: column;
+    gap: px2rpx(15);
+
+    &.two-btn {
+      flex-direction: row;
+      justify-content: space-between;
+
+      u-button {
+        flex: 1;
+        margin: 0 px2rpx(10);
+
+        &:first-child {
+          margin-left: 0;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .btn-primary {
+    height: px2rpx(80);
+    font-size: px2rpx(18);
+  }
+
+  .prev-btn {
+    border-color: #4a6cf7;
+    color: #4a6cf7;
+  }
+
+  .crm-title-box {
+    display: flex;
+    align-items: center;
+    margin: px2rpx(20) 0;
+
+    .tit {
+      font-size: px2rpx(18);
+      font-weight: 500;
+      color: #1a1a1a;
+    }
+
+    .icon-tip {
+      margin-left: px2rpx(10);
+      font-size: px2rpx(16);
+      color: #4a6cf7;
+      cursor: pointer;
+    }
+  }
+
+  .popup-content {
+    padding: px2rpx(20);
+    text-align: center;
+  }
+
+  .dia-content {
+    padding: px2rpx(30);
+    text-align: center;
+
+    .icon {
+      margin-bottom: px2rpx(20);
+
+      i {
+        font-size: px2rpx(60);
+        color: #4a6cf7;
+      }
+    }
+
+    .des1 {
+      font-size: px2rpx(18);
+      font-weight: 500;
+      margin-bottom: px2rpx(10);
+    }
+
+    .des2 {
+      font-size: px2rpx(14);
+      color: #666;
+      margin-bottom: px2rpx(30);
+    }
+
+    .dialog-footer {
+      display: flex;
+      justify-content: space-between;
+      margin-top: px2rpx(30);
+
+      u-button {
+        flex: 1;
+        margin: 0 px2rpx(10);
+
+        &:first-child {
+          margin-left: 0;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .cwg-upload {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: px2rpx(40);
+    border: 1px dashed #ddd;
+    border-radius: px2rpx(8);
+    cursor: pointer;
+
+    cwg-icon {
+      font-size: px2rpx(40);
+      margin-bottom: px2rpx(10);
+      color: #999;
+    }
+
+    .name {
+      font-size: px2rpx(16);
+      margin-bottom: px2rpx(5);
+    }
+
+    .back {
+      font-size: px2rpx(12);
+      color: #999;
+    }
+  }
+</style>

+ 1 - 0
static/icons/crm-document.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1774422618227" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2082" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M288 320h448a32 32 0 0 0 0-64H288a32 32 0 0 0 0 64zM288 544h448a32 32 0 0 0 0-64H288a32 32 0 0 0 0 64zM544 704H288a32 32 0 0 0 0 64h256a32 32 0 0 0 0-64z" p-id="2083"></path><path d="M896 132.928C896 77.28 851.552 32 796.928 32H227.04C172.448 32 128 77.28 128 132.928v758.144C128 946.72 172.448 992 227.04 992h435.008c1.568 0 2.912-0.672 4.416-0.896 8.96 1.6 18.464-0.256 25.984-6.528l192-160a31.424 31.424 0 0 0 10.816-27.2c0.16-1.184 0.736-2.208 0.736-3.424V132.928zM192 891.072V132.928C192 112.576 207.712 96 227.04 96h569.888C816.288 96 832 112.576 832 132.928V736h-96a96 96 0 0 0-96 96v96H227.04C207.712 928 192 911.424 192 891.072zM814.016 800L704 891.68V832a32 32 0 0 1 32-32h78.016z" p-id="2084"></path></svg>

+ 1 - 0
static/icons/crm-refresh.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M129.9 292.5C143.2 199.5 223.3 128 320 128C373 128 421 149.5 455.8 184.2C456 184.4 456.2 184.6 456.4 184.8L464 192L416.1 192C398.4 192 384.1 206.3 384.1 224C384.1 241.7 398.4 256 416.1 256L544.1 256C561.8 256 576.1 241.7 576.1 224L576.1 96C576.1 78.3 561.8 64 544.1 64C526.4 64 512.1 78.3 512.1 96L512.1 149.4L500.8 138.7C454.5 92.6 390.5 64 320 64C191 64 84.3 159.4 66.6 283.5C64.1 301 76.2 317.2 93.7 319.7C111.2 322.2 127.4 310 129.9 292.6zM573.4 356.5C575.9 339 563.7 322.8 546.3 320.3C528.9 317.8 512.6 330 510.1 347.4C496.8 440.4 416.7 511.9 320 511.9C267 511.9 219 490.4 184.2 455.7C184 455.5 183.8 455.3 183.6 455.1L176 447.9L223.9 447.9C241.6 447.9 255.9 433.6 255.9 415.9C255.9 398.2 241.6 383.9 223.9 383.9L96 384C87.5 384 79.3 387.4 73.3 393.5C67.3 399.6 63.9 407.7 64 416.3L65 543.3C65.1 561 79.6 575.2 97.3 575C115 574.8 129.2 560.4 129 542.7L128.6 491.2L139.3 501.3C185.6 547.4 249.5 576 320 576C449 576 555.7 480.6 573.4 356.5z"/></svg>

+ 1 - 1
static/scss/global/global.scss

@@ -559,7 +559,7 @@ uni-content {
         font-size: var(--font-size-16);
         font-size: var(--font-size-16);
         font-weight: bold;
         font-weight: bold;
         color: var(--black);
         color: var(--black);
-        background: var(--main-yellow) !important;
+        background-color: var(--color-navy-900) !important;
         border: none !important;
         border: none !important;
         border-radius: px2rpx(100) !important;
         border-radius: px2rpx(100) !important;