|
|
@@ -0,0 +1,924 @@
|
|
|
+<template>
|
|
|
+ <view class="login-page">
|
|
|
+ <!-- 状态栏占位 -->
|
|
|
+ <view class="status-bar"></view>
|
|
|
+
|
|
|
+ <!-- 水墨背景 -->
|
|
|
+ <view class="ink-bg">
|
|
|
+ <view class="ink-wash ink-1"></view>
|
|
|
+ <view class="ink-wash ink-2"></view>
|
|
|
+ <view class="ink-wash ink-3"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 返回按钮 -->
|
|
|
+ <view class="nav-back pad-t-20" @click="goBack">
|
|
|
+ <view class="back-btn">
|
|
|
+ <u-icon name="arrow-left" size="30"></u-icon>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- Logo和标题 -->
|
|
|
+ <view class="header">
|
|
|
+ <view class="logo-container">
|
|
|
+ <view class="logo-circle">
|
|
|
+ <image class="logo" mode="aspectFit"
|
|
|
+ src="https://ndtk.tos-cn-guangzhou.volces.com/uploads/156adea827104e38ae0e25ec4701ecfe.jpg">
|
|
|
+ </image>
|
|
|
+ </view>
|
|
|
+ <view class="logo-shadow"></view>
|
|
|
+ </view>
|
|
|
+ <view class="title-section">
|
|
|
+ <text class="title">宏匠</text>
|
|
|
+ <view class="title-brush"></view>
|
|
|
+ </view>
|
|
|
+ <text class="subtitle">唐卡世界,一键开启</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 登录按钮 -->
|
|
|
+ <view class="login-section">
|
|
|
+ <view class="btn-container">
|
|
|
+ <button :class="{ 'btn-loading': isLoading }" class="wechat-btn" @tap="handleWxLogin">
|
|
|
+ <view class="btn-ink"></view>
|
|
|
+ <text class="font32">一键快捷登录</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="zen-divider">
|
|
|
+ <view class="zen-dot"></view>
|
|
|
+ <view class="zen-line"></view>
|
|
|
+ <view class="zen-dot"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="btn-container">
|
|
|
+ <button class="browse-btn" @tap="handleBrowse">
|
|
|
+ <text>暂不登录,先去逛逛</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="agreement">
|
|
|
+ <view class="checkbox-wrapper" @tap="toggleAgreement">
|
|
|
+ <view :class="{ 'checked': isAgree }" class="zen-checkbox">
|
|
|
+ <view v-if="isAgree" class="zen-circle-inner"></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="agreement-text">
|
|
|
+ 登录即代表您已同意
|
|
|
+ <text class="link" @tap="goToPrivacy">《隐私政策》</text>
|
|
|
+ 和
|
|
|
+ <text class="link" @tap="goToService">《服务协议》</text>
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 底部装饰 -->
|
|
|
+ <view class="bottom-decoration">
|
|
|
+ <view class="zen-mountain">
|
|
|
+ <view class="mountain-peak"></view>
|
|
|
+ <view class="mountain-base"></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 首次登录设置弹框 -->
|
|
|
+ <u-popup :show="showProfileModal">
|
|
|
+ <view class="profile-modal">
|
|
|
+ <view class="modal-header">
|
|
|
+ <text class="modal-title">完善个人信息</text>
|
|
|
+ <text class="modal-subtitle">请设置您的账号和头像</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="modal-content">
|
|
|
+ <!-- 头像选择 -->
|
|
|
+ <view class="avatar-section">
|
|
|
+ <text class="section-label">头像</text>
|
|
|
+ <button :disabled="isUploadingAvatar" class="avatar-button" open-type="chooseAvatar"
|
|
|
+ @chooseavatar="onChooseAvatar">
|
|
|
+ <view class="avatar-container">
|
|
|
+ <image :src="tempAvatar || '/static/images/avatar.png'" class="avatar-preview"
|
|
|
+ mode="aspectFill"></image>
|
|
|
+ <view class="avatar-overlay">
|
|
|
+ <u-icon v-if="!isUploadingAvatar" color="#fff" name="camera" size="24"></u-icon>
|
|
|
+ <u-loading-icon v-else color="#fff" mode="spinner" size="24"></u-loading-icon>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 账号输入 -->
|
|
|
+ <view class="account-section">
|
|
|
+ <text class="section-label">用户名</text>
|
|
|
+ <u-input v-model="tempAccount" :clearable="true" :maxlength="20" border="surround"
|
|
|
+ placeholder="请输入用户名"></u-input>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="modal-actions">
|
|
|
+ <button :disabled="!tempAccount.trim() || isUploadingAvatar" class="confirm-btn"
|
|
|
+ @tap="confirmProfile">
|
|
|
+ <text v-if="!isUploadingAvatar">确认</text>
|
|
|
+ <text v-else>头像上传中...</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </u-popup>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+
|
|
|
+// import {
|
|
|
+// wxLogin,
|
|
|
+// updateProfile
|
|
|
+// } from '@/config/api.js';
|
|
|
+// import {
|
|
|
+// UPLOAD_URL
|
|
|
+// } from '@/common/config.js';
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ isAgree: false,
|
|
|
+ isLoading: false,
|
|
|
+ redirectUrl: '', // 登录成功后的重定向地址
|
|
|
+ showProfileModal: false, // 显示个人信息设置弹框
|
|
|
+ tempAccount: '', // 临时账号
|
|
|
+ tempAvatar: '', // 临时头像
|
|
|
+ loginData: null, // 临时保存登录数据
|
|
|
+ isUploadingAvatar: false // 头像上传状态
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad(options) {
|
|
|
+ // 获取重定向地址
|
|
|
+ if (options.redirect) {
|
|
|
+ this.redirectUrl = decodeURIComponent(options.redirect);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 处理微信登录
|
|
|
+ async handleWxLogin() {
|
|
|
+ if (!this.isAgree) {
|
|
|
+ let that = this
|
|
|
+ // 弹出确认弹框询问用户是否同意协议
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '登录需要您同意《隐私政策》和《服务协议》,是否同意?',
|
|
|
+ success: function (res) {
|
|
|
+ if (res.confirm) {
|
|
|
+ // 用户点击同意,自动勾选协议并执行登录
|
|
|
+ that.isAgree = true;
|
|
|
+ that.executeLogin();
|
|
|
+ } else if (res.cancel) {
|
|
|
+ console.log('用户点击取消');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.executeLogin();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 执行登录逻辑
|
|
|
+ async executeLogin() {
|
|
|
+ uni.showLoading({
|
|
|
+ mask: true
|
|
|
+ })
|
|
|
+ this.isLoading = true;
|
|
|
+
|
|
|
+ uni.getUserProfile({
|
|
|
+ desc: '用于完善会员资料',
|
|
|
+ success: (profileRes) => {
|
|
|
+ uni.login({
|
|
|
+ provider: 'weixin',
|
|
|
+ success: async (loginRes) => {
|
|
|
+ try {
|
|
|
+ const loginData = await wxLogin({
|
|
|
+ code: loginRes.code,
|
|
|
+ account: profileRes.userInfo.nickName,
|
|
|
+ avatarUrl: profileRes.userInfo.avatarUrl,
|
|
|
+ grant_type: 'wechat'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (loginData.code === 200) {
|
|
|
+ // 检查是否为首次登录
|
|
|
+ if (loginData.isFirstLogin) {
|
|
|
+ // 首次登录,显示个人信息设置弹框
|
|
|
+ this.loginData = loginData;
|
|
|
+ this.tempAccount = loginData.account || '';
|
|
|
+ this.tempAvatar = loginData.avatar || '';
|
|
|
+ this.showProfileModal = true;
|
|
|
+ this.isLoading = false;
|
|
|
+ uni.setStorageSync('access_token', loginData
|
|
|
+ .access_token);
|
|
|
+ uni.setStorageSync('refresh_token', loginData
|
|
|
+ .refresh_token);
|
|
|
+ uni.setStorageSync('user', loginData);
|
|
|
+
|
|
|
+ this.$store.commit('isLogin', true);
|
|
|
+ this.$store.commit('refresh_token', loginData
|
|
|
+ .refresh_token);
|
|
|
+ uni.hideLoading();
|
|
|
+ } else {
|
|
|
+ // 非首次登录,直接保存并跳转
|
|
|
+ this.saveLoginDataAndRedirect(loginData);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: loginData.msg || '登录失败',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('登录错误:', e);
|
|
|
+ uni.showToast({
|
|
|
+ title: '登录失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ this.isLoading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ this.isLoading = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ this.isLoading = false;
|
|
|
+ if (err.errMsg.includes('cancel')) {
|
|
|
+ return; // 用户取消,不显示提示
|
|
|
+ }
|
|
|
+ uni.showToast({
|
|
|
+ title: '获取用户信息失败',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 切换协议同意状态
|
|
|
+ toggleAgreement() {
|
|
|
+ this.isAgree = !this.isAgree;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 返回上一页
|
|
|
+ goBack() {
|
|
|
+ uni.navigateBack();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 跳转到隐私政策
|
|
|
+ goToPrivacy() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/packageUser/pages/richtext/index'
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 跳转到服务协议
|
|
|
+ goToService() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/packageUser/pages/richtext/index'
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ handleBrowse() {
|
|
|
+ // 直接返回首页
|
|
|
+ uni.switchTab({
|
|
|
+ url: '/pages/index/indexNew'
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存登录数据并跳转
|
|
|
+ saveLoginDataAndRedirect(loginData) {
|
|
|
+ uni.setStorageSync('access_token', loginData.access_token);
|
|
|
+ uni.setStorageSync('refresh_token', loginData.refresh_token);
|
|
|
+ uni.setStorageSync('user', loginData);
|
|
|
+
|
|
|
+ this.$store.commit('isLogin', true);
|
|
|
+ this.$store.commit('refresh_token', loginData.refresh_token);
|
|
|
+
|
|
|
+ uni.showToast({
|
|
|
+ title: '登录成功',
|
|
|
+ icon: 'success',
|
|
|
+ duration: 1000
|
|
|
+ });
|
|
|
+
|
|
|
+ // 登录成功后的跳转
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.redirectUrl) {
|
|
|
+ uni.redirectTo({
|
|
|
+ url: this.redirectUrl
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 检查是否有待处理的邀请,如果有则跳转到首页触发邀请弹框
|
|
|
+ const pendingInvitation = uni.getStorageSync('pendingInvitation');
|
|
|
+ if (pendingInvitation && pendingInvitation.inviterId) {
|
|
|
+ console.log('登录成功,发现待处理邀请,跳转到首页');
|
|
|
+ // 使用 reLaunch 确保首页能重新加载并检查邀请
|
|
|
+ uni.reLaunch({
|
|
|
+ url: '/pages/index/indexNew'
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ uni.switchTab({
|
|
|
+ url: '/pages/index/indexNew'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 微信小程序头像选择回调
|
|
|
+ async onChooseAvatar(e) {
|
|
|
+ console.log('选择头像:', e.detail.avatarUrl);
|
|
|
+
|
|
|
+ // 显示上传状态
|
|
|
+ this.isUploadingAvatar = true;
|
|
|
+ uni.showLoading({
|
|
|
+ title: '上传头像中...',
|
|
|
+ mask: true
|
|
|
+ });
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 上传头像到服务器
|
|
|
+ const uploadResult = await this.uploadFilePromise(e.detail.avatarUrl);
|
|
|
+ if (uploadResult && uploadResult.data && uploadResult.data.link) {
|
|
|
+ this.tempAvatar = uploadResult.data.link;
|
|
|
+ uni.showToast({
|
|
|
+ title: '头像上传成功',
|
|
|
+ icon: 'success'
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ throw new Error('上传失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('头像上传失败:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '头像上传失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ this.isUploadingAvatar = false;
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 上传文件到服务器 一般用于上传头像
|
|
|
+ uploadFilePromise(filePath) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 优先使用登录数据中的token,如果没有则使用本地存储的token
|
|
|
+ const token = (this.loginData && this.loginData.access_token) || uni.getStorageSync(
|
|
|
+ 'access_token');
|
|
|
+
|
|
|
+ if (!token) {
|
|
|
+ reject(new Error('未找到访问令牌'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.uploadFile({
|
|
|
+ url: UPLOAD_URL,
|
|
|
+ filePath: filePath,
|
|
|
+ header: {
|
|
|
+ "Blade-Auth": token
|
|
|
+ },
|
|
|
+ name: 'file',
|
|
|
+ formData: {
|
|
|
+ user: 'avatar'
|
|
|
+ },
|
|
|
+ success: (res) => {
|
|
|
+ try {
|
|
|
+ const result = JSON.parse(res.data);
|
|
|
+ if (result.success || result.code === 200) {
|
|
|
+ resolve(result);
|
|
|
+ } else {
|
|
|
+ reject(new Error(result.msg || '上传失败'));
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ reject(new Error('解析响应失败'));
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (error) => {
|
|
|
+ reject(error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 确认个人信息设置
|
|
|
+ async confirmProfile() {
|
|
|
+ if (!this.tempAccount.trim()) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '请输入账号',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showLoading({
|
|
|
+ title: '保存中...',
|
|
|
+ mask: true
|
|
|
+ });
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用更新用户信息接口
|
|
|
+ const updateRes = await updateProfile({
|
|
|
+ account: this.tempAccount.trim(),
|
|
|
+ avatar: this.tempAvatar
|
|
|
+ });
|
|
|
+
|
|
|
+ if (updateRes.code == 200) {
|
|
|
+ // 更新登录数据中的用户信息
|
|
|
+ this.loginData.account = this.tempAccount.trim();
|
|
|
+ if (this.tempAvatar) {
|
|
|
+ this.loginData.avatar = this.tempAvatar;
|
|
|
+ this.loginData.avatarUrl = this.tempAvatar; // 同时更新 avatarUrl 字段
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新本地存储的用户信息
|
|
|
+ uni.setStorageSync('user', this.loginData);
|
|
|
+
|
|
|
+ // 保存登录数据并跳转
|
|
|
+ this.saveLoginDataAndRedirect(this.loginData);
|
|
|
+ this.showProfileModal = false;
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: updateRes.msg || '保存失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('更新用户信息错误:', error);
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.login-page {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: linear-gradient(135deg, #f8f6f0 0%, #e8e4d8 50%, #d4cfc0 100%);
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.status-bar {
|
|
|
+ height: var(--status-bar-height);
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+// 水墨背景
|
|
|
+.ink-bg {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ pointer-events: none;
|
|
|
+ z-index: 1;
|
|
|
+
|
|
|
+ .ink-wash {
|
|
|
+ position: absolute;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: radial-gradient(circle, rgba(0, 0, 0, 0.03) 0%, transparent 70%);
|
|
|
+
|
|
|
+ &.ink-1 {
|
|
|
+ width: 400rpx;
|
|
|
+ height: 400rpx;
|
|
|
+ top: 10%;
|
|
|
+ right: -100rpx;
|
|
|
+ transform: rotate(15deg);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ink-2 {
|
|
|
+ width: 300rpx;
|
|
|
+ height: 300rpx;
|
|
|
+ top: 40%;
|
|
|
+ left: -50rpx;
|
|
|
+ transform: rotate(-20deg);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ink-3 {
|
|
|
+ width: 200rpx;
|
|
|
+ height: 200rpx;
|
|
|
+ bottom: 20%;
|
|
|
+ right: 20%;
|
|
|
+ transform: rotate(45deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.nav-back {
|
|
|
+ position: fixed;
|
|
|
+ left: 30rpx;
|
|
|
+ top: calc(var(--status-bar-height) + 20rpx);
|
|
|
+ z-index: 100;
|
|
|
+
|
|
|
+ .back-btn {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ background: rgba(255, 255, 255, 0.8);
|
|
|
+ border: 1rpx solid rgba(0, 0, 0, 0.1);
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ transform: scale(0.95);
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .back-icon {
|
|
|
+ font-family: "iconfont";
|
|
|
+ font-size: 36rpx;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.header {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding-top: 120rpx;
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+
|
|
|
+ .logo-container {
|
|
|
+ position: relative;
|
|
|
+ margin-bottom: 60rpx;
|
|
|
+
|
|
|
+ .logo-circle {
|
|
|
+ width: 200rpx;
|
|
|
+ height: 200rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: linear-gradient(135deg, #fff 0%, #f5f5f5 100%);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
|
|
|
+ border: 2rpx solid rgba(0, 0, 0, 0.05);
|
|
|
+
|
|
|
+ .logo {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .logo-shadow {
|
|
|
+ position: absolute;
|
|
|
+ bottom: -20rpx;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width: 160rpx;
|
|
|
+ height: 20rpx;
|
|
|
+ background: radial-gradient(ellipse, rgba(0, 0, 0, 0.1) 0%, transparent 70%);
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-section {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 64rpx;
|
|
|
+ font-weight: normal;
|
|
|
+ color: #2c3e50;
|
|
|
+ letter-spacing: 12rpx;
|
|
|
+ font-family: 'KaiTi', '楷体', serif;
|
|
|
+ text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-brush {
|
|
|
+ position: absolute;
|
|
|
+ bottom: -10rpx;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width: 120rpx;
|
|
|
+ height: 4rpx;
|
|
|
+ background: linear-gradient(90deg, transparent, #2c3e50, transparent);
|
|
|
+ border-radius: 2rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .subtitle {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: rgba(44, 62, 80, 0.7);
|
|
|
+ font-weight: 300;
|
|
|
+ letter-spacing: 4rpx;
|
|
|
+ font-style: italic;
|
|
|
+ font-family: inherit;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.login-section {
|
|
|
+ padding: 80rpx 60rpx;
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+
|
|
|
+ .btn-container {
|
|
|
+ margin-bottom: 40rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .wechat-btn {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 96rpx;
|
|
|
+ background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
|
|
|
+ border: 2rpx solid rgba(0, 0, 0, 0.08);
|
|
|
+ border-radius: 48rpx;
|
|
|
+ color: #2c3e50;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: normal;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ transform: translateY(2rpx);
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.btn-loading {
|
|
|
+ background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
|
|
|
+ color: rgba(44, 62, 80, 0.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-ink {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: linear-gradient(135deg, rgba(0, 0, 0, 0.02) 0%, transparent 50%);
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .wechat-icon {
|
|
|
+ width: 44rpx;
|
|
|
+ height: 44rpx;
|
|
|
+ margin-right: 16rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .zen-divider {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin: 50rpx 0;
|
|
|
+
|
|
|
+ .zen-dot {
|
|
|
+ width: 8rpx;
|
|
|
+ height: 8rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: rgba(44, 62, 80, 0.3);
|
|
|
+ }
|
|
|
+
|
|
|
+ .zen-line {
|
|
|
+ width: 100rpx;
|
|
|
+ height: 1rpx;
|
|
|
+ background: linear-gradient(90deg, transparent, rgba(44, 62, 80, 0.2), transparent);
|
|
|
+ margin: 0 20rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .browse-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 88rpx;
|
|
|
+ background: transparent;
|
|
|
+ border: 1rpx solid rgba(44, 62, 80, 0.15);
|
|
|
+ border-radius: 44rpx;
|
|
|
+ color: rgba(44, 62, 80, 0.7);
|
|
|
+ font-size: 28rpx;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ background: rgba(44, 62, 80, 0.05);
|
|
|
+ transform: translateY(1rpx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .agreement {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 60rpx;
|
|
|
+
|
|
|
+ .checkbox-wrapper {
|
|
|
+ margin-right: 16rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .zen-checkbox {
|
|
|
+ width: 36rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ border: 2rpx solid rgba(44, 62, 80, 0.3);
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ background: rgba(255, 255, 255, 0.8);
|
|
|
+
|
|
|
+ &.checked {
|
|
|
+ background: #2c3e50;
|
|
|
+ border-color: #2c3e50;
|
|
|
+ }
|
|
|
+
|
|
|
+ .zen-circle-inner {
|
|
|
+ width: 16rpx;
|
|
|
+ height: 16rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .agreement-text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: rgba(44, 62, 80, 0.6);
|
|
|
+ line-height: 1.5;
|
|
|
+
|
|
|
+ .link {
|
|
|
+ color: #2c3e50;
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 底部装饰
|
|
|
+.bottom-decoration {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 40rpx;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ z-index: 1;
|
|
|
+
|
|
|
+ .zen-mountain {
|
|
|
+ position: relative;
|
|
|
+ width: 200rpx;
|
|
|
+ height: 120rpx;
|
|
|
+
|
|
|
+ .mountain-peak {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-left: 60rpx solid transparent;
|
|
|
+ border-right: 60rpx solid transparent;
|
|
|
+ border-bottom: 80rpx solid rgba(44, 62, 80, 0.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .mountain-base {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 40rpx;
|
|
|
+ background: linear-gradient(90deg, transparent, rgba(44, 62, 80, 0.05), transparent);
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 个人信息设置弹框样式
|
|
|
+.profile-modal {
|
|
|
+ width: 750rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .modal-header {
|
|
|
+ text-align: center;
|
|
|
+ padding: 60rpx 40rpx 40rpx;
|
|
|
+ background: linear-gradient(135deg, #f8f6f0 0%, #e8e4d8 100%);
|
|
|
+
|
|
|
+ .modal-title {
|
|
|
+ display: block;
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2c3e50;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-subtitle {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: rgba(44, 62, 80, 0.7);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-content {
|
|
|
+ padding: 40rpx;
|
|
|
+
|
|
|
+ .avatar-section {
|
|
|
+ margin-bottom: 40rpx;
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ .section-label {
|
|
|
+ display: block;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #2c3e50;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ .avatar-button {
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0 auto;
|
|
|
+ display: block;
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:disabled {
|
|
|
+ opacity: 0.7;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .avatar-container {
|
|
|
+ position: relative;
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 3rpx solid #e8e4d8;
|
|
|
+
|
|
|
+ .avatar-preview {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .avatar-overlay {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 50rpx;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .account-section {
|
|
|
+ .section-label {
|
|
|
+ display: block;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #2c3e50;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-actions {
|
|
|
+ padding: 0 40rpx 40rpx;
|
|
|
+
|
|
|
+ .confirm-btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 80rpx;
|
|
|
+ background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ border: none;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &:disabled {
|
|
|
+ background: #bdc3c7;
|
|
|
+ color: rgba(255, 255, 255, 0.7);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:not(:disabled):active {
|
|
|
+ transform: translateY(2rpx);
|
|
|
+ box-shadow: 0 2rpx 8rpx rgba(44, 62, 80, 0.3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|