Update .gitignore
This commit is contained in:
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
20
index.html
Normal file
20
index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
11386
package-lock.json
generated
Normal file
11386
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
69
package.json
Normal file
69
package.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "uni-preset-vue",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-jd": "uni -p mp-jd",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-harmony": "uni -p mp-harmony",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:mp-xhs": "uni -p mp-xhs",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-jd": "uni build -p mp-jd",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-harmony": "uni build -p mp-harmony",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:mp-xhs": "uni build -p mp-xhs",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-app-harmony": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-components": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-h5": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-harmony": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-ui": "^1.5.10",
|
||||
"vue": "^3.4.21",
|
||||
"vue-i18n": "^9.14.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.4.8",
|
||||
"@dcloudio/uni-automator": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-4070520250711001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-4070520250711001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-4070520250711001",
|
||||
"@vue/runtime-core": "^3.4.21",
|
||||
"sass": "^1.89.2",
|
||||
"vite": "5.2.8"
|
||||
}
|
||||
}
|
||||
10
shims-uni.d.ts
vendored
Normal file
10
shims-uni.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/// <reference types='@dcloudio/types' />
|
||||
import 'vue'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
|
||||
interface ComponentCustomOptions extends Hooks {
|
||||
|
||||
}
|
||||
}
|
||||
17
src/App.vue
Normal file
17
src/App.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export default {
|
||||
onLaunch: function () {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function () {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function () {
|
||||
console.log('App Hide')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
</style>
|
||||
56
src/main.js
Normal file
56
src/main.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
// 导入语言包
|
||||
import en from './static/lang/enUS.json'
|
||||
import cn from './static/lang/zh_CN.json'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
|
||||
// 获取系统语言(适配uni-app环境)
|
||||
const systemInfo = uni.getSystemInfoSync() || {};
|
||||
const systemLanguage = systemInfo.language || 'zh-CN';
|
||||
let curLang = 'cn';
|
||||
|
||||
// 语言判断(转换为小写处理)
|
||||
switch (systemLanguage.toLowerCase()) {
|
||||
case 'en':
|
||||
case 'en-us':
|
||||
curLang = 'en';
|
||||
break;
|
||||
case 'zh':
|
||||
case 'zh-cn':
|
||||
case 'zh-hans':
|
||||
curLang = 'cn';
|
||||
break;
|
||||
}
|
||||
|
||||
// 配置i18n
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: curLang, // 使用检测到的系统语言
|
||||
fallbackLocale: 'en',
|
||||
messages: {
|
||||
en, // 英文语言包
|
||||
cn // 中文语言包
|
||||
},
|
||||
missing: (locale, key) => {
|
||||
console.error(`[i18n] 缺失: '${key}' 在 '${locale}' 语言包中不存在`);
|
||||
return process.env.NODE_ENV === 'development' ? `[缺失: ${key}]` : '';
|
||||
}
|
||||
})
|
||||
|
||||
app.use(i18n)
|
||||
|
||||
return {
|
||||
app,
|
||||
i18n
|
||||
}
|
||||
}
|
||||
|
||||
// 非SSR模式下挂载应用
|
||||
if (!globalThis.__IS_SSR__) {
|
||||
const { app } = createApp()
|
||||
app.mount('#app')
|
||||
}
|
||||
72
src/manifest.json
Normal file
72
src/manifest.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name" : "",
|
||||
"appid" : "",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
}
|
||||
22
src/pages.json
Normal file
22
src/pages.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/register/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
}
|
||||
552
src/pages/login/login.vue
Normal file
552
src/pages/login/login.vue
Normal file
@@ -0,0 +1,552 @@
|
||||
<template>
|
||||
<view class="login-container">
|
||||
<!-- 语言选择文字按钮(点击文字即可弹出窗口) -->
|
||||
<view class="language-text-btn" @click="showLanguageModal = true">
|
||||
<text class="lang-text">{{ $t('login.changelanguage') }}</text>
|
||||
<i class="iconfont icon-arrow-down"></i>
|
||||
</view>
|
||||
|
||||
<!-- 语言选择弹窗 -->
|
||||
<view class="lang-modal" v-if="showLanguageModal">
|
||||
<view class="modal-mask" @click="showLanguageModal = false"></view>
|
||||
<view class="modal-content">
|
||||
<view class="modal-title">{{ $t('login.chooseLanguage') }}</view>
|
||||
<view class="lang-list">
|
||||
<view
|
||||
class="lang-item"
|
||||
@click="changeLanguage('en')"
|
||||
:class="{ 'active': currentLang === 'en' }"
|
||||
>
|
||||
<text>English</text>
|
||||
<i class="iconfont icon-check" v-if="currentLang === 'en'"></i>
|
||||
</view>
|
||||
<view
|
||||
class="lang-item"
|
||||
@click="changeLanguage('cn')"
|
||||
:class="{ 'active': currentLang === 'cn' }"
|
||||
>
|
||||
<text>Chinese</text>
|
||||
<i class="iconfont icon-check" v-if="currentLang === 'cn'"></i>
|
||||
</view>
|
||||
</view>
|
||||
<button class="modal-close" @click="showLanguageModal = false">
|
||||
{{ $t('login.languagechangeclose') }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部标题 -->
|
||||
<view class="login-header">
|
||||
<text class="app-title">{{ $t('login.appTitle') }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="login-form">
|
||||
<!-- 账号输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('login.idCardLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-user"></i>
|
||||
<input
|
||||
type="text"
|
||||
v-model="username"
|
||||
:placeholder="$t('login.usernamePlaceholder')"
|
||||
class="input-field"
|
||||
maxlength="6"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('login.passwordLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-lock"></i>
|
||||
<input
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
v-model="password"
|
||||
:placeholder="$t('login.passwordPlaceholder')"
|
||||
class="input-field"
|
||||
/>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
@click.stop="togglePasswordVisibility"
|
||||
:class="{ active: showPassword }"
|
||||
>
|
||||
<i class="iconfont" :class="showPassword ? 'icon-eye' : 'icon-eye-close'"></i>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 记住密码选项 -->
|
||||
<view class="remember-section">
|
||||
<view class="remember-check">
|
||||
<checkbox
|
||||
v-model="rememberPassword"
|
||||
class="remember-checkbox"
|
||||
color="#007aff"
|
||||
/>
|
||||
<text class="remember-text">{{ $t('login.rememberPassword') }}</text>
|
||||
</view>
|
||||
|
||||
<!-- <text class="forgot-link" @click="handleForgotPassword">
|
||||
{{ $t('login.forgotPassword') }}
|
||||
</text> -->
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view class="error-message" v-if="showError">
|
||||
{{ errorMessage }}
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button
|
||||
class="login-btn"
|
||||
@click="handleLogin"
|
||||
:disabled="isLoading || !agreeTerms"
|
||||
>
|
||||
<template v-if="isLoading">
|
||||
<i class="iconfont icon-loading loading-icon"></i>
|
||||
</template>
|
||||
{{ $t('login.loginButton') }}
|
||||
</button>
|
||||
|
||||
<!-- 协议同意勾选框 -->
|
||||
<view class="agreement-check">
|
||||
<checkbox
|
||||
v-model="agreeTerms"
|
||||
class="agree-checkbox"
|
||||
color="#007aff"
|
||||
/>
|
||||
<text class="agree-text">
|
||||
{{ $t('login.agreeTermsPrefix') }}
|
||||
<text class="link" @click="openAgreement('terms')">{{ $t('login.userAgreement') }}</text>
|
||||
{{ $t('login.and') }}
|
||||
<text class="link" @click="openAgreement('privacy')">{{ $t('login.privacyPolicy') }}</text>
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 注册链接 -->
|
||||
<view class="register-link-section">
|
||||
<text class="register-text">
|
||||
{{ $t('login.noAccount') }}
|
||||
<text class="register-link" @click="navigateToRegister">
|
||||
{{ $t('login.registerButton') }}
|
||||
</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
username: '',
|
||||
password: '',
|
||||
showError: false,
|
||||
errorMessage: '',
|
||||
isLoading: false,
|
||||
currentLang: 'en', // 默认英文
|
||||
agreeTerms: false,
|
||||
rememberPassword: false,
|
||||
showLanguageModal: false,
|
||||
showPassword: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.currentLang = this.$i18n.locale
|
||||
this.loadRememberedAccount()
|
||||
},
|
||||
methods: {
|
||||
togglePasswordVisibility() {
|
||||
this.showPassword = !this.showPassword
|
||||
},
|
||||
|
||||
loadRememberedAccount() {
|
||||
const remembered = uni.getStorageSync('rememberedAccount')
|
||||
if (remembered && remembered.expire > Date.now()) {
|
||||
this.username = remembered.username
|
||||
this.password = remembered.password
|
||||
this.rememberPassword = true
|
||||
}
|
||||
},
|
||||
|
||||
saveRememberedAccount() {
|
||||
if (this.rememberPassword) {
|
||||
const expire = Date.now() + 30 * 24 * 60 * 60 * 1000
|
||||
uni.setStorageSync('rememberedAccount', {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
expire
|
||||
})
|
||||
} else {
|
||||
uni.removeStorageSync('rememberedAccount')
|
||||
}
|
||||
},
|
||||
|
||||
changeLanguage(lang) {
|
||||
this.currentLang = lang
|
||||
this.$i18n.locale = lang
|
||||
this.showError = false
|
||||
this.showLanguageModal = false
|
||||
},
|
||||
|
||||
handleLogin() {
|
||||
if (!this.agreeTerms) {
|
||||
this.showError = true
|
||||
this.errorMessage = this.$t('login.errors.agreeTermsFirst')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.username) {
|
||||
this.showError = true
|
||||
this.errorMessage = this.$t('login.errors.emptyUsername')
|
||||
return
|
||||
}
|
||||
|
||||
if (this.username.length !== 6 || !/^\d{6}$/.test(this.username)) {
|
||||
this.showError = true
|
||||
this.errorMessage = this.$t('login.errors.invalidIdCard')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.password) {
|
||||
this.showError = true
|
||||
this.errorMessage = this.$t('login.errors.emptyPassword')
|
||||
return
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
this.showError = false
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('登录信息:', { username: this.username, password: this.password })
|
||||
this.saveRememberedAccount()
|
||||
uni.navigateTo({ url: '/pages/index/index' })
|
||||
this.isLoading = false
|
||||
}, 1500)
|
||||
},
|
||||
|
||||
navigateToRegister() {
|
||||
uni.redirectTo({ url: '/pages/register/register' })
|
||||
},
|
||||
|
||||
openAgreement(type) {
|
||||
const title = type === 'terms'
|
||||
? this.$t('login.userAgreement')
|
||||
: this.$t('login.privacyPolicy')
|
||||
|
||||
uni.showModal({
|
||||
title,
|
||||
content: this.$t(`login.${type}Content`),
|
||||
showCancel: false,
|
||||
confirmText: this.$t('login.confirm')
|
||||
})
|
||||
},
|
||||
|
||||
handleForgotPassword() {
|
||||
uni.showModal({
|
||||
title: this.$t('login.forgotPassword'),
|
||||
content: this.$t('login.forgotPasswordDesc'),
|
||||
confirmText: this.$t('login.resetPassword'),
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({ url: '/pages/reset-password/reset-password' })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
padding: 0 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 语言选择文字按钮样式(核心修改) */
|
||||
.language-text-btn {
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
right: 30rpx;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx 20rpx;
|
||||
color: #007aff; /* 使用主题色突出显示 */
|
||||
font-size: 28rpx;
|
||||
cursor: pointer; /* 显示指针光标表明可点击 */
|
||||
}
|
||||
|
||||
/* 保持下拉箭头样式 */
|
||||
.icon-arrow-down {
|
||||
font-size: 24rpx;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 语言弹窗样式保持不变 */
|
||||
.lang-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.modal-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
text-align: center;
|
||||
font-size: 34rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.lang-list {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.lang-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 25rpx 10rpx;
|
||||
font-size: 30rpx;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
}
|
||||
|
||||
.lang-item.active {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.icon-check {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: #007aff;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 45rpx;
|
||||
}
|
||||
|
||||
/* 其他样式保持不变 */
|
||||
.login-header {
|
||||
padding-top: 160rpx;
|
||||
padding-bottom: 100rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #000000;
|
||||
margin-bottom: 15rpx;
|
||||
padding-left: 30rpx;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 80rpx;
|
||||
padding: 0 30rpx;
|
||||
height: 90rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.input-field::placeholder {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.toggle-btn {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.toggle-btn .iconfont {
|
||||
margin: 0;
|
||||
color: #999;
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
.toggle-btn.active .iconfont {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.remember-section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.remember-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.remember-checkbox {
|
||||
transform: scale(0.8);
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.remember-text {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.forgot-link {
|
||||
font-size: 26rpx;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff4d4f;
|
||||
font-size: 26rpx;
|
||||
padding: 15rpx 30rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.agreement-check {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.agree-checkbox {
|
||||
transform: scale(0.8);
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.agree-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #007aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
border-radius: 80rpx;
|
||||
background-color: #007aff !important;
|
||||
color: #ffffff !important;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.login-btn:disabled {
|
||||
background-color: #b3d4fc !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.register-link-section {
|
||||
text-align: center;
|
||||
margin-top: 30rpx;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.register-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.register-link {
|
||||
color: #007aff;
|
||||
margin-left: 5rpx;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.loading-icon {
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
|
||||
617
src/pages/register/register.vue
Normal file
617
src/pages/register/register.vue
Normal file
@@ -0,0 +1,617 @@
|
||||
<template>
|
||||
<view class="register-container">
|
||||
<!-- 语言选择文字按钮(点击文字即可弹出窗口) -->
|
||||
<view class="language-text-btn" @click="showLanguageModal = true">
|
||||
<text class="lang-text">{{ $t('login.changelanguage') }}</text>
|
||||
<i class="iconfont icon-arrow-down"></i>
|
||||
</view>
|
||||
|
||||
<!-- 语言选择弹窗 -->
|
||||
<view class="lang-modal" v-if="showLanguageModal">
|
||||
<view class="modal-mask" @click="showLanguageModal = false"></view>
|
||||
<view class="modal-content">
|
||||
<view class="modal-title">{{ $t('register.chooseLanguage') }}</view>
|
||||
<view class="lang-list">
|
||||
<view
|
||||
class="lang-item"
|
||||
@click="changeLanguage('en')"
|
||||
:class="{ 'active': currentLang === 'en' }"
|
||||
>
|
||||
<text>English</text>
|
||||
<i class="iconfont icon-check" v-if="currentLang === 'en'"></i>
|
||||
</view>
|
||||
<view
|
||||
class="lang-item"
|
||||
@click="changeLanguage('cn')"
|
||||
:class="{ 'active': currentLang === 'cn' }"
|
||||
>
|
||||
<text>中文</text>
|
||||
<i class="iconfont icon-check" v-if="currentLang === 'cn'"></i>
|
||||
</view>
|
||||
</view>
|
||||
<button class="modal-close" @click="showLanguageModal = false">
|
||||
{{ $t('register.languagechangeclose') }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部标题 -->
|
||||
<view class="register-header">
|
||||
<text class="app-title">{{ $t('register.appTitle') }}</text>
|
||||
<text class="register-desc">{{ $t('register.registerDesc') }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<view class="register-form">
|
||||
<!-- 身份证后六位输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('register.idCardLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-idcard"></i>
|
||||
<input
|
||||
type="text"
|
||||
v-model="idCardLast6"
|
||||
:placeholder="$t('register.idCardPlaceholder')"
|
||||
class="input-field"
|
||||
maxlength="6"
|
||||
@input="validateIdCard"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入(带显示/隐藏切换) -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('register.passwordLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-lock"></i>
|
||||
<input
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
v-model="password"
|
||||
:placeholder="$t('register.passwordPlaceholder')"
|
||||
class="input-field"
|
||||
@input="validatePassword"
|
||||
/>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
@click.stop="togglePasswordVisibility"
|
||||
:class="{ active: showPassword }"
|
||||
>
|
||||
<i class="iconfont" :class="showPassword ? 'icon-eye' : 'icon-eye-close'"></i>
|
||||
</button>
|
||||
</view>
|
||||
<text class="password-tip" v-if="showPasswordTip">{{ $t('register.passwordTip') }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 确认密码输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('register.confirmPasswordLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-lock"></i>
|
||||
<input
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
v-model="confirmPassword"
|
||||
:placeholder="$t('register.confirmPasswordPlaceholder')"
|
||||
class="input-field"
|
||||
@input="validateConfirmPassword"
|
||||
/>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
@click.stop="toggleConfirmPasswordVisibility"
|
||||
:class="{ active: showConfirmPassword }"
|
||||
>
|
||||
<i class="iconfont" :class="showConfirmPassword ? 'icon-eye' : 'icon-eye-close'"></i>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 邀请码输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('register.inviteCodeLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-invite"></i>
|
||||
<input
|
||||
type="text"
|
||||
v-model="inviteCode"
|
||||
:placeholder="$t('register.inviteCodePlaceholder')"
|
||||
class="input-field"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 邮箱输入 -->
|
||||
<view class="form-group">
|
||||
<text class="input-label">{{ $t('register.emailLabel') }}</text>
|
||||
<view class="input-wrapper">
|
||||
<i class="iconfont icon-email"></i>
|
||||
<input
|
||||
type="text"
|
||||
v-model="email"
|
||||
:placeholder="$t('register.emailPlaceholder')"
|
||||
class="input-field"
|
||||
@input="validateEmail"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view class="error-message" v-if="showError">
|
||||
{{ errorMessage }}
|
||||
</view>
|
||||
|
||||
<!-- 协议同意勾选框 -->
|
||||
<view class="agreement-check">
|
||||
<checkbox
|
||||
v-model="agreeTerms"
|
||||
class="agree-checkbox"
|
||||
color="#007aff"
|
||||
/>
|
||||
<text class="agree-text">
|
||||
{{ $t('register.agreeTermsPrefix') }}
|
||||
<text class="link" @click="openAgreement('terms')">{{ $t('register.userAgreement') }}</text>
|
||||
{{ $t('register.and') }}
|
||||
<text class="link" @click="openAgreement('privacy')">{{ $t('register.privacyPolicy') }}</text>
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button
|
||||
class="register-btn"
|
||||
@click="handleRegister"
|
||||
:disabled="isLoading || !agreeTerms || formInvalid"
|
||||
>
|
||||
<template v-if="isLoading">
|
||||
<i class="iconfont icon-loading loading-icon"></i>
|
||||
</template>
|
||||
{{ $t('register.registerButton') }}
|
||||
</button>
|
||||
|
||||
<!-- 登录链接 -->
|
||||
<view class="login-link-section">
|
||||
<text class="login-text">
|
||||
{{ $t('register.hasAccount') }}
|
||||
<text class="login-link" @click="navigateToLogin">
|
||||
{{ $t('register.loginNow') }}
|
||||
</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 表单数据
|
||||
idCardLast6: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
inviteCode: '',
|
||||
email: '',
|
||||
|
||||
// 状态控制
|
||||
showError: false,
|
||||
errorMessage: '',
|
||||
isLoading: false,
|
||||
currentLang: 'en', // 默认英文
|
||||
showLanguageModal: false,
|
||||
showPassword: false,
|
||||
showConfirmPassword: false,
|
||||
showPasswordTip: false,
|
||||
formInvalid: true,
|
||||
agreeTerms: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.currentLang = this.$i18n.locale
|
||||
},
|
||||
methods: {
|
||||
// 切换密码显示状态
|
||||
togglePasswordVisibility() {
|
||||
this.showPassword = !this.showPassword
|
||||
this.showPasswordTip = true
|
||||
},
|
||||
|
||||
// 切换确认密码显示状态
|
||||
toggleConfirmPasswordVisibility() {
|
||||
this.showConfirmPassword = !this.showConfirmPassword
|
||||
},
|
||||
|
||||
// 切换语言
|
||||
changeLanguage(lang) {
|
||||
this.currentLang = lang
|
||||
this.$i18n.locale = lang
|
||||
this.showError = false
|
||||
this.showLanguageModal = false
|
||||
},
|
||||
|
||||
// 验证身份证后六位
|
||||
validateIdCard() {
|
||||
const idReg = /^\d{6}$/
|
||||
if (this.idCardLast6 && !idReg.test(this.idCardLast6)) {
|
||||
this.setError(this.$t('register.errors.invalidIdCard'))
|
||||
return false
|
||||
}
|
||||
this.checkFormValidity()
|
||||
return true
|
||||
},
|
||||
|
||||
// 验证密码
|
||||
validatePassword() {
|
||||
// 密码规则:至少8位,包含数字和字母
|
||||
const pwdReg = /^(?=.*[A-Za-z])(?=.*\d).{8,}$/
|
||||
if (this.password && !pwdReg.test(this.password)) {
|
||||
this.setError(this.$t('register.errors.invalidPassword'))
|
||||
return false
|
||||
}
|
||||
this.validateConfirmPassword()
|
||||
this.checkFormValidity()
|
||||
return true
|
||||
},
|
||||
|
||||
// 验证确认密码
|
||||
validateConfirmPassword() {
|
||||
if (this.confirmPassword && this.confirmPassword !== this.password) {
|
||||
this.setError(this.$t('register.errors.passwordMismatch'))
|
||||
return false
|
||||
}
|
||||
this.checkFormValidity()
|
||||
return true
|
||||
},
|
||||
|
||||
// 验证邮箱
|
||||
validateEmail() {
|
||||
const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
if (this.email && !emailReg.test(this.email)) {
|
||||
this.setError(this.$t('register.errors.invalidEmail'))
|
||||
return false
|
||||
}
|
||||
this.checkFormValidity()
|
||||
return true
|
||||
},
|
||||
|
||||
// 检查表单有效性
|
||||
checkFormValidity() {
|
||||
const idReg = /^\d{6}$/
|
||||
const pwdReg = /^(?=.*[A-Za-z])(?=.*\d).{8,}$/
|
||||
const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
|
||||
const isIdValid = idReg.test(this.idCardLast6)
|
||||
const isPwdValid = pwdReg.test(this.password)
|
||||
const isConfirmValid = this.confirmPassword === this.password
|
||||
const isEmailValid = emailReg.test(this.email)
|
||||
|
||||
this.formInvalid = !(isIdValid && isPwdValid && isConfirmValid && isEmailValid)
|
||||
},
|
||||
|
||||
// 设置错误信息
|
||||
setError(message) {
|
||||
this.showError = true
|
||||
this.errorMessage = message
|
||||
},
|
||||
|
||||
// 处理注册
|
||||
handleRegister() {
|
||||
// 再次验证表单
|
||||
if (!this.validateIdCard() || !this.validatePassword() || !this.validateEmail()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 验证协议同意
|
||||
if (!this.agreeTerms) {
|
||||
this.setError(this.$t('register.errors.agreeTermsFirst'))
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟注册
|
||||
this.isLoading = true
|
||||
this.showError = false
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('注册信息:', {
|
||||
idCardLast6: this.idCardLast6,
|
||||
password: this.password,
|
||||
inviteCode: this.inviteCode,
|
||||
email: this.email
|
||||
})
|
||||
|
||||
// 注册成功提示
|
||||
uni.showToast({
|
||||
title: this.$t('register.registerSuccess'),
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// 跳转登录页面
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({ url: '/pages/login/login' })
|
||||
}, 2000)
|
||||
|
||||
this.isLoading = false
|
||||
}, 2000)
|
||||
},
|
||||
|
||||
// 跳转到登录页面
|
||||
navigateToLogin() {
|
||||
uni.navigateTo({ url: '/pages/login/login' })
|
||||
},
|
||||
|
||||
// 打开协议详情
|
||||
openAgreement(type) {
|
||||
const title = type === 'terms'
|
||||
? this.$t('register.userAgreement')
|
||||
: this.$t('register.privacyPolicy')
|
||||
|
||||
uni.showModal({
|
||||
title,
|
||||
content: this.$t(`register.${type}Content`),
|
||||
showCancel: false,
|
||||
confirmText: this.$t('register.confirm')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.register-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
padding: 0 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.language-text-btn {
|
||||
position: absolute;
|
||||
top: 30rpx;
|
||||
right: 30rpx;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx 20rpx;
|
||||
color: #007aff; /* 使用主题色突出显示 */
|
||||
font-size: 28rpx;
|
||||
cursor: pointer; /* 显示指针光标表明可点击 */
|
||||
}
|
||||
|
||||
.icon-arrow-down {
|
||||
font-size: 24rpx;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 语言弹窗样式 */
|
||||
.lang-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.modal-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
text-align: center;
|
||||
font-size: 34rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.lang-list {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.lang-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 25rpx 10rpx;
|
||||
font-size: 30rpx;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
}
|
||||
|
||||
.lang-item.active {
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.icon-check {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: #007aff;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 45rpx;
|
||||
}
|
||||
|
||||
.register-header {
|
||||
padding-top: 120rpx;
|
||||
padding-bottom: 60rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.register-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #000000;
|
||||
margin-bottom: 15rpx;
|
||||
padding-left: 30rpx;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 80rpx;
|
||||
padding: 0 30rpx;
|
||||
height: 90rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.input-field::placeholder {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 密码提示 */
|
||||
.password-tip {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
padding-left: 30rpx;
|
||||
margin-top: 10rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 邀请码提示 */
|
||||
.invite-tip {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
padding-left: 30rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff4d4f;
|
||||
font-size: 26rpx;
|
||||
padding: 15rpx 30rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
/* 协议勾选区域 */
|
||||
.agreement-check {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx 30rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.agree-checkbox {
|
||||
transform: scale(0.8);
|
||||
margin-right: 15rpx;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
|
||||
.agree-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #007aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 注册按钮 */
|
||||
.register-btn {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
border-radius: 80rpx;
|
||||
background-color: #007aff !important;
|
||||
color: #ffffff !important;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.register-btn:disabled {
|
||||
background-color: #b3d4fc;
|
||||
}
|
||||
|
||||
/* 登录链接区域 */
|
||||
.login-link-section {
|
||||
text-align: center;
|
||||
margin-top: 30rpx;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.login-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.login-link {
|
||||
color: #007aff;
|
||||
margin-left: 5rpx;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
.loading-icon {
|
||||
animation: spin 1s linear infinite;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
6
src/shime-uni.d.ts
vendored
Normal file
6
src/shime-uni.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export {};
|
||||
|
||||
declare module "vue" {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
||||
5
src/static/lang/enUS.json
Normal file
5
src/static/lang/enUS.json
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
"index.Loading": "Loading",
|
||||
"index.errMsg": "Error"
|
||||
|
||||
}
|
||||
57
src/static/lang/index.js
Normal file
57
src/static/lang/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { createSSRApp } from "vue";
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import App from "./App.vue";
|
||||
import en from './enUS.json';
|
||||
import cn from './zh_CN.json';
|
||||
|
||||
export function createApp() {
|
||||
// 创建 Vue 应用
|
||||
const app = createSSRApp(App);
|
||||
|
||||
// 获取系统语言(更安全的写法)
|
||||
const systemInfo = uni.getSystemInfoSync() || {};
|
||||
const systemLanguage = systemInfo.language || 'cn';
|
||||
let cur_lang = 'cn';
|
||||
|
||||
// 语言判断(转换为小写更可靠)
|
||||
switch (systemLanguage.toLowerCase()) {
|
||||
case 'en':
|
||||
case 'en-us':
|
||||
cur_lang = 'en';
|
||||
break;
|
||||
case 'zh':
|
||||
case 'zh-cn':
|
||||
case 'zh-hans':
|
||||
cur_lang = 'cn';
|
||||
break;
|
||||
/* 如果需要印尼语
|
||||
case 'id':
|
||||
cur_lang = 'idn';
|
||||
break;
|
||||
*/
|
||||
}
|
||||
|
||||
// 创建 i18n 实例
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: cur_lang,
|
||||
fallbackLocale: 'en', // 建议英文作为回退
|
||||
messages: {
|
||||
en,
|
||||
cn
|
||||
},
|
||||
missing: (locale, key) => {
|
||||
console.error(`[i18n] 严重: '${key}' 在 '${locale}' 语言包中不存在`);
|
||||
// 生产环境返回空字符串避免暴露键名
|
||||
return process.env.NODE_ENV === 'development' ? `[MISSING: ${key}]` : '';
|
||||
}
|
||||
});
|
||||
|
||||
// 使用 i18n 插件
|
||||
app.use(i18n);
|
||||
|
||||
return {
|
||||
app,
|
||||
i18n
|
||||
};
|
||||
}
|
||||
50
src/static/lang/zh_CN.json
Normal file
50
src/static/lang/zh_CN.json
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
{
|
||||
"index.Loading": "加载中...",
|
||||
"index.errMsg": "加载失败",
|
||||
"login.loginButton": "登录",
|
||||
"login.usernamePlaceholder": "请输入用户名",
|
||||
"login.idCardLabel": "身份证号码后六位",
|
||||
"login.passwordPlaceholder": "请输入密码",
|
||||
"login.passwordLabel": "密码",
|
||||
"login.appTitle":"欧洲股票软件",
|
||||
"login.rememberPassword": "记住密码",
|
||||
"login.forgotPassword": "忘记密码",
|
||||
"login.agreeTermsPrefix": "我已阅读并同意",
|
||||
"login.agreeTermsSuffix": "《用户协议》",
|
||||
"login.userAgreement": "用户协议",
|
||||
"login.and": "和",
|
||||
"login.privacyPolicy": "隐私政策",
|
||||
"login.registerButton": "注册",
|
||||
"login.noAccount": "没有账号?",
|
||||
"login.languagechangeclose": "完成",
|
||||
"login.chooseLanguage": "选择语言",
|
||||
"login.changelanguage": "切换语言",
|
||||
|
||||
|
||||
"register.chooseLanguage": "选择语言",
|
||||
"register.languagechangeclose": "完成",
|
||||
"register.appTitle": "欧美股票软件",
|
||||
"register.registerDesc": "创建一个账号以继续",
|
||||
"register.idCardLabel": "身份证号码后六位",
|
||||
"register.idCardPlaceholder": "请输入身份证号码后六位",
|
||||
"register.passwordLabel": "密码",
|
||||
"“register.passwordPlaceholder": "请输入密码",
|
||||
"register.confirmPasswordLabel": "确认密码",
|
||||
"register.passwordPlaceholder": "请输入确认密码",
|
||||
"register.confirmPasswordPlaceholder": "请再次确认密码",
|
||||
"register.inviteCodeLabel": "邀请码",
|
||||
"register.inviteCodePlaceholder": "请输入邀请码",
|
||||
"register.emailLabel": "邮箱",
|
||||
"register.emailPlaceholder": "请输入邮箱",
|
||||
"register.agreeTermsPrefix": "我已阅读并同意",
|
||||
"register.userAgreement": "用户协议",
|
||||
"register.and": "和",
|
||||
"register.privacyPolicy": "隐私政策",
|
||||
"register.registerButton": "注 册",
|
||||
"register.hasAccount": "已有账号?",
|
||||
"register.loginNow": "立即登录",
|
||||
"register.registerSuccess": "注册成功"
|
||||
|
||||
|
||||
}
|
||||
BIN
src/static/logo.png
Normal file
BIN
src/static/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
76
src/uni.scss
Normal file
76
src/uni.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color: #333; // 基本色
|
||||
$uni-text-color-inverse: #fff; // 反色
|
||||
$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable: #c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color: #fff;
|
||||
$uni-bg-color-grey: #f8f8f8;
|
||||
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
|
||||
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color: #c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm: 12px;
|
||||
$uni-font-size-base: 14px;
|
||||
$uni-font-size-lg: 16;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm: 20px;
|
||||
$uni-img-size-base: 26px;
|
||||
$uni-img-size-lg: 40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2c405a; // 文章标题颜色
|
||||
$uni-font-size-title: 20px;
|
||||
$uni-color-subtitle: #555; // 二级标题颜色
|
||||
$uni-font-size-subtitle: 18px;
|
||||
$uni-color-paragraph: #3f536e; // 文章段落颜色
|
||||
$uni-font-size-paragraph: 15px;
|
||||
8
vite.config.js
Normal file
8
vite.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
uni(),
|
||||
],
|
||||
})
|
||||
Reference in New Issue
Block a user