fix: 🐛 修复小程序显示问题

This commit is contained in:
ray
2025-04-28 08:08:47 +08:00
parent 7a04eea075
commit 93c5fe873e
12 changed files with 289 additions and 705 deletions

View File

@@ -25,12 +25,8 @@
"keyframes-name-pattern": null,
"no-descending-specificity": null,
"no-empty-source": null,
"unit-no-unknown": [
true,
{
"ignoreUnits": ["rpx"]
}
],
"declaration-property-value-no-unknown": null,
"unit-no-unknown": null,
"selector-type-no-unknown": [
true,
{

View File

@@ -21,13 +21,24 @@ onHide(() => {
</script>
<style lang="scss">
/* H5 环境样式变量设置 */
:root {
--primary-color: #165dff;
--primary-color-light: #94bfff;
--primary-color-dark: #0e3c9b;
}
/* 小程序环境样式变量设置 */
page {
--primary-color: #165dff;
--primary-color-light: #94bfff;
--primary-color-dark: #0e3c9b;
background: #f8f8f8;
}
/* 动态加载小程序主题色的钩子 */
/* 用于通过小程序原生API获取主题色并应用 */
.theme-container {
display: none;
}
</style>

View File

@@ -50,7 +50,7 @@
"quickapp": {},
/* */
"mp-weixin": {
"appid": "",
"appid": "wx99a151dc43d2637b",
"setting": {
"urlCheck": false
},

View File

@@ -1,487 +0,0 @@
<template>
<view class="complete-profile-container">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<wd-icon name="arrow-left" size="20" color="#fff" @click="goBack" />
<text class="nav-title">完善个人信息</text>
<view style="width: 20px"></view>
</view>
<!-- 蓝色区域内容 -->
<view class="top-content">
<view class="title">完善个人信息</view>
<view class="subtitle">完善您的个人信息以获得更好的使用体验</view>
</view>
<!-- 白色区域 -->
<view class="bottom-content">
<!-- 头像上传 -->
<view class="avatar-section">
<view class="avatar-wrapper" @click="chooseAvatar">
<image v-if="userForm.avatar" :src="userForm.avatar" class="avatar" />
<view v-else class="avatar-placeholder">
<wd-icon name="fill-camera" size="28" color="#999" />
</view>
<view class="avatar-upload">
<wd-icon name="camera" size="16" color="#fff" />
</view>
</view>
<view class="avatar-tip">点击更换头像</view>
</view>
<!-- 表单部分 -->
<view class="form-section">
<wd-form ref="formRef" :model="userForm">
<!-- 昵称输入框 -->
<view class="input-wrap">
<text class="input-label">昵称</text>
<input
v-model="userForm.nickname"
class="form-input"
placeholder="请输入您的昵称"
placeholder-style="color: #999; font-weight: normal;"
/>
<wd-icon
v-if="userForm.nickname"
name="close-fill"
size="18"
color="#999"
class="clear-icon"
@click="userForm.nickname = ''"
/>
</view>
<view class="divider"></view>
<!-- 性别选择 -->
<view class="gender-wrap">
<text class="input-label">性别</text>
<view class="gender-options">
<view
class="gender-option"
:class="userForm.gender === 1 ? 'gender-selected' : ''"
@click="userForm.gender = 1"
>
<text></text>
</view>
<view
class="gender-option"
:class="userForm.gender === 2 ? 'gender-selected' : ''"
@click="userForm.gender = 2"
>
<text></text>
</view>
</view>
</view>
<view class="divider"></view>
<!-- 提交按钮 -->
<view class="button-wrap">
<button
class="submit-button"
:disabled="submitting"
:style="submitting ? 'opacity: 0.7;' : ''"
@click="handleSubmit"
>
提交
</button>
</view>
<!-- 微信获取信息按钮 -->
<view v-if="isWechatEnv" class="button-wrap mt-20">
<button
class="wechat-button"
:disabled="wxAuthing"
:style="wxAuthing ? 'opacity: 0.7;' : ''"
@click="handleGetWechatInfo"
>
<image src="/static/icons/weixin.png" class="wechat-icon" />
<text>一键获取微信头像昵称</text>
</button>
</view>
</wd-form>
</view>
</view>
<!-- 头像裁剪 -->
<wd-img-cropper v-model="avatarShow" :img-src="originalSrc" @confirm="handleAvatarConfirm" />
<!-- 弹窗 -->
<wd-toast />
</view>
</template>
<script lang="ts" setup>
import { onLoad } from "@dcloudio/uni-app";
import { useToast } from "wot-design-uni";
import { useUserStore } from "@/store/modules/user";
import FileAPI, { type FileInfo } from "@/api/file";
import UserAPI, { type UserProfileForm } from "@/api/system/user";
import { ref } from "vue";
const toast = useToast();
const formRef = ref();
const userStore = useUserStore();
const submitting = ref(false);
const wxAuthing = ref(false);
const avatarShow = ref(false);
const originalSrc = ref("");
const redirectPath = ref("/pages/index/index");
// 用户表单数据
const userForm = ref<UserProfileForm>({
nickname: "",
gender: 1,
avatar: "",
});
// 判断是否微信环境
const isWechatEnv = ref(false);
// 获取参数
onLoad((options) => {
// 读取用户信息
if (userStore.userInfo) {
userForm.value.nickname = userStore.userInfo.nickname || "";
userForm.value.gender = userStore.userInfo.gender || 1;
userForm.value.avatar = userStore.userInfo.avatar || "";
}
// 保存跳转路径
if (options.redirect) {
redirectPath.value = decodeURIComponent(options.redirect);
}
// 检测环境
// #ifdef MP-WEIXIN
isWechatEnv.value = true;
// #endif
});
// 返回上一页
const goBack = () => {
uni.navigateBack();
};
// 选择头像
const chooseAvatar = () => {
uni.chooseImage({
count: 1,
success: (res) => {
originalSrc.value = res.tempFilePaths[0];
avatarShow.value = true;
},
});
};
// 头像裁剪完成
const handleAvatarConfirm = (event: any) => {
const { tempFilePath } = event;
// 显示上传中
uni.showLoading({ title: "上传中..." });
// 上传头像
FileAPI.upload(tempFilePath)
.then((fileInfo: FileInfo) => {
userForm.value.avatar = fileInfo.url;
uni.hideLoading();
})
.catch(() => {
uni.hideLoading();
toast.error("头像上传失败,请重试");
});
};
// 一键获取微信信息
const handleGetWechatInfo = () => {
wxAuthing.value = true;
// #ifdef MP-WEIXIN
// @ts-ignore
uni.getUserProfile({
desc: "用于完善用户资料",
success: (res) => {
const { userInfo } = res;
// 填充表单
userForm.value.nickname = userInfo.nickName;
userForm.value.gender = userInfo.gender;
// 如果有头像,下载并上传头像
if (userInfo.avatarUrl) {
uni.showLoading({ title: "获取头像中..." });
// 下载微信头像
uni.downloadFile({
url: userInfo.avatarUrl,
success: (res) => {
if (res.statusCode === 200) {
// 上传到服务器
FileAPI.upload(res.tempFilePath)
.then((fileInfo: FileInfo) => {
userForm.value.avatar = fileInfo.url;
uni.hideLoading();
})
.catch(() => {
uni.hideLoading();
toast.error("头像上传失败");
});
}
},
fail: () => {
uni.hideLoading();
toast.error("获取微信头像失败");
},
});
}
},
fail: () => {
toast.error("获取微信信息失败,请手动填写");
},
complete: () => {
wxAuthing.value = false;
},
});
// #endif
// 非微信环境
// #ifndef MP-WEIXIN
toast.error("当前环境不支持获取微信信息");
wxAuthing.value = false;
// #endif
};
// 提交表单
const handleSubmit = () => {
if (submitting.value) return;
// 简单验证
if (!userForm.value.nickname.trim()) {
toast.error("请填写昵称");
return;
}
submitting.value = true;
// 更新用户信息
UserAPI.updateProfile(userForm.value)
.then(async () => {
// 更新本地存储的用户信息
await userStore.getInfo();
toast.success("信息已更新");
// 延迟跳转
setTimeout(() => {
uni.reLaunch({
url: redirectPath.value,
});
}, 1500);
})
.catch(() => {
toast.error("更新失败,请重试");
})
.finally(() => {
submitting.value = false;
});
};
</script>
<style lang="scss" scoped>
.complete-profile-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #0063ff;
}
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
padding-top: calc(30rpx + var(--status-bar-height, 0px));
}
.nav-title {
font-size: 36rpx;
font-weight: 500;
color: #fff;
}
.top-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0 60rpx;
}
.top-content .title {
margin-bottom: 20rpx;
font-size: 36rpx;
font-weight: 500;
color: #fff;
}
.top-content .subtitle {
padding: 0 60rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.9);
text-align: center;
}
.bottom-content {
flex: 1;
padding: 40rpx 30rpx;
overflow-y: auto;
background-color: #fff;
border-radius: 30rpx 30rpx 0 0;
}
.avatar-section {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 40rpx;
}
.avatar-section .avatar-wrapper {
position: relative;
width: 160rpx;
height: 160rpx;
margin-bottom: 20rpx;
}
.avatar-section .avatar-wrapper .avatar {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
}
.avatar-section .avatar-wrapper .avatar-placeholder {
display: flex;
align-items: center;
justify-content: center;
width: 160rpx;
height: 160rpx;
background-color: #f5f7fa;
border-radius: 50%;
}
.avatar-section .avatar-wrapper .avatar-upload {
position: absolute;
right: 5rpx;
bottom: 5rpx;
display: flex;
align-items: center;
justify-content: center;
width: 40rpx;
height: 40rpx;
background-color: #4080ff;
border: 2rpx solid #fff;
border-radius: 50%;
}
.avatar-section .avatar-tip {
font-size: 26rpx;
color: #666;
}
.form-section .input-wrap {
position: relative;
display: flex;
align-items: center;
padding: 20rpx 0;
}
.form-section .input-wrap .input-label {
width: 100rpx;
font-size: 28rpx;
color: #333;
}
.form-section .input-wrap .form-input {
flex: 1;
height: 60rpx;
font-size: 28rpx;
line-height: 60rpx;
color: #333;
}
.form-section .input-wrap .clear-icon {
padding: 10rpx;
}
.form-section .gender-wrap {
display: flex;
align-items: center;
padding: 20rpx 0;
}
.form-section .gender-wrap .input-label {
width: 100rpx;
font-size: 28rpx;
color: #333;
}
.form-section .gender-wrap .gender-options {
display: flex;
flex: 1;
gap: 20rpx;
justify-content: flex-end;
}
.form-section .gender-wrap .gender-options .gender-option {
padding: 10rpx 30rpx;
font-size: 28rpx;
color: #666;
background-color: #f5f7fa;
border-radius: 10rpx;
}
.form-section .gender-wrap .gender-options .gender-option.gender-selected {
color: #fff;
background-color: #4080ff;
}
.form-section .divider {
height: 1px;
margin: 0 0 10rpx 0;
background-color: #e8e8e8;
}
.form-section .button-wrap {
margin-top: 60rpx;
}
.form-section .button-wrap .submit-button {
width: 100%;
height: 90rpx;
font-size: 32rpx;
line-height: 90rpx;
color: #fff;
background-color: #4080ff;
border: none;
border-radius: 45rpx;
}
.form-section .button-wrap .wechat-button {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 90rpx;
font-size: 30rpx;
color: #fff;
background-color: #07c160;
border: none;
border-radius: 45rpx;
}
.form-section .button-wrap .wechat-button .wechat-icon {
width: 36rpx;
height: 36rpx;
margin-right: 10rpx;
}
.mt-20 {
margin-top: 20rpx;
}
</style>

View File

@@ -35,11 +35,17 @@
<input
v-model="loginFormData.password"
class="form-input"
type="password"
:type="showPassword ? 'text' : 'password'"
placeholder="请输入密码"
placeholder-style="color: #9ca3af; font-weight: normal;"
/>
<wd-icon name="eye-close" size="18" color="#9ca3af" class="eye-icon" />
<wd-icon
:name="showPassword ? 'eye-open' : 'eye-close'"
size="18"
color="#9ca3af"
class="eye-icon"
@click="showPassword = !showPassword"
/>
</view>
<view class="divider"></view>
@@ -94,6 +100,7 @@ const loginFormRef = ref();
const toast = useToast();
const loading = ref(false);
const userStore = useUserStore();
const showPassword = ref(false);
// 登录表单数据
const loginFormData = ref<LoginFormData>({

View File

@@ -10,9 +10,6 @@
:src="isLogin ? userInfo!.avatar : defaultAvatar"
mode="aspectFill"
/>
<view v-if="isLogin" class="avatar-edit">
<wd-icon name="edit-pen" size="16" color="#fff" />
</view>
</view>
<view class="user-details">
<block v-if="isLogin">
@@ -21,7 +18,12 @@
</block>
<block v-else>
<view class="login-prompt">立即登录获取更多功能</view>
<wd-button class="login-btn" size="small" type="primary" @click="navigateToLoginPage">
<wd-button
custom-class="btn-login"
size="small"
type="primary"
@click="navigateToLoginPage"
>
登录/注册
</wd-button>
</block>
@@ -31,7 +33,7 @@
<wd-icon name="setting1" size="22" color="#333" />
</view>
<view v-if="isLogin" class="action-btn" @click="navigateToSection('messages')">
<wd-icon name="message" size="22" color="#333" />
<wd-icon name="notification" size="22" color="#333" />
<view v-if="true" class="badge">2</view>
</view>
</view>
@@ -56,53 +58,6 @@
</view>
</view>
<!-- 我的订单 -->
<view class="card-container">
<view class="card-header">
<view class="card-title">
<wd-icon name="cart" size="18" :color="themeStore.primaryColor" />
<text>我的订单</text>
</view>
<view class="card-action" @click="navigateToSection('orders')">
<text>全部订单</text>
<wd-icon name="arrow-right" size="14" color="#999" />
</view>
</view>
<view class="order-status">
<view class="status-item" @click="navigateToSection('orders', 'pending')">
<view class="status-icon">
<wd-icon name="wallet-pay" size="28" :color="themeStore.primaryColor" />
<view v-if="true" class="status-badge">2</view>
</view>
<view class="status-label">待付款</view>
</view>
<view class="status-item" @click="navigateToSection('orders', 'shipping')">
<view class="status-icon">
<wd-icon name="shopping" size="28" :color="themeStore.primaryColor" />
</view>
<view class="status-label">待发货</view>
</view>
<view class="status-item" @click="navigateToSection('orders', 'receiving')">
<view class="status-icon">
<wd-icon name="car" size="28" :color="themeStore.primaryColor" />
</view>
<view class="status-label">待收货</view>
</view>
<view class="status-item" @click="navigateToSection('orders', 'comment')">
<view class="status-icon">
<wd-icon name="comment-o" size="28" :color="themeStore.primaryColor" />
</view>
<view class="status-label">待评价</view>
</view>
<view class="status-item" @click="navigateToSection('orders', 'after-sale')">
<view class="status-icon">
<wd-icon name="service" size="28" :color="themeStore.primaryColor" />
</view>
<view class="status-label">售后</view>
</view>
</view>
</view>
<!-- 常用工具 -->
<view class="card-container">
<view class="card-header">
@@ -114,22 +69,11 @@
<view class="tools-grid">
<view class="tool-item" @click="navigateToProfile">
<view class="tool-icon">
<wd-icon name="person" size="24" :color="themeStore.primaryColor" />
<wd-icon name="user" size="24" :color="themeStore.primaryColor" />
</view>
<view class="tool-label">个人资料</view>
</view>
<view class="tool-item" @click="navigateToSection('address')">
<view class="tool-icon">
<wd-icon name="location" size="24" :color="themeStore.primaryColor" />
</view>
<view class="tool-label">收货地址</view>
</view>
<view class="tool-item" @click="navigateToSection('todos')">
<view class="tool-icon">
<wd-icon name="task" size="24" :color="themeStore.primaryColor" />
</view>
<view class="tool-label">待办事项</view>
</view>
<view class="tool-item" @click="navigateToFAQ">
<view class="tool-icon">
<wd-icon name="help-circle" size="24" :color="themeStore.primaryColor" />
@@ -148,18 +92,6 @@
</view>
<view class="tool-label">关于我们</view>
</view>
<view class="tool-item" @click="navigateToSettings">
<view class="tool-icon">
<wd-icon name="setting1" size="24" :color="themeStore.primaryColor" />
</view>
<view class="tool-label">设置</view>
</view>
<view class="tool-item" @click="navigateToSection('wallet')">
<view class="tool-icon">
<wd-icon name="wallet" size="24" :color="themeStore.primaryColor" />
</view>
<view class="tool-label">我的钱包</view>
</view>
</view>
</view>
@@ -174,8 +106,8 @@
<view class="services-list">
<view class="service-item" @click="navigateToSection('services', 'vip')">
<view class="service-left">
<view class="service-icon vip-icon">
<wd-icon name="crown" size="22" color="#FFD700" />
<view class="service-icon">
<wd-icon name="dong" size="22" :color="themeStore.primaryColor" />
</view>
<view class="service-info">
<view class="service-name">会员中心</view>
@@ -187,7 +119,7 @@
<view class="service-item" @click="navigateToSection('services', 'coupon')">
<view class="service-left">
<view class="service-icon">
<wd-icon name="ticket" size="22" :color="themeStore.primaryColor" />
<wd-icon name="discount" size="22" :color="themeStore.primaryColor" />
</view>
<view class="service-info">
<view class="service-name">优惠券</view>
@@ -212,7 +144,7 @@
</view>
<view v-if="isLogin" class="logout-btn-container">
<wd-button class="logout-btn" @click="handleLogout">退出登录</wd-button>
<wd-button custom-class="logout-btn-unocss" @click="handleLogout">退出登录</wd-button>
</view>
<wd-toast />
@@ -314,6 +246,7 @@ const navigateToSection = (section: string, subSection?: string) => {
</script>
<style lang="scss" scoped>
/* stylelint-disable declaration-property-value-no-unknown */
.mine-container {
min-height: 100vh;
padding-bottom: 100rpx;
@@ -352,20 +285,6 @@ const navigateToSection = (section: string, subSection?: string) => {
border-radius: 50%;
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.1);
}
.avatar-edit {
position: absolute;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 36rpx;
height: 36rpx;
background-color: var(--primary-color);
border-radius: 50%;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.2);
}
}
.user-details {
@@ -389,16 +308,6 @@ const navigateToSection = (section: string, subSection?: string) => {
font-size: 28rpx;
color: #fff;
}
.login-btn {
width: 160rpx;
height: 60rpx;
font-size: 26rpx;
color: var(--primary-color);
background-color: #fff;
border: none;
border-radius: 30rpx;
}
}
.actions {
@@ -617,10 +526,6 @@ const navigateToSection = (section: string, subSection?: string) => {
height: 70rpx;
background-color: rgba(var(--primary-color-rgb), 0.08);
border-radius: 16rpx;
&.vip-icon {
background: linear-gradient(135deg, #ffd700, #ffa500);
}
}
.service-info {
@@ -645,19 +550,33 @@ const navigateToSection = (section: string, subSection?: string) => {
// 退出登录按钮
.logout-btn-container {
margin: 60rpx 30rpx;
.logout-btn {
width: 100%;
height: 80rpx;
font-size: 28rpx;
color: #666;
background-color: #f5f5f5;
border: none;
border-radius: 40rpx;
&:active {
opacity: 0.8;
}
}
}
</style>
<style>
/* 使用全局样式解决微信小程序组件样式问题 */
.logout-btn-unocss {
display: flex !important;
align-items: center !important;
justify-content: center !important;
width: 100% !important;
height: 80rpx !important;
font-size: 32rpx !important;
font-weight: bold !important;
color: #fff !important;
background-color: var(--primary-color) !important;
border: 2rpx solid var(--primary-color) !important;
border-radius: 40rpx !important;
box-shadow: 0 4rpx 12rpx rgba(var(--primary-color-rgb), 0.3) !important;
}
.btn-login {
width: 160rpx !important;
height: 60rpx !important;
font-size: 26rpx !important;
color: var(--primary-color) !important;
background-color: #fff !important;
border: none !important;
border-radius: 30rpx !important;
}
</style>

View File

@@ -1,10 +1,12 @@
<template>
<view class="settings-container">
<wd-cell-group>
<wd-cell title="个人资料" icon="user" is-link @click="navigateToProfile" />
<wd-cell title="账号和安全" icon="secured" is-link @click="navigateToAccount" />
<wd-cell title="主题设置" icon="brush" is-link @click="navigateToTheme" />
<wd-cell title="主题设置" icon="setting1" is-link @click="navigateToTheme" />
<wd-cell title="用户协议" icon="user" is-link @click="navigateToUserAgreement" />
<wd-cell title="隐私政策" icon="folder" is-link @click="navigateToPrivacy" />
<wd-cell title="关于我们" icon="info" is-link @click="navigateToAbout" />
</wd-cell-group>
<wd-cell-group custom-style="margin-top:40rpx">
@@ -18,9 +20,9 @@
/>
</wd-cell-group>
<wd-cell-group v-if="isLogin" custom-style="margin-top:40rpx">
<wd-cell title="退出" icon="logout" is-link @click="handleLogout" />
</wd-cell-group>
<view v-if="isLogin" class="logout-section">
<wd-button class="logout-btn" @click="handleLogout">退出登录</wd-button>
</view>
<!-- 全屏 loading -->
<view v-if="clearing" class="loading-mask">
@@ -35,28 +37,57 @@
<script lang="ts" setup>
import { useUserStore } from "@/store/modules/user";
import { checkLogin } from "@/utils/auth";
import { computed, ref } from "vue";
const userStore = useUserStore();
const isLogin = computed(() => !!userStore.userInfo);
// 个人资料
const navigateToProfile = () => {
if (checkLogin()) {
uni.navigateTo({
url: "/pages/mine/profile/index",
});
}
};
// 账号和安全
const navigateToAccount = () => {
uni.navigateTo({ url: "/pages/mine/settings/account/index" });
if (checkLogin()) {
uni.navigateTo({
url: "/pages/mine/settings/account/index",
});
}
};
// 主题设置
const navigateToTheme = () => {
uni.navigateTo({
url: "/pages/mine/settings/theme/index",
});
};
// 用户协议
const navigateToUserAgreement = () => {
uni.navigateTo({ url: "/pages/mine/settings/agreement/index" });
uni.navigateTo({
url: "/pages/mine/agreements/user-agreement",
});
};
// 隐私政策
const navigateToPrivacy = () => {
uni.navigateTo({ url: "/pages/mine/settings/privacy/index" });
uni.navigateTo({
url: "/pages/mine/agreements/privacy-policy",
});
};
// 主题设置
const navigateToTheme = () => {
uni.navigateTo({ url: "/pages/mine/settings/theme/index" });
// 关于我们
const navigateToAbout = () => {
uni.navigateTo({
url: "/pages/mine/about/index",
});
};
// 网络测试
const navigateToNetworkTest = () => {
uni.navigateTo({ url: "/pages/mine/settings/network/index" });
@@ -145,10 +176,18 @@ const handleClearCache = async () => {
// 退出登录
const handleLogout = () => {
userStore.logout().then(() => {
uni.showToast({ title: "已退出登录", icon: "success" });
// 跳转到登录页
uni.reLaunch({ url: "/pages/mine/index" });
uni.showModal({
title: "提示",
content: "确定要退出登录吗?",
success: function (res) {
if (res.confirm) {
userStore.logout();
uni.showToast({
title: "已退出登录",
icon: "success",
});
}
},
});
};
@@ -161,6 +200,7 @@ onLoad(() => {
</script>
<style lang="scss" scoped>
.settings-container {
min-height: 100vh;
padding: 20px;
.loading-mask {
@@ -199,5 +239,33 @@ onLoad(() => {
}
}
}
.logout-section {
display: flex;
align-items: center;
justify-content: center;
padding: 0 20rpx;
margin-top: 60rpx;
}
.logout-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 90rpx;
font-size: 32rpx;
font-weight: 500;
color: #fff;
background-color: var(--primary-color);
border: none;
border-radius: 45rpx;
box-shadow: 0 4rpx 12rpx rgba(var(--primary-color-rgb), 0.3);
transition: opacity 0.2s;
&:active {
opacity: 0.85;
}
}
}
</style>

View File

@@ -54,8 +54,9 @@
</template>
<script lang="ts" setup>
import { onLoad } from "@dcloudio/uni-app";
import { onLoad, onShow } from "@dcloudio/uni-app";
import { useThemeStore } from "@/store";
import { applyThemeOnPageShow } from "@/utils/theme";
const themeStore = useThemeStore();
@@ -138,6 +139,22 @@ onLoad(() => {
// 初始化自定义颜色输入框
customColor.value = themeStore.primaryColor;
});
// 页面显示时重新应用主题(解决小程序环境问题)
onShow(() => {
// 在小程序环境中,页面显示时重新应用主题
if (typeof document === "undefined") {
applyThemeOnPageShow(themeStore.primaryColor);
// 为了确保样式应用,我们可以在页面中设置内联样式
// 这样可以绕过小程序的CSS变量限制
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
if (currentPage) {
console.log("当前页面重新应用主题色");
}
}
});
</script>
<style lang="scss" scoped>
@@ -245,30 +262,30 @@ onLoad(() => {
display: flex;
align-items: center;
justify-content: center;
}
.preview-button {
width: 200rpx;
height: 80rpx;
font-size: 28rpx;
line-height: 80rpx;
color: #fff;
text-align: center;
border-radius: 8rpx;
}
.preview-button {
width: 100%;
height: 80rpx;
line-height: 80rpx;
color: #fff;
text-align: center;
border-radius: 8rpx;
}
.preview-text {
font-size: 32rpx;
font-weight: bold;
}
.preview-text {
font-size: 32rpx;
font-weight: 500;
}
.preview-border {
width: 200rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border: 2px solid;
border-radius: 8rpx;
}
.preview-border {
width: 100%;
height: 80rpx;
line-height: 80rpx;
text-align: center;
background-color: #f5f5f5;
border: 2px solid;
border-radius: 8rpx;
}
}
}
@@ -276,10 +293,9 @@ onLoad(() => {
.reset-btn {
width: 100%;
height: 80rpx;
margin-bottom: 30rpx;
font-size: 28rpx;
line-height: 80rpx;
color: #666;
color: #333;
background-color: #f5f5f5;
border: none;
border-radius: 8rpx;

View File

@@ -11,8 +11,8 @@
placeholder="请输入关键字"
/>
<view class="flex-between py-2">
<wd-button custom-class="w-20per" type="info" @click="handleResetQuery">重置</wd-button>
<wd-button custom-class="w-70per" @click="handleQuery">确定</wd-button>
<wd-button custom-class="w-20%" type="info" @click="handleResetQuery">重置</wd-button>
<wd-button custom-class="w-70%" @click="handleQuery">确定</wd-button>
</view>
</view>
</wd-drop-menu-item>

View File

@@ -1,5 +1,7 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { applyThemeToMiniProgram } from "@/utils/theme";
import { getLighterColor, getDarkerColor } from "@/utils/colorUtils";
// 从缓存获取主题色
const getThemeColor = (): string => {
@@ -21,52 +23,20 @@ export const useThemeStore = defineStore("theme", () => {
primaryColor.value = color;
setThemeColorCache(color);
// 设置CSS变量方便全局使用
document.documentElement.style.setProperty("--primary-color", color);
// 检测运行环境,区分处理
if (typeof document !== "undefined") {
// H5环境
document.documentElement.style.setProperty("--primary-color", color);
// 计算衍生色
const lighterColor = getLighterColor(color, 0.8);
const darkerColor = getDarkerColor(color, 0.8);
document.documentElement.style.setProperty("--primary-color-light", lighterColor);
document.documentElement.style.setProperty("--primary-color-dark", darkerColor);
};
// 获取浅色版本主题色
const getLighterColor = (hexColor: string, factor: number): string => {
// 去掉#前缀
const hex = hexColor.replace("#", "");
// 解析RGB值
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// 调亮颜色
r = Math.min(255, Math.floor(r + (255 - r) * factor));
g = Math.min(255, Math.floor(g + (255 - g) * factor));
b = Math.min(255, Math.floor(b + (255 - b) * factor));
// 转回16进制
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
};
// 获取深色版本主题色
const getDarkerColor = (hexColor: string, factor: number): string => {
// 去掉#前缀
const hex = hexColor.replace("#", "");
// 解析RGB值
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// 调暗颜色
r = Math.max(0, Math.floor(r * factor));
g = Math.max(0, Math.floor(g * factor));
b = Math.max(0, Math.floor(b * factor));
// 转回16进制
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
// 计算衍生色
const lighterColor = getLighterColor(color, 0.8);
const darkerColor = getDarkerColor(color, 0.8);
document.documentElement.style.setProperty("--primary-color-light", lighterColor);
document.documentElement.style.setProperty("--primary-color-dark", darkerColor);
} else {
// 小程序环境
applyThemeToMiniProgram(color);
}
};
// 初始化,应用主题色

51
src/utils/colorUtils.ts Normal file
View File

@@ -0,0 +1,51 @@
/**
* 颜色处理工具类
*/
/**
* 获取浅色版本的颜色
* @param hexColor 十六进制颜色值
* @param factor 调亮因子 (0-1)
* @returns 调亮后的颜色值
*/
export function getLighterColor(hexColor: string, factor: number): string {
// 去掉#前缀
const hex = hexColor.replace("#", "");
// 解析RGB值
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// 调亮颜色
r = Math.min(255, Math.floor(r + (255 - r) * factor));
g = Math.min(255, Math.floor(g + (255 - g) * factor));
b = Math.min(255, Math.floor(b + (255 - b) * factor));
// 转回16进制
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
}
/**
* 获取深色版本的颜色
* @param hexColor 十六进制颜色值
* @param factor 调暗因子 (0-1)
* @returns 调暗后的颜色值
*/
export function getDarkerColor(hexColor: string, factor: number): string {
// 去掉#前缀
const hex = hexColor.replace("#", "");
// 解析RGB值
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// 调暗颜色
r = Math.max(0, Math.floor(r * factor));
g = Math.max(0, Math.floor(g * factor));
b = Math.max(0, Math.floor(b * factor));
// 转回16进制
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
}

33
src/utils/theme.ts Normal file
View File

@@ -0,0 +1,33 @@
/**
* 小程序主题工具类
* 用于解决小程序环境中CSS变量不能动态设置的问题
*/
// 注入小程序环境的全局样式
export function applyThemeToMiniProgram(primaryColor: string) {
// 确保在小程序环境中执行
if (typeof document !== "undefined") return;
try {
// 设置TabBar样式
uni.setTabBarStyle({
color: "#000000",
selectedColor: primaryColor,
backgroundColor: "#ffffff",
borderStyle: "black",
});
console.log("小程序主题色已应用:", primaryColor);
} catch (error) {
console.error("应用小程序主题色失败:", error);
}
}
// 在页面展示时应用主题
export function applyThemeOnPageShow(primaryColor: string) {
// 各平台小程序可能需要不同处理
const platform = uni.getSystemInfoSync().platform;
console.log(`当前平台: ${platform}, 应用主题色: ${primaryColor}`);
// 某些平台可能需要特定处理
}