From 304f819d3e9b2498ebdb70b99b632cda67725a52 Mon Sep 17 00:00:00 2001
From: 李 <344137771@qq.com>
Date: Sun, 31 May 2026 17:57:32 +0800
Subject: [PATCH] 1

---
 src/views/register/index.vue |  729 +++++++++++++++++++++++++++----------------------------
 1 files changed, 362 insertions(+), 367 deletions(-)

diff --git a/src/views/register/index.vue b/src/views/register/index.vue
index 0649edb..7857eaf 100644
--- a/src/views/register/index.vue
+++ b/src/views/register/index.vue
@@ -1,419 +1,414 @@
 <template>
     <div class="register">
-        <div class="top flex justify-between items-center">
-            <img src="../../assets/image/icon-close.png" alt="" @click="router.go(-1)">
-            <div @click="onRoute('/customerService')">{{ $t('onLineService') }}</div>
-        </div>
-        <!-- <Step :step="1"></Step> -->
-        <div class="title textColor">{{ $t('register') }}</div>
-        <div class="flex re-tab">
-            <!-- <div class="textColor1" :class="activeIndex == 0 ? 'active' : ''" @click="changeIndex(0)">{{
-                $t('account')
-            }}</div> -->
-            <div class="textColor1" :class="activeIndex == 1 ? 'active' : ''" @click="changeIndex(1)">{{ $t('email') }}
+        <div class="reg-inner">
+            <div class="reg-back" @click="router.go(-1)">
+                <van-icon name="arrow-left" size="22" />
             </div>
-            <div class="textColor1" :class="activeIndex == 2 ? 'active' : ''" @click="changeIndex(2)">{{
-                $t('phoneNum')
-                }}</div>
-        </div>
-        <ExInput :label="getRegType(activeIndex, true)" :placeholderText="getRegType(activeIndex, false)"
-            v-model="username" :area="isArea" :dialCode="dialCode" @selectArea="onSelectArea" :icon="icon" />
 
-        <ExInput :label="$t('setPassword')" :placeholderText="$t('passwordTips')" v-model="password"
-            typeText="password" />
-        <ExInput :label="$t('repassword')" :placeholderText="$t('surePassword')" v-model="repassword"
-            typeText="password" />
-        <ExInput :label="$t('setSafeword')" :placeholderText="$t('safewordTips')" v-model="safeword" typeText="password"
-            v-if="activeIndex === 1 || activeIndex === 2" />
-        <div class="inputCom" v-if="activeIndex === 1 || activeIndex === 2">
-            <p class="label  textColor">{{ $t('验证码') }}</p>
-            <div class="iptbox inputBackground">
-                <input class="inputBackground textColor" type="text" :placeholder="$t('entryVerifyCode')"
-                    v-model="verifyCode">
-                <span v-if="type !== 3" @click="senCode">{{ $t('sendVerifyCode') }}
-                    <template v-if="time">({{ time }})s</template>
+            <div class="reg-logo-wrap">
+                <img :src="LOGO" alt="" class="reg-logo" />
+            </div>
+            <h1 class="reg-title">{{ $t('register') }}</h1>
+            <p class="reg-login">
+                {{ $t('hasAccount') }}
+                <span class="reg-login-link" @click="router.push('/login')">{{ $t('goLogin') }}</span>
+            </p>
+            <p class="reg-lang" @click="onRoute('/language')">{{ currentLocaleLabel }}</p>
+
+            <!-- Email -->
+            <div class="reg-field">
+                <input
+                    v-model="username"
+                    type="text"
+                    class="reg-input"
+                    :placeholder="$t('entryEmail')"
+                    autocomplete="email"
+                />
+            </div>
+            <!-- Verification Code -->
+            <div class="reg-field reg-field-code">
+                <input
+                    v-model="verifyCode"
+                    type="text"
+                    class="reg-input"
+                    :placeholder="$t('entryVerifyCode')"
+                    maxlength="6"
+                />
+                <span class="reg-send-code" @click="senCode">
+                    {{ time > 0 ? `(${time})s` : $t('sendVerifyCode') }}
                 </span>
             </div>
-        </div>
-        <ExInput :label="$t('金融机构代码')" :placeholderText="$t('请输入')" v-model="invitCode" :clearBtn="false" />
-        <div class="protocol textColor">
-            <i @click="agreeProt">
-                <img v-show="agree" src="../../assets/image/login/prot2.png" alt="" />
-                <img v-show="!agree" src="../../assets/image/login/prot1.png" alt="" />
-            </i>
-            <!-- {{ $t('readAgree') }}<span class="colorMain" @click="router.push('/TermsOfService')">{{
-                $t('serviceConf')
-                }}</span> -->
-            {{ $t('readAgree') }}<span class="colorMain" @click="router.push('/aboutUs?serviceTerm=23')">{{
-                $t('serviceConf')
-            }}</span>
-        </div>
-        <van-button class="w-full" style="margin-top:10px;" type="primary" @click="register">{{ $t('register') }}
-        </van-button>
-        <div class="noTips textColor">{{ $t('hasAccount') }}<span class="colorMain" @click="router.push('/login')">
-                {{ $t('goLogin') }}</span>
-        </div>
-        <nationality-list ref='controlChildRef' :title="$t('selectArea')" @getName="getName"></nationality-list>
+            <!-- Password -->
+            <div class="reg-field reg-field-pwd">
+                <input
+                    v-model="password"
+                    :type="pwdVisible ? 'text' : 'password'"
+                    class="reg-input"
+                    :placeholder="$t('entryPassword')"
+                    autocomplete="new-password"
+                />
+                <span class="reg-eye" @click="pwdVisible = !pwdVisible">
+                    <van-icon :name="pwdVisible ? 'eye-o' : 'closed-eye'" size="20" />
+                </span>
+            </div>
+            <!-- Confirm Password -->
+            <div class="reg-field reg-field-pwd">
+                <input
+                    v-model="repassword"
+                    :type="repwdVisible ? 'text' : 'password'"
+                    class="reg-input"
+                    :placeholder="$t('surePassword')"
+                    autocomplete="new-password"
+                />
+                <span class="reg-eye" @click="repwdVisible = !repwdVisible">
+                    <van-icon :name="repwdVisible ? 'eye-o' : 'closed-eye'" size="20" />
+                </span>
+            </div>
+            <!-- Referral Code -->
+            <div class="reg-field">
+                <input
+                    v-model="invitCode"
+                    type="text"
+                    class="reg-input"
+                    :placeholder="$t('entryInvitCode')"
+                />
+            </div>
 
-        <Vcode :imgs="[img1, img2]" :show="show" @success="onSuccess" :canvasHeight="200" @fail="onFail"
-            @close="show = false;" sliderText='' :successText="$t('vertifyPass')" :failText="$t('vertifuFail')" />
+            <div class="reg-protocol">
+                <span class="reg-protocol-check" :class="{ checked: agree }" @click="agree = !agree"></span>
+                <span>{{ $t('readAgree') }}</span>
+                <span class="reg-protocol-link" @click.stop="router.push('/aboutUs?serviceTerm=23')">{{ $t('serviceConf') }}</span>
+            </div>
 
-        <div>{{ msg }}</div>
+            <button class="reg-btn reg-btn-primary" @click="register">{{ $t('register') }}</button>
+        </div>
+
+        <nationality-list ref="controlChildRef" :title="$t('selectArea')" @getName="getName" />
     </div>
 </template>
 
 <script setup>
-import ExInput from "@/components/ex-input/index.vue";
-import Step from "./step.vue";
-import { _registerUser, _sendVerifyCode } from "@/service/login.api";
+import { _sendVerifyCode } from "@/service/login.api";
 import { _bindEmailRegister } from "@/service/user.api.js";
 import { useUserStore } from '@/store/user';
-import { GET_USERINFO } from '@/store/types.store'
-import nationalityList from '../authentication/components/nationalityList.vue'
-import Vcode from "vue3-puzzle-vcode";
-import img1 from "../../assets/image/slider/1.png";
-import img2 from "../../assets/image/slider/2.png";
-import { getStorage } from '@/utils/index'
-import { useI18n } from 'vue-i18n'
-import { customerServiceUrl } from "@/config";
+import { GET_USERINFO } from '@/store/types.store';
+import nationalityList from '../authentication/components/nationalityList.vue';
+import { getStorage } from '@/utils/index';
+import { useI18n } from 'vue-i18n';
+import { LOGO } from "@/config";
 import { useRouter } from 'vue-router';
-import { ref, onMounted, reactive, onUnmounted } from 'vue';
+import { ref, computed, onMounted, onUnmounted, reactive } from 'vue';
 import { showToast } from "vant";
-import store from '@/store/store'
-const customer_service_url = ref(customerServiceUrl) // 客服链接,有值的话就会跳转到客服外链
-const { t } = useI18n()
-const router = useRouter()
-const onRoute = (path) => {
-    if (path == 'back') {
-        router.go(-1)
-    } else {
-        if (path == '/customerService') {
-            if (customer_service_url.value) {
-                window.location.href = customer_service_url.value;
-            } else {
-                router.push(path)
-            }
-        } else {
-            router.push(path)
-        }
-    }
-}
+import store from '@/store/store';
+
+const { t, locale } = useI18n();
+const router = useRouter();
 const userStore = useUserStore();
 
-let show = ref(false)
-const msg = ref('')
-const type = ref(1)
-const time = ref(0)
-let agree = ref(false)
-const username = ref('')
-const password = ref('')
-const repassword = ref('')
-const verifyCode = ref('')
-const safeword = ref('')
-const fundPassword = ref('')
-const refundPassword = ref('')
-const activeIndex = ref(1)
-const typeText = ref('password')
-let isArea = ref(false)
-let dialCode = ref(0)
-let icon = ref('')
-const state = reactive({
-    timer: null
-})
+const localeLabels = { en: 'English', cn: '中文', Korean: '한국인', Japanese: 'やまと', de: 'Deutsch', French: 'Français', Italy: 'Italiano' };
+const currentLocaleLabel = computed(() => localeLabels[locale.value] || locale.value || 'English');
 
-let invitCode = ref('')
+const username = ref('');
+const password = ref('');
+const agree = ref(false);
+const repassword = ref('');
+const verifyCode = ref('');
+const invitCode = ref('');
+const pwdVisible = ref(false);
+const repwdVisible = ref(false);
+const time = ref(0);
+const dialCode = ref(0);
+const icon = ref('');
+const controlChildRef = ref(null);
+const state = reactive({ timer: null });
+
 onMounted(() => {
-    console.log(store)
-    let usercode = getStorage('usercode')
-    if (usercode) {
-        invitCode = usercode;
-    }
-    clearInterval(state.timer)
-    state.timer = null
-})
-
+    const usercode = getStorage('usercode');
+    if (usercode) invitCode.value = usercode;
+});
 onUnmounted(() => {
-    clearInterval(state.timer)
-    state.timer = null
-})
+    if (state.timer) clearInterval(state.timer);
+});
 
-const getRegType = (activeIndex, bFlag) => {
-    switch (activeIndex) {
-        case 0:
-            return bFlag ? t('account') : t('entryAccount');
-        case 1:
-            return bFlag ? t('email') : t('entryEmail');
-        case 2:
-            return bFlag ? t('phoneNum') : t('entryPhone');
-    }
-}
+const onRoute = (path) => {
+    router.push(path);
+};
 
 const senCode = () => {
-    if (time.value > 0) {
-        return false
+    if (time.value > 0) return;
+    const email = username.value.trim();
+    if (!email || !/@/.test(email)) {
+        showToast(t('entryCorrectEmail'));
+        return;
     }
-    _sendVerifyCode({
-        target: activeIndex.value === 1 ? username.value : dialCode.value + username.value,
-    }).then((res) => {
+    _sendVerifyCode({ target: email }).then(() => {
         time.value = 30;
         state.timer = setInterval(() => {
-            if (time.value > 0) {
-                time.value = time.value - 1
-            } else {
-                time.value = 0;
-                clearInterval(state.timer)
-                state.timer = null
+            if (time.value > 0) time.value--;
+            else {
+                clearInterval(state.timer);
+                state.timer = null;
             }
         }, 1000);
-    }).catch((error) => {
-        showToast(t(error.msg));
+    }).catch((err) => {
+        showToast(err?.msg || t('sendVerifyCode'));
     });
-}
+};
 
-const onSuccess = () => {
-    console.log('onSuccess')
+const validatePassword = (pwd) => {
+    return /^(?=.*[A-Z])(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,16}$/.test(pwd);
+};
+
+const register = () => {
+    const email = username.value.trim();
+    if (!email || !/@/.test(email)) {
+        showToast(t('entryCorrectEmail'));
+        return;
+    }
+    if (!verifyCode.value || verifyCode.value.length < 6) {
+        showToast(t('entryVerifyTips'));
+        return;
+    }
+    if (!password.value) {
+        showToast(t('entryPassword'));
+        return;
+    }
+    if (!password.value || password.value.length < 6 || password.value.length > 16) {
+        showToast(t('passwordTips'));
+        return;
+    }
+    if (repassword.value !== password.value) {
+        showToast(t('noSamePassword'));
+        return;
+    }
+    if (!invitCode.value.trim()) {
+        showToast(t('请输入邀请码'));
+        return;
+    }
+    if (!agree.value) {
+        showToast(t('agreeServiceCond'));
+        return;
+    }
     registerApi();
-    show.value = false;
-}
-const onFail = () => {
-    msg.value = ''
-}
-const onRefresh = () => {
-    msg.value = ''
-}
+};
 
-const controlChildRef = ref(null)
-const onSelectArea = () => {
-    controlChildRef.value.open();
-}
+const registerApi = () => {
+    _bindEmailRegister({
+        username: username.value.trim(),
+        password: password.value,
+        type: '2',
+        verifcode: verifyCode.value,
+        usercode: invitCode.value.trim(),
+        safeword: password.value
+    }).then((res) => {
+        userStore[GET_USERINFO](res);
+        store.state.user.userInfo = res;
+        router.push('/login');
+    }).catch((err) => {
+        showToast(err);
+    });
+};
+
+const onDownloadApp = () => {
+    // 可配置 APP 下载链接
+    const url = 'https://your-app-download-url.com';
+    if (url && (url.startsWith('http://') || url.startsWith('https://'))) {
+        window.open(url, '_blank');
+    } else {
+        showToast(t('downloadAPP'));
+    }
+};
 
 const getName = (params) => {
     icon.value = params.code;
     dialCode.value = params.dialCode;
-}
-const agreeProt = () => {
-    agree.value = !agree.value
-}
-const register = () => {
-    console.log(activeIndex.value, 'activeIndex.value')
-    if (activeIndex.value == 0) {
-        if (username.value == '') {
-            showToast(t('entryAccount'));
-            return
-        }
-        if (username.value.length < 6 || username.value.length > 30) {
-            showToast(t('accountLength'));
-            return
-        }
-    } else if (activeIndex.value == 1) {
-        let match = username.value.search(/@/);
-        if (username.value == '' || match.value == -1) {
-            showToast(t('entryCorrectEmail'));
-            return
-        }
-        if (safeword.value == '') {
-            showToast(t('safewordTips'));
-            return
-        }
-        if (verifyCode.value.length < 6) {
-            showToast(t('entryVerifyTips'));
-            return
-        }
-    } else if (activeIndex.value == 2) {
-        if (!(/(^[1-9]\d*$)/.test(username.value))) {
-            showToast(t('entryPhone'));
-            return
-        }
-        if (username.value == '') {
-            showToast(t('entryPhone'));
-            return
-        }
-    }
-    if (password.value == '') {
-        showToast(t('entryPassword'));
-        return
-    }
-    if (password.value.length < 6) {
-        showToast(t('passwordTips'));
-        return
-    }
-    if (repassword.value !== password.value) {
-        showToast(t('noSamePassword'));
-        return
-    }
-    if (!agree.value) {
-        showToast(t('agreeServiceCond'));
-        return
-    }
-    show.value = true
-}
-const changeIndex = (index) => {
-    activeIndex.value = index;
-    if (index == 0 || index == 1) {
-        isArea.value = false
-    } else {
-        isArea.value = true
-    }
-}
-const registerApi = () => {
-    switch (activeIndex.value) {
-        case 0:
-            {
-                type.value = 3;
-                break;
-            }
-        case 1:
-            {
-                type.value = 2;
-                break;
-            }
-        case 2:
-            {
-                type.value = 1;
-                break;
-            }
-    }
-
-    if (activeIndex.value === 1 || activeIndex.value === 2) {
-        _bindEmailRegister({
-            username: activeIndex.value === 1 ? username.value : dialCode.value + username.value,
-            password: password.value,
-            type: activeIndex.value === 1 ? '2' : '1',   // 2邮箱,1手机
-            verifcode: verifyCode.value,
-            usercode: invitCode.value,
-            safeword: safeword.value
-        }).then((res) => {
-            userStore[GET_USERINFO](res)
-            store.state.user.userInfo = res
-            // 其他操作??
-            // router.push('/identity')
-            router.push('/login')
-        })
-    } else {
-        _registerUser({
-            userName: (activeIndex.value === 0 || activeIndex.value === 1) ? username.value : `${dialCode.value}${username.value}`,
-            password: password.value,
-            // re_password: repassword.value,
-            type: type.value,
-            userCode: invitCode.value,
-        }).then((res) => {
-            userStore[GET_USERINFO](res)
-            store.state.user.userInfo = res
-            if (activeIndex.value == 0) {
-                router.push('/setFond')
-            } else {
-                router.push({ name: 'verify', query: { type: activeIndex.value, account: activeIndex.value == 1 ? username.value : `${dialCode.value}${username.value}` } })
-            }
-        });
-    }
-}
+};
 </script>
 
 <style lang="scss" scoped>
-.activeBKClick {
-    &:active {
-        background: $tab_background;
-        opacity: 0.5;
-    }
-}
-
-.activeClick {
-    &:active {
-        background: $mainbgWhiteColor;
-        opacity: 0.5;
-    }
-}
-
 .register {
-    width: 100%;
+    position: relative;
+    min-height: 100vh;
+    background: #fff;
+    padding: 56px 24px 48px;
     box-sizing: border-box;
-    padding: 16px;
-    font-size: 13px;
-    background-color: $mainbgWhiteColor;
 }
-
-.top {
-    padding-left: 9px;
-    padding-top: 9px;
-
-    img {
-        width: 18px;
-        height: 18px;
-    }
-}
-
-.title {
-    font-weight: 700;
-    font-size: 26px;
-    margin-top: 27px;
-    margin-bottom: 33px;
-}
-
-.re-tab {
-    margin-bottom: 22px;
-
-    div {
-        padding: 0 18px;
-        height: 34px;
-        line-height: 34px;
-        text-align: center;
-        border-radius: 4px;
-        margin-right: 10px;
-    }
-
-    .active {
-        // background: $US_tabActice_background;
-        background: $bg_yellow;
-        // color: $color_main;
-        color: $text_color4;
-    }
-}
-
-.forget {
-    color: $color_main;
-    font-size: 12px;
-    line-height: 14px;
-}
-
-.noTips {
-    margin-top: 24px;
-}
-
-.protocol {
+.reg-inner {
+    max-width: 400px;
+    margin: 0 auto;
     display: flex;
+    flex-direction: column;
     align-items: center;
-    height: 15px;
-
-    i {
-        width: 15px;
-        height: 15px;
-        margin-right: 9px;
-
-        img {
-            width: 100%;
-            height: 100%;
-        }
-    }
 }
 
-.iptbox {
-    height: 44px;
-    margin-top: 8px;
-    margin-bottom: 18px;
-    padding: 0 20px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
+.reg-back {
+    position: absolute;
+    left: 24px;
+    top: 24px;
+    color: #000;
+    cursor: pointer;
+}
+
+.reg-logo-wrap {
+    width: 100px;
+    height: 100%;
     border-radius: 6px;
+    // background: linear-gradient(135deg, #2c1a5c 0%, #5a37a5 100%);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 24px;
+}
+.reg-logo {
+    width: 100%;
+    height: 100%;
+    border-radius: 6px;
+    object-fit: contain;
+}
 
-    input {
-        flex: 1;
-        height: 100%;
-        border: none;
-    }
+.reg-title {
+    font-size: 26px;
+    font-weight: 700;
+    color: #000;
+    margin: 0 0 8px;
+}
+.reg-login {
+    font-size: 14px;
+    color: #4a4a4a;
+    margin: 0 0 6px;
+}
+.reg-login-link {
+    color: #8a2be2;
+    cursor: pointer;
+}
+.reg-lang {
+    font-size: 13px;
+    color: #9b9b9b;
+    margin: 0 0 28px;
+    cursor: pointer;
+}
 
-    span {
-        color: $color_main;
-    }
+/* 输入框:与登录页一致 */
+.reg-field {
+    width: 100%;
+    margin-bottom: 16px;
+    position: relative;
+}
+.reg-field-code {
+    .reg-input { padding-right: 90px; }
+}
+.reg-field-pwd {
+    .reg-input { padding-right: 44px; }
+}
+.reg-input {
+    width: 100%;
+    height: 48px;
+    padding: 0 16px;
+    box-sizing: border-box;
+    font-size: 15px;
+    color: #333;
+    background: #f6f5fa;
+    border: none;
+    border-radius: 6px;
+    outline: none;
+}
+.reg-input::placeholder {
+    color: #9b9b9b;
+}
+.reg-send-code {
+    position: absolute;
+    right: 12px;
+    top: 50%;
+    transform: translateY(-50%);
+    font-size: 14px;
+    color: #8a2be2;
+    cursor: pointer;
+}
+.reg-eye {
+    position: absolute;
+    right: 16px;
+    top: 50%;
+    transform: translateY(-50%);
+    color: #6e6e6e;
+.reg-protocol {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 8px;
+    margin-bottom: 24px;
+    font-size: 13px;
+    color: #4a4a4a;
+}
+.reg-protocol-check {
+    width: 16px;
+    height: 16px;
+    flex-shrink: 0;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    cursor: pointer;
+    background: #fff;
+    display: inline-block;
+}
+.reg-protocol-check.checked {
+    background: #8a2be2;
+    border-color: #8a2be2;
+}
+.reg-protocol-link {
+    color: #8a2be2;
+    cursor: pointer;
+}
+
+    cursor: pointer;
+}
+
+.reg-protocol {
+    width: 100%;
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 8px;
+    margin-bottom: 24px;
+    font-size: 13px;
+    color: #4a4a4a;
+}
+.reg-protocol-check {
+    width: 16px;
+    height: 16px;
+    flex-shrink: 0;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    cursor: pointer;
+    background: #fff;
+    display: inline-block;
+}
+.reg-protocol-check.checked {
+    background: #8a2be2;
+    border-color: #8a2be2;
+}
+.reg-protocol-link {
+    color: #8a2be2;
+    cursor: pointer;
+}
+
+/* 主按钮:渐变,圆角 6px */
+.reg-btn {
+    width: 100%;
+    height: 48px;
+    border: none;
+    border-radius: 6px;
+    font-size: 16px;
+    font-weight: 700;
+    cursor: pointer;
+}
+.reg-btn-primary {
+    background: linear-gradient(90deg, #a443cf, #5e2bc8);
+    color: #fff;
+    margin-bottom: 12px;
+}
+.reg-btn-outline {
+    background: #fff;
+    border: 1px solid #8a2be2;
+    color: #8a2be2;
 }
 </style>

--
Gitblit v1.9.3