This commit is contained in:
owenchen committed 2026-10-17 13:22:10 +08:00
1 parent b5d2a2ede0
commit aff58692bb
17 files changed
+1851 -240

No files matched your search

+207 -41
View File
@@ -7,6 +7,7 @@ import type { LoginProfile } from "@/data/auto/loginProfile";
import { onLoad } from "@dcloudio/uni-app";
import { useLocale } from "uview-pro";
import { computed, ref } from "vue";
import { brandGlyph, veinGlyph } from "@/common/brand";
import { backendLocale, baseUrl } from "@/common/http.interceptor";
import { encryptLoginPassword } from "@/common/pwd-crypto";
import { LoginData as LoginDataClass } from "@/data/auto/loginData";
@@ -17,6 +18,7 @@ import { useLoginProfileStore } from "@/stores";
const userMobile = ref("");
const password = ref("");
const showPwd = ref(false);
const loading = ref(false);
const loginProfileStore = useLoginProfileStore();
@@ -44,6 +46,10 @@ onLoad((options) => {
// 登录页中英文切换:走 uView Pro 语言包(t / setLocale),语言包 name 为 zh-CN / en-US
const { t, setLocale, currentLocale } = useLocale();
const isZh = computed(() => (currentLocale.value?.name ?? "zh-CN") !== "en-US");
/** 非发布构建才显示「当前环境 + 实际调用的后端地址」:发布版 import.meta.env.PROD 为 true,整行编译期即被剔除 */
const isProd = import.meta.env.PROD;
const envMode = import.meta.env.MODE;
function toggleLang() {
setLocale(isZh.value ? "en-US" : "zh-CN");
// 开发构建顺手重拉数据库翻译:改完 DB 词条点一下切换就能看到新值,无需整页刷新
@@ -53,15 +59,11 @@ function toggleLang() {
}
}
/** 取消:清空输入 */
function handleCancel() {
userMobile.value = "";
password.value = "";
/** 进入注册页(/register,免登录):navigateTo 保留历史以便返回登录 */
function goRegister() {
uni.navigateTo({ url: pageUrl("register") });
}
// 开发构建显示「登录测试」标记,发布构建只显示后端地址(import.meta.env.DEV 编译期确定)
const isDev = import.meta.env.DEV;
/** 生成 v4 风格 Guid(无需引入 uuid 包,与旧系统 uuidv4() 等效) */
function makeGuid(): string {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
@@ -116,77 +118,241 @@ async function handleLogin() {
<template>
<view class="login-page">
<view class="login-title">
有家相册
</view>
<view class="login-subtitle">
{{ isDev ? `登录测试 · ${baseUrl}` : baseUrl }}
<!-- 背景右上淡叶脉暗纹(纯装饰,低透明) -->
<image class="login-vein" :src="veinGlyph" mode="aspectFit" />
<!-- 品牌位:叶脉树 Logo + 名称 + 标语 -->
<view class="login-brand">
<view class="login-brand__logo">
<image class="login-brand__glyph" :src="brandGlyph" mode="aspectFit" />
</view>
<view class="login-brand__name">
{{ t("LoginForm.brandName") }}
</view>
<view class="login-brand__slogan">
{{ t("LoginForm.slogan") }}
</view>
</view>
<!-- 表单:图标内嵌白底圆角胶囊 -->
<view class="login-form">
<u-input v-model="userMobile" :placeholder="t('LoginForm.userLabel')" border clearable />
<u-input
v-model="password" type="password" :placeholder="t('LoginForm.passwordLabel')" border :password-icon="true"
@confirm="handleLogin"
/>
<u-button type="primary" shape="circle" :loading="loading" :text="t('LoginForm.loginBut')" @click="handleLogin" />
<u-button shape="circle" :text="t('LoginForm.cancelBut')" @click="handleCancel" />
<view class="login-field">
<u-icon name="account" size="34" color="#9aa0a6" />
<input
v-model="userMobile" class="login-field__input" :placeholder="t('LoginForm.userLabel')"
placeholder-class="login-field__ph" @confirm="handleLogin"
>
</view>
<view class="login-field">
<u-icon name="lock" size="34" color="#9aa0a6" />
<input
v-model="password" class="login-field__input" :password="!showPwd" :placeholder="t('LoginForm.passwordLabel')"
placeholder-class="login-field__ph" @confirm="handleLogin"
>
<u-icon :name="showPwd ? 'eye-fill' : 'eye-off'" size="34" color="#9aa0a6" @click="showPwd = !showPwd" />
</view>
</view>
<view class="login-lang" @click="toggleLang">
<text class="login-lang__label">
{{ t('LoginForm.cultureLabel') }}
</text>
<text class="login-lang__switch">
{{ isZh ? 'English' : '中文' }}
</text>
<!-- 按钮:登录黛翠绿渐变实心 -->
<view class="login-btn login-btn--submit" @click="handleLogin">
<u-loading v-if="loading" mode="circle" color="#ffffff" :size="34" />
<text v-else>{{ t("LoginForm.loginBut") }}</text>
</view>
<!-- 底部:语言切换 + 注册入口(非发布版另显示当前环境与后端地址) -->
<view class="login-footer">
<view class="login-lang" @click="toggleLang">
<text class="login-lang__label">
{{ t("LoginForm.cultureLabel") }}
</text>
<text class="login-lang__switch">
{{ isZh ? t("LoginForm.langZh") : t("LoginForm.langEn") }}
</text>
</view>
<view class="login-register" @click="goRegister">
<text class="login-register__tip">
{{ t("LoginForm.registerTip") }}
</text>
<text class="login-register__link">
{{ t("LoginForm.registerBut") }}
</text>
</view>
<view v-if="!isProd" class="login-env">
{{ envMode }} · {{ baseUrl }}
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
/* 品牌配色:黛翠绿主色 + 琥珀金点缀 + 暖米白底,登录页品牌身份独立于应用内主题 */
$brand-green: #2f7d5c;
$brand-green-dark: #1f5f47;
$brand-green-light: #47a678;
$brand-amber: #c8912f;
$brand-ink: #1f3d2f;
.login-page {
min-height: 100vh;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
padding: 200rpx 60rpx 0;
background: linear-gradient(160deg, rgba(41, 121, 255, 0.08), rgba(25, 190, 107, 0.06));
box-sizing: border-box;
min-height: 100vh;
padding: 150rpx 60rpx 60rpx;
overflow: hidden;
background: linear-gradient(165deg, #f7f0e3 0%, #f1e7d6 55%, #eaddc7 100%);
}
.login-title {
font-size: 56rpx;
/* 右上淡叶脉暗纹:半隐若现,不拦截点击 */
.login-vein {
position: absolute;
top: -40rpx;
right: -60rpx;
width: 460rpx;
height: 460rpx;
opacity: 0.08;
pointer-events: none;
}
/* ===== 品牌位 ===== */
.login-brand {
display: flex;
z-index: 1;
flex-direction: column;
align-items: center;
margin-bottom: 80rpx;
}
.login-brand__logo {
display: flex;
align-items: center;
justify-content: center;
width: 132rpx;
height: 132rpx;
margin-bottom: 28rpx;
border-radius: 36rpx;
background: linear-gradient(150deg, $brand-green-light, $brand-green-dark);
box-shadow: 0 16rpx 36rpx rgba(31, 95, 71, 0.32);
}
.login-brand__glyph {
width: 76rpx;
height: 76rpx;
}
.login-brand__name {
font-size: 52rpx;
font-weight: 700;
color: var(--u-type-primary);
letter-spacing: 4rpx;
color: $brand-ink;
}
.login-subtitle {
margin: 16rpx 0 80rpx;
font-size: 24rpx;
color: $u-tips-color;
.login-brand__slogan {
margin-top: 14rpx;
font-size: 26rpx;
letter-spacing: 6rpx;
color: $brand-amber;
}
/* ===== 表单 ===== */
.login-form {
display: flex;
z-index: 1;
flex-direction: column;
gap: 32rpx;
width: 100%;
}
.login-field {
display: flex;
align-items: center;
gap: 16rpx;
padding: 0 32rpx;
border-radius: 20rpx;
background-color: #ffffff;
box-shadow: 0 6rpx 20rpx rgba(31, 95, 71, 0.06);
}
.login-field__input {
flex: 1;
height: 96rpx;
font-size: 30rpx;
color: $brand-ink;
}
.login-field__ph {
color: #b3b8bd;
}
/* ===== 按钮 ===== */
.login-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 96rpx;
margin-top: 40rpx;
border-radius: 48rpx;
font-size: 32rpx;
font-weight: 600;
letter-spacing: 8rpx;
}
.login-btn--submit {
color: #ffffff;
background: linear-gradient(135deg, $brand-green-light, $brand-green-dark);
box-shadow: 0 16rpx 32rpx rgba(31, 95, 71, 0.3);
}
/* ===== 底部 ===== */
.login-footer {
display: flex;
flex-direction: column;
gap: 40rpx;
align-items: center;
width: 100%;
margin-top: auto;
padding-top: 60rpx;
}
.login-lang {
margin-top: 48rpx;
display: flex;
align-items: center;
gap: 8rpx;
gap: 6rpx;
font-size: 26rpx;
}
.login-lang__label {
color: $u-tips-color;
color: #9aa0a6;
}
.login-lang__switch {
color: var(--u-type-primary);
font-weight: 600;
color: $brand-green;
}
.login-register {
display: flex;
align-items: center;
gap: 6rpx;
margin-top: 24rpx;
font-size: 26rpx;
}
.login-register__tip {
color: #9aa0a6;
}
.login-register__link {
font-weight: 600;
color: $brand-amber;
}
/* 非发布版的环境 / 后端地址角标:低调灰字,仅开发或 UAT 构建出现 */
.login-env {
margin-top: 22rpx;
font-size: 22rpx;
letter-spacing: 0.5rpx;
color: #b0a894;
}
</style>