refactor: ♻️ 暗黑模式适配调整和代码优化

This commit is contained in:
ray
2025-10-04 10:11:47 +08:00
parent 8b2ae01a9a
commit 12454c9301
13 changed files with 813 additions and 805 deletions

View File

@@ -0,0 +1,250 @@
---
alwaysApply: true
---
# CSS样式与UnoCSS使用规范
## 样式选择原则
### UnoCSS原子类使用规则
- **≤5个原子类**: 直接使用UnoCSS原子类
- **>5个原子类**: 必须提取为语义化CSS类,避免模板膨胀
```vue
<!-- ✅ 好的做法:5个以内原子类 -->
<view class="flex items-center p-20rpx text-center bg-white"></view>
```
### 优先使用UnoCSS预设shortcuts
参考 [unocss.config.ts](mdc:unocss.config.ts) 中定义的shortcuts:
```typescript
// 已定义的shortcuts,优先使用
"flex-center": "flex justify-center items-center"
"flex-start": "flex justify-start items-center"
"flex-between": "flex justify-between items-center"
"flex-col-center": "flex flex-col items-center"
```
## CSS类命名规范
### BEM命名规范
严格遵循BEM (Block\_\_Element--Modifier) 命名规范:
```scss
// Block: 独立的功能组件
.user-profile {
}
// Element: Block的子元素
.user-profile__avatar {
}
.user-profile__action {
}
.user-profile__badge {
}
// Modifier: Block或Element的状态/变体
.user-profile--dark {
}
.user-profile__action--active {
}
```
### 命名要求
1. **使用简短、易理解的英文单词**
2. **符合业务场景语义**
3. **避免缩写,除非是通用缩写**
```scss
// ✅ 好的命名
.user-profile__action
.stats-card
.service-icon
.tool-item
// ❌ 坏的命名
.up-act
.sc
.si
.ti
```
## 样式组织原则
### 1. 复用性判断
- 同一组合在项目中出现 >3次 → 提取为语义化类
- 具备明确语义的区域 → 提取为语义化类
- 需要主题适配的样式 → 提取为语义化类
### 2. 常用组合添加到shortcuts
当发现重复的原子类组合时,添加到 [unocss.config.ts](mdc:unocss.config.ts):
```typescript
shortcuts: [
{
// 现有shortcuts...
// 新增常用组合
"card-container": "mx-30rpx my-20rpx bg-white rounded-16rpx shadow-sm",
"action-button": "flex-center w-70rpx h-70rpx bg-white bg-opacity-90 rounded-full",
},
];
```
### 3. 主题适配
使用wot-design-uni的CSS变量或自定义变量:
```scss
// ✅ 使用主题变量
.service-icon {
background-color: var(--wot-color-bg-light, #f3f4f6);
}
// ✅ 响应式主题色
:color="themeStore.isDark ? '#fff' : '#333'";
```
### 4. 暗黑模式适配规则
#### 优先级顺序
1. **优先使用wot-design-uni内置变量** - 自动适配暗黑模式
2. **使用项目 [theme.scss](mdc:src/styles/theme.scss) 定义的变量** - 统一管理主题色
3. **最后考虑组件内部定义** - 仅用于特殊场景
#### 自定义主题变量定义
当需要自定义颜色时,必须在 [theme.scss](mdc:src/styles/theme.scss) 中定义:
```scss
/* 在 theme.scss 中添加自定义变量 */
:root,
page {
--custom-text-color: #333333;
--custom-bg-color: #ffffff;
--custom-border-color: #e5e7eb;
}
.wot-theme-dark {
--custom-text-color: #ffffff;
--custom-bg-color: #1a1a1a;
--custom-border-color: #374151;
}
```
#### 组件中使用主题变量
```scss
// ✅ 推荐:使用wot内置变量
.my-component {
background-color: var(--wot-card-bg);
color: var(--wot-color-text);
}
// ✅ 推荐:使用theme.scss定义的变量
.my-component {
background-color: var(--custom-bg-color);
border-color: var(--custom-border-color);
}
// ❌ 避免:组件内部硬编码暗黑模式
.my-component {
background-color: #ffffff;
}
.wot-theme-dark .my-component {
background-color: #1a1a1a;
}
```
#### 图标和文字颜色适配
```vue
<template>
<!-- ✅ 推荐:使用计算属性适配 -->
<wd-icon :color="iconColor" />
<!-- ✅ 推荐:使用CSS变量 -->
<text style="color: var(--wot-color-text)">文本</text>
</template>
<script setup>
// 图标颜色适配
const iconColor = computed(() => (themeStore.isDark ? "#ffffff" : "#333333"));
</script>
```
## 实践示例
### 数据统计卡片
```vue
<!-- 使用wot组件 + 少量原子类 -->
<wd-card custom-class="mx-30rpx my-20rpx">
<wd-grid :column="3" border>
<wd-grid-item class="flex-col-center py-20rpx">
<view class="text-36rpx font-600">0.00</view>
<view class="text-26rpx text-gray-500">我的余额</view>
</wd-grid-item>
</wd-grid>
</wd-card>
```
### 用户操作按钮
```vue
<template>
<view class="user-profile__action" @click="handleClick">
<wd-icon name="setting1" :color="iconColor" />
</view>
</template>
<style scoped>
.user-profile__action {
display: flex;
align-items: center;
justify-content: center;
width: 70rpx;
height: 70rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 50%;
}
</style>
```
## 禁止项
❌ **不要在SCSS中重复定义UnoCSS已提供的工具类**
❌ **不要使用 `@apply` 指令**
❌ **不要把一次性样式放到全局**
❌ **不要使用非语义化的类名**
❌ **不要在模板中堆叠超过5个原子类**
## 组件库样式覆盖
使用wot-design-uni组件时:
- 使用 `custom-class` 传入类名
- 使用 `:deep()` 进行样式穿透
- 添加 `!important` 提升优先级
```vue
<wd-button custom-class="logout-button" @click="logout">
退出登录
</wd-button>
<style scoped>
:deep(.logout-button) {
width: 100% !important;
height: 80rpx !important;
border-radius: 40rpx !important;
}
</style>
```

6
components.d.ts vendored
View File

@@ -26,7 +26,6 @@ declare module 'vue' {
WdConfigProvider: typeof import('wot-design-uni/components/wd-config-provider/wd-config-provider.vue')['default'] WdConfigProvider: typeof import('wot-design-uni/components/wd-config-provider/wd-config-provider.vue')['default']
WdDivider: typeof import('wot-design-uni/components/wd-divider/wd-divider.vue')['default'] WdDivider: typeof import('wot-design-uni/components/wd-divider/wd-divider.vue')['default']
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default'] WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
WdFormItem: typeof import('wot-design-uni/components/wd-form-item/wd-form-item.vue')['default']
WdGrid: typeof import('wot-design-uni/components/wd-grid/wd-grid.vue')['default'] WdGrid: typeof import('wot-design-uni/components/wd-grid/wd-grid.vue')['default']
WdGridItem: typeof import('wot-design-uni/components/wd-grid-item/wd-grid-item.vue')['default'] WdGridItem: typeof import('wot-design-uni/components/wd-grid-item/wd-grid-item.vue')['default']
WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default'] WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default']
@@ -35,10 +34,10 @@ declare module 'vue' {
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default'] WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
WdLoading: typeof import('wot-design-uni/components/wd-loading/wd-loading.vue')['default'] WdLoading: typeof import('wot-design-uni/components/wd-loading/wd-loading.vue')['default']
WdMessageBox: typeof import('wot-design-uni/components/wd-message-box/wd-message-box.vue')['default'] WdMessageBox: typeof import('wot-design-uni/components/wd-message-box/wd-message-box.vue')['default']
WdNavbar: typeof import('wot-design-uni/components/wd-navbar/wd-navbar.vue')['default']
WdNoticeBar: typeof import('wot-design-uni/components/wd-notice-bar/wd-notice-bar.vue')['default'] WdNoticeBar: typeof import('wot-design-uni/components/wd-notice-bar/wd-notice-bar.vue')['default']
WdNotify: typeof import('wot-design-uni/components/wd-notify/wd-notify.vue')['default'] WdNotify: typeof import('wot-design-uni/components/wd-notify/wd-notify.vue')['default']
WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default'] WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default']
WdProgress: typeof import('wot-design-uni/components/wd-progress/wd-progress.vue')['default']
WdRadio: typeof import('wot-design-uni/components/wd-radio/wd-radio.vue')['default'] WdRadio: typeof import('wot-design-uni/components/wd-radio/wd-radio.vue')['default']
WdRadioGroup: typeof import('wot-design-uni/components/wd-radio-group/wd-radio-group.vue')['default'] WdRadioGroup: typeof import('wot-design-uni/components/wd-radio-group/wd-radio-group.vue')['default']
WdStatusTip: typeof import('wot-design-uni/components/wd-status-tip/wd-status-tip.vue')['default'] WdStatusTip: typeof import('wot-design-uni/components/wd-status-tip/wd-status-tip.vue')['default']
@@ -47,9 +46,6 @@ declare module 'vue' {
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default'] WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default'] WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
WdTag: typeof import('wot-design-uni/components/wd-tag/wd-tag.vue')['default'] WdTag: typeof import('wot-design-uni/components/wd-tag/wd-tag.vue')['default']
WdText: typeof import('wot-design-uni/components/wd-text/wd-text.vue')['default']
WdTextarea: typeof import('wot-design-uni/components/wd-textarea/wd-textarea.vue')['default']
WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default'] WdToast: typeof import('wot-design-uni/components/wd-toast/wd-toast.vue')['default']
WdUpload: typeof import('wot-design-uni/components/wd-upload/wd-upload.vue')['default']
} }
} }

View File

@@ -95,7 +95,7 @@
"@vueuse/core": "9.13.0", "@vueuse/core": "9.13.0",
"pinia": "^2.2.2", "pinia": "^2.2.2",
"vue": "^3.5.13", "vue": "^3.5.13",
"wot-design-uni": "^1.9.1" "wot-design-uni": "^1.13.0"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^19.5.0", "@commitlint/cli": "^19.5.0",

View File

@@ -7,7 +7,7 @@ export default defineUniPages({
globalStyle: { globalStyle: {
navigationBarBackgroundColor: "@navBgColor", navigationBarBackgroundColor: "@navBgColor",
navigationBarTextStyle: "@navTxtStyle", navigationBarTextStyle: "@navTxtStyle",
navigationBarTitleText: "Wot-Demo", navigationBarTitleText: "vue-uniapp-template",
backgroundColor: "@bgColor", backgroundColor: "@bgColor",
backgroundTextStyle: "@bgTxtStyle", backgroundTextStyle: "@bgTxtStyle",
backgroundColorTop: "@bgColorTop", backgroundColorTop: "@bgColorTop",

View File

@@ -1,5 +1,5 @@
import { getToken } from "@/utils/storage"; import { getToken } from "@/utils/storage";
import { ApiCode } from "@/enums/api-code.enum"; import { ApiCode } from "@/enums/api-code-enum";
// H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_APP_API_URL 作为请求路径 // H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_APP_API_URL 作为请求路径
let baseApi = import.meta.env.VITE_APP_API_URL; let baseApi = import.meta.env.VITE_APP_API_URL;

View File

@@ -66,7 +66,17 @@ export default {
<style lang="scss"> <style lang="scss">
.page-wraper { .page-wraper {
box-sizing: border-box; box-sizing: border-box;
// 页面最小高度 = 视窗高度 - 状态栏高度
// --window-top: uni-app提供的状态栏高度CSS变量(包含状态栏+导航栏)
min-height: calc(100vh - var(--window-top)); min-height: calc(100vh - var(--window-top));
// 为固定定位的tabbar预留底部空间,避免内容被遮挡
// 50px: wd-tabbar组件的固定高度
// env(safe-area-inset-bottom): iOS设备底部安全区域高度(iPhone X系列的Home Indicator区域)
// 34px: 当设备不支持safe-area-inset-bottom时的降级值(一般Android设备)
padding-bottom: calc(50px + env(safe-area-inset-bottom, 34px));
background: #f9f9f9; background: #f9f9f9;
} }

View File

@@ -11,7 +11,10 @@
}, },
{ {
"path": "pages/login/index", "path": "pages/login/index",
"type": "page" "type": "page",
"style": {
"navigationStyle": "custom"
}
}, },
{ {
"path": "pages/mine/index", "path": "pages/mine/index",
@@ -96,7 +99,7 @@
"globalStyle": { "globalStyle": {
"navigationBarBackgroundColor": "@navBgColor", "navigationBarBackgroundColor": "@navBgColor",
"navigationBarTextStyle": "@navTxtStyle", "navigationBarTextStyle": "@navTxtStyle",
"navigationBarTitleText": "Wot-Demo", "navigationBarTitleText": "vue-uniapp-template",
"backgroundColor": "@bgColor", "backgroundColor": "@bgColor",
"backgroundTextStyle": "@bgTxtStyle", "backgroundTextStyle": "@bgTxtStyle",
"backgroundColorTop": "@bgColorTop", "backgroundColorTop": "@bgColorTop",
@@ -124,6 +127,5 @@
} }
] ]
}, },
"__esModule": true,
"subPackages": [] "subPackages": []
} }

View File

@@ -1,107 +1,103 @@
<template> <template>
<view class="app-container"> <view class="login-page dark:text-[var(--wot-dark-color)]">
<!-- 背景图 --> <!-- 背景图 -->
<image src="/static/images/login-bg.svg" mode="aspectFill" class="login-bg" /> <image src="/static/images/login-bg.svg" mode="aspectFill" class="login-page__bg" />
<!-- Logo和标题区域 -->
<view class="header"></view>
<!-- 登录卡片 -->
<view class="login-card"> <view class="login-card">
<view class="form-wrap"> <!-- 账号密码登录表单 -->
<!-- 账号密码登录表单 --> <wd-form v-if="loginType === 'account'" ref="loginFormRef" :model="loginFormData">
<wd-form v-if="loginType === 'account'" ref="loginFormRef" :model="loginFormData"> <!-- 用户名输入框 -->
<!-- 用户名输入框 --> <view class="login-form__item">
<view class="form-item"> <wd-icon name="user" size="22" class="mr-20rpx" />
<wd-icon name="user" size="22" class="input-icon" /> <input
<input v-model="loginFormData.username"
v-model="loginFormData.username" class="login-form__input"
class="form-input input-transparent" placeholder="请输入用户名"
placeholder="请输入用户名" placeholder-class="login-form__placeholder"
placeholder-class="input-placeholder" />
/> </view>
</view> <view class="login-form__divider"></view>
<view class="divider"></view>
<!-- 密码输入框 --> <!-- 密码输入框 -->
<view class="form-item"> <view class="login-form__item">
<wd-icon name="lock-on" size="22" class="input-icon" /> <wd-icon name="lock-on" size="22" class="mr-20rpx" />
<input <input
v-model="loginFormData.password" v-model="loginFormData.password"
class="form-input input-transparent" class="login-form__input"
:password="!showPassword" :password="!showPassword"
placeholder="请输入密码" placeholder="请输入密码"
placeholder-class="input-placeholder" placeholder-class="login-form__placeholder"
/> />
<wd-icon <wd-icon
:name="showPassword ? 'eye-open' : 'eye-close'" :name="showPassword ? 'eye-open' : 'eye-close'"
size="18" size="18"
class="eye-icon" class="p-10rpx"
@click="showPassword = !showPassword" @click="showPassword = !showPassword"
/> />
</view> </view>
<view class="divider"></view> <view class="login-form__divider"></view>
<!-- 登录按钮 --> <!-- 登录按钮 -->
<button <button
class="login-btn" class="login-btn"
:disabled="loading" :disabled="loading"
:style="loading ? 'opacity: 0.7;' : ''" :class="{ 'login-btn--loading': loading }"
@click="handleAccountLogin" @click="handleAccountLogin"
> >
{{ loading ? "登录中..." : "账号登录" }} {{ loading ? "登录中..." : "账号登录" }}
</button> </button>
<!-- 切换登录方式 --> <!-- 切换登录方式 -->
<view class="switch-login-type" @click="loginType = 'phone'"> <view class="login-switch" @click="loginType = 'phone'">
<text>使用手机号一键登录</text> <text>使用手机号一键登录</text>
<wd-icon name="arrow-right" size="12" /> <wd-icon name="arrow-right" size="12" />
</view> </view>
</wd-form> </wd-form>
<!-- 手机号登录 --> <!-- 手机号登录 -->
<view v-else class="phone-login-form"> <view v-else class="phone-login">
<view class="phone-login-title">微信一键登录</view> <view class="phone-login__title">微信一键登录</view>
<view class="phone-login-subtitle">授权后将获取您的手机号</view> <view class="phone-login__subtitle">授权后将获取您的手机号</view>
<button <button
class="wechat-phone-btn" class="wechat-btn"
:disabled="loading" :disabled="loading"
open-type="getPhoneNumber" open-type="getPhoneNumber"
@getphonenumber="handleWechatPhoneLogin" @getphonenumber="handleWechatPhoneLogin"
> >
<wd-icon name="weixin" size="24" color="#ffffff" /> <wd-icon name="weixin" size="24" color="#ffffff" />
<text>微信一键登录</text> <text class="ml-16rpx">微信一键登录</text>
</button> </button>
<!-- 切换登录方式 --> <!-- 切换登录方式 -->
<view class="switch-login-type" @click="loginType = 'account'"> <view class="login-switch" @click="loginType = 'account'">
<text>使用账号密码登录</text> <text>使用账号密码登录</text>
<wd-icon name="arrow-right" size="12" /> <wd-icon name="arrow-right" size="12" />
</view> </view>
</view>
<!-- 其他登录方式 -->
<view class="other-login">
<view class="other-login__title">
<view class="other-login__line"></view>
<text class="other-login__text">其他登录方式</text>
<view class="other-login__line"></view>
</view> </view>
<!-- 其他登录方式 --> <view class="flex-center" @click="handleWechatLogin">
<view class="other-login"> <view class="wechat-icon">
<view class="other-login-title"> <image src="/static/icons/weixin.png" class="w-40rpx h-40rpx" />
<view class="line"></view>
<text class="text">其他登录方式</text>
<view class="line"></view>
</view>
<view class="wechat-login" @click="handleWechatLogin">
<view class="wechat-icon-wrapper">
<image src="/static/icons/weixin.png" class="wechat-icon" />
</view>
</view> </view>
</view> </view>
</view>
<!-- 底部协议 --> <!-- 底部协议 -->
<view class="agreement"> <view class="login-agreement">
<text class="text">登录即同意</text> <text class="login-agreement__text">登录即同意</text>
<text class="link" @click="navigateToUserAgreement">《用户协议》</text> <text class="login-agreement__link" @click="navigateToUserAgreement">《用户协议》</text>
<text class="text">和</text> <text class="login-agreement__text">和</text>
<text class="link" @click="navigateToPrivacy">《隐私政策》</text> <text class="login-agreement__link" @click="navigateToPrivacy">《隐私政策》</text>
</view>
</view> </view>
</view> </view>
@@ -285,169 +281,87 @@ const navigateToPrivacy = () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-container { // 登录页面主容器
.login-page {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
height: 100%;
min-height: 100vh; min-height: 100vh;
overflow: hidden; overflow: hidden;
background-color: var(--wot-color-bg-container); background-color: var(--wot-color-bg-container);
// 背景图
&__bg {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
}
} }
.login-bg { // 登录卡片
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.header {
z-index: 2;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 120rpx;
}
.logo {
width: 140rpx;
height: 140rpx;
margin-bottom: 20rpx;
}
.title {
margin-bottom: 10rpx;
font-size: 48rpx;
font-weight: bold;
color: #ffffff;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.subtitle {
font-size: 28rpx;
color: #ffffff;
text-align: center;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.login-card { .login-card {
z-index: 2;
display: flex;
flex-direction: column;
width: 90%;
margin-top: 80rpx;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 24rpx;
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.1);
.wot-theme-dark & {
background-color: rgba(31, 31, 31, 0.95);
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.5);
}
}
.form-wrap {
padding: 40rpx;
}
.form-item {
position: relative; position: relative;
display: flex; z-index: 2;
align-items: center; width: 80%; // 进一步减少宽度,增加更多左右间距
padding: 24rpx 0; padding: 40rpx;
background-color: transparent; margin-top: 200rpx;
background-color: var(--wot-card-bg);
border-radius: 24rpx;
}
.wot-theme-dark & { // 登录表单
background-color: transparent; .login-form {
&__item {
display: flex;
align-items: center;
padding: 24rpx 0;
} }
}
.input-icon { &__input {
margin-right: 20rpx; flex: 1;
} height: 60rpx;
font-size: 28rpx;
/* 强制所有输入元素为透明背景 */ line-height: 60rpx;
input, color: var(--wot-color-text);
.form-input,
.input-transparent {
flex: 1;
height: 60rpx;
font-size: 28rpx;
line-height: 60rpx;
color: #333;
background-color: transparent !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
.wot-theme-dark & {
color: #f5f5f5;
background-color: transparent !important; background-color: transparent !important;
border: none;
outline: none;
}
&__divider {
height: 1px;
background-color: var(--wot-color-border-light);
}
&__placeholder {
color: var(--wot-color-text-placeholder);
} }
} }
/* 修复webkit浏览器自动填充问题 */ // 登录按钮
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
caret-color: var(--wot-color-text);
background-color: transparent !important;
-webkit-box-shadow: 0 0 0 1000px transparent inset !important;
transition: background-color 5000s;
-webkit-text-fill-color: var(--wot-color-text) !important;
.wot-theme-dark & {
-webkit-text-fill-color: #f5f5f5 !important;
background-color: transparent !important;
-webkit-box-shadow: 0 0 0 1000px rgba(31, 31, 31, 0) inset !important;
}
}
/* 尝试通过更强的选择器覆盖自动填充 */
.form-item input,
input.form-input,
input.input-transparent {
-webkit-appearance: none;
background: none !important;
background-color: transparent !important;
border: none !important;
}
.clear-icon,
.eye-icon {
padding: 10rpx;
}
.divider {
height: 1px;
margin: 0;
background-color: rgba(0, 0, 0, 0.06);
.wot-theme-dark & {
background-color: rgba(255, 255, 255, 0.15);
}
}
.login-btn { .login-btn {
width: 100%; width: 100%;
height: 88rpx; height: 88rpx;
margin-top: 60rpx; margin-top: 60rpx;
font-size: 32rpx; font-size: 32rpx;
font-weight: 500; font-weight: 500;
line-height: 88rpx;
color: #fff; color: #fff;
text-align: center;
background-color: var(--wot-color-theme); background-color: var(--wot-color-theme);
border: none; border: none;
border-radius: 44rpx; border-radius: 44rpx;
transition: opacity 0.2s;
&--loading {
opacity: 0.7;
}
} }
.switch-login-type { // 切换登录方式
.login-switch {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -456,35 +370,29 @@ input.input-transparent {
color: var(--wot-color-theme); color: var(--wot-color-theme);
} }
.phone-login-form { // 手机号登录
.phone-login {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
padding: 40rpx 0; padding: 40rpx 0;
}
.phone-login-title { &__title {
margin-bottom: 16rpx; margin-bottom: 16rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
color: #333; color: var(--wot-color-text);
}
.wot-theme-dark & { &__subtitle {
color: #f5f5f5; margin-bottom: 60rpx;
font-size: 28rpx;
color: var(--wot-color-text-secondary);
} }
} }
.phone-login-subtitle { // 微信按钮
margin-bottom: 60rpx; .wechat-btn {
font-size: 28rpx;
color: #666;
.wot-theme-dark & {
color: #c0c0c0;
}
}
.wechat-phone-btn {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -495,49 +403,34 @@ input.input-transparent {
background-color: #07c160; background-color: #07c160;
border: none; border: none;
border-radius: 44rpx; border-radius: 44rpx;
text {
margin-left: 16rpx;
}
} }
// 其他登录方式
.other-login { .other-login {
margin-top: 60rpx; margin-top: 60rpx;
}
.other-login-title { &__title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-bottom: 40rpx; margin-bottom: 40rpx;
} }
.line { &__line {
width: 80rpx; width: 80rpx;
height: 1rpx; height: 1rpx;
background-color: rgba(0, 0, 0, 0.1); background-color: var(--wot-color-border-light);
}
.wot-theme-dark & { &__text {
background-color: rgba(255, 255, 255, 0.2); margin: 0 20rpx;
font-size: 26rpx;
color: var(--wot-color-text-secondary);
} }
} }
.text { // 微信图标
margin: 0 20rpx; .wechat-icon {
font-size: 26rpx;
color: rgba(0, 0, 0, 0.4);
.wot-theme-dark & {
color: rgba(255, 255, 255, 0.6);
}
}
.wechat-login {
display: flex;
justify-content: center;
}
.wechat-icon-wrapper {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -545,59 +438,21 @@ input.input-transparent {
height: 80rpx; height: 80rpx;
background-color: #07c160; background-color: #07c160;
border-radius: 50%; border-radius: 50%;
.wot-theme-dark & {
box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3);
}
} }
.wechat-icon { // 登录协议
width: 40rpx; .login-agreement {
height: 40rpx;
}
.agreement {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 60rpx; margin-top: 60rpx;
font-size: 24rpx; font-size: 24rpx;
}
.link { &__text {
color: var(--wot-color-theme); color: var(--wot-color-text-secondary);
}
.input-placeholder {
color: rgba(0, 0, 0, 0.3);
.wot-theme-dark & {
color: rgba(255, 255, 255, 0.4);
}
}
/* 加强输入框透明度 - 暗黑模式特别处理 */
.wot-theme-dark {
:deep(input) {
background: none !important;
background-color: transparent !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
} }
.form-input, &__link {
input { color: var(--wot-color-theme);
background: none !important;
background-color: transparent !important;
background-image: none !important;
}
}
/* 修复Android Chrome输入框背景色问题 */
@supports (-webkit-appearance: none) {
input {
-webkit-appearance: none;
background: transparent !important;
background-color: transparent !important;
} }
} }
</style> </style>

View File

@@ -30,125 +30,144 @@
</wd-button> </wd-button>
</block> </block>
</view> </view>
<view class="actions"> <view class="flex">
<view class="action-btn" @click="navigateToSettings"> <view class="user-profile__action" @click="navigateToSettings">
<wd-icon name="setting1" size="22" color="#333" /> <wd-icon name="setting1" size="22" :color="themeStore.isDark ? '#fff' : '#333'" />
</view> </view>
<view v-if="isLogin" class="action-btn" @click="navigateToSection('messages')"> <view
<wd-icon name="notification" size="22" color="#333" /> v-if="isLogin"
<view v-if="true" class="badge">2</view> class="user-profile__action relative ml-16rpx"
@click="navigateToSection('messages')"
>
<wd-icon name="notification" size="22" />
<view v-if="true" class="user-profile__badge">2</view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 数据统计 --> <!-- 数据统计 -->
<view class="stats-card"> <wd-card custom-class="mx-30rpx my-20rpx">
<view class="stats-item" @click="navigateToSection('wallet')"> <wd-grid :column="3" border>
<view class="mb-8rpx text-36rpx font-600">0.00</view> <wd-grid-item @click="navigateToSection('wallet')">
<view class="text-26rpx text-gray-500">我的余额</view> <view class="flex-col-center py-20rpx">
</view> <view class="mb-8rpx text-36rpx font-600">0.00</view>
<view class="stats-divider"></view> <view class="text-26rpx text-gray-500">我的余额</view>
<view class="stats-item" @click="navigateToSection('favorites')"> </view>
<view class="mb-8rpx text-36rpx font-600">0</view> </wd-grid-item>
<view class="text-26rpx text-gray-500">我的收藏</view> <wd-grid-item @click="navigateToSection('favorites')">
</view> <view class="flex-col-center py-20rpx">
<view class="stats-divider"></view> <view class="mb-8rpx text-36rpx font-600">0</view>
<view class="stats-item" @click="navigateToSection('history')"> <view class="text-26rpx text-gray-500">我的收藏</view>
<view class="mb-8rpx text-36rpx font-600">0</view> </view>
<view class="text-26rpx text-gray-500">浏览历史</view> </wd-grid-item>
</view> <wd-grid-item @click="navigateToSection('history')">
</view> <view class="flex-col-center py-20rpx">
<view class="mb-8rpx text-36rpx font-600">0</view>
<view class="text-26rpx text-gray-500">浏览历史</view>
</view>
</wd-grid-item>
</wd-grid>
</wd-card>
<!-- 常用工具 --> <!-- 常用工具 -->
<view class="card-container"> <wd-card>
<view class="card-header"> <template #header>
<view class="flex-start"> <view class="flex-start">
<wd-icon name="tools" size="18" :color="currentThemeColor" /> <wd-icon name="tools" size="18" :color="currentThemeColor" />
<text class="ml-12rpx text-28rpx font-600">常用工具</text> <text class="ml-12rpx text-28rpx font-600">常用工具</text>
</view> </view>
</view> </template>
<view class="flex flex-wrap p-20rpx pt-20rpx pb-10rpx">
<view class="tool-item" @click="navigateToProfile"> <wd-grid :column="4" border>
<view class="tool-icon"> <wd-grid-item @click="navigateToProfile">
<wd-icon name="user" size="24" :color="currentThemeColor" /> <view class="flex-col-center py-20rpx">
<view class="tool-icon mb-12rpx">
<wd-icon name="user" size="24" :color="currentThemeColor" />
</view>
<view class="text-24rpx">个人资料</view>
</view> </view>
<view class="text-24rpx">个人资料</view> </wd-grid-item>
</view> <wd-grid-item @click="navigateToFAQ">
<view class="tool-item" @click="navigateToFAQ"> <view class="flex-col-center py-20rpx">
<view class="tool-icon"> <view class="tool-icon mb-12rpx">
<wd-icon name="help-circle" size="24" :color="currentThemeColor" /> <wd-icon name="help-circle" size="24" :color="currentThemeColor" />
</view>
<view class="text-24rpx">常见问题</view>
</view> </view>
<view class="text-24rpx">常见问题</view> </wd-grid-item>
</view> <wd-grid-item @click="handleQuestionFeedback">
<view class="tool-item" @click="handleQuestionFeedback"> <view class="flex-col-center py-20rpx">
<view class="tool-icon"> <view class="tool-icon mb-12rpx">
<wd-icon name="check-circle" size="24" :color="currentThemeColor" /> <wd-icon name="check-circle" size="24" :color="currentThemeColor" />
</view>
<view class="text-24rpx">问题反馈</view>
</view> </view>
<view class="text-24rpx">问题反馈</view> </wd-grid-item>
</view> <wd-grid-item @click="navigateToAbout">
<view class="tool-item" @click="navigateToAbout"> <view class="flex-col-center py-20rpx">
<view class="tool-icon"> <view class="tool-icon mb-12rpx">
<wd-icon name="info-circle" size="24" :color="currentThemeColor" /> <wd-icon name="info-circle" size="24" :color="currentThemeColor" />
</view>
<view class="text-24rpx">关于我们</view>
</view> </view>
<view class="text-24rpx">关于我们</view> </wd-grid-item>
</view> </wd-grid>
</view> </wd-card>
</view>
<!-- 推荐服务 --> <!-- 推荐服务 -->
<view class="card-container"> <wd-card>
<view class="card-header"> <template #header>
<view class="flex-start"> <view class="flex-start">
<wd-icon name="star" size="18" :color="currentThemeColor" /> <wd-icon name="star" size="18" :color="currentThemeColor" />
<text class="ml-12rpx text-28rpx font-600">推荐服务</text> <text class="ml-12rpx text-28rpx font-600">推荐服务</text>
</view> </view>
</view> </template>
<view>
<view class="service-item" @click="navigateToSection('services', 'vip')"> <wd-cell-group>
<view class="flex-start"> <wd-cell
<view class="service-icon"> title="会员中心"
label="解锁更多特权"
is-link
@click="navigateToSection('services', 'vip')"
>
<template #icon>
<view class="service-icon mr-20rpx">
<wd-icon name="dong" size="22" :color="currentThemeColor" /> <wd-icon name="dong" size="22" :color="currentThemeColor" />
</view> </view>
<view> </template>
<view class="text-28rpx font-500">会员中心</view> </wd-cell>
<view class="mt-8rpx text-24rpx text-gray-500">解锁更多特权</view>
</view> <wd-cell
</view> title="优惠券"
<wd-icon name="arrow-right" size="14" /> label="查看我的优惠券"
</view> is-link
<view class="service-item" @click="navigateToSection('services', 'coupon')"> @click="navigateToSection('services', 'coupon')"
<view class="flex-start"> >
<view class="service-icon"> <template #icon>
<view class="service-icon mr-20rpx">
<wd-icon name="discount" size="22" :color="currentThemeColor" /> <wd-icon name="discount" size="22" :color="currentThemeColor" />
</view> </view>
<view> </template>
<view class="text-28rpx font-500">优惠券</view> </wd-cell>
<view class="mt-8rpx text-24rpx text-gray-500">查看我的优惠券</view>
</view> <wd-cell
</view> title="邀请有礼"
<wd-icon name="arrow-right" size="14" /> label="邀请好友得奖励"
</view> is-link
<view
class="service-item service-item-last"
@click="navigateToSection('services', 'invite')" @click="navigateToSection('services', 'invite')"
> >
<view class="flex-start"> <template #icon>
<view class="service-icon"> <view class="service-icon mr-20rpx">
<wd-icon name="share" size="22" :color="currentThemeColor" /> <wd-icon name="share" size="22" :color="currentThemeColor" />
</view> </view>
<view> </template>
<view class="text-28rpx font-500">邀请有礼</view> </wd-cell>
<view class="mt-8rpx text-24rpx text-gray-500">邀请好友得奖励</view> </wd-cell-group>
</view> </wd-card>
</view>
<wd-icon name="arrow-right" size="14" />
</view>
</view>
</view>
<!-- 退出登录按钮 --> <!-- 退出登录按钮 -->
<view v-if="isLogin" class="p-30rpx"> <view v-if="isLogin">
<wd-button custom-class="logout-button" plain @click="handleLogout">退出登录</wd-button> <wd-button custom-class="logout-button" plain @click="handleLogout">退出登录</wd-button>
</view> </view>
@@ -299,156 +318,35 @@ const navigateToSection = (section: string, subSection?: string) => {
} }
} }
.actions { // BEM命名规范的用户操作按钮
.user-profile__action {
display: flex; display: flex;
align-items: center;
.action-btn { justify-content: center;
position: relative; width: 70rpx;
display: flex; height: 70rpx;
align-items: center; background-color: rgba(255, 255, 255, 0.9);
justify-content: center; border-radius: 50%;
width: 70rpx; // 移除无效果的box-shadow
height: 70rpx;
margin-left: 16rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 50%;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.badge {
position: absolute;
top: -6rpx;
right: -6rpx;
z-index: 2;
min-width: 32rpx;
height: 32rpx;
padding: 0 6rpx;
font-size: 20rpx;
line-height: 32rpx;
color: #fff;
text-align: center;
background-color: var(--wot-color-danger);
border: 2rpx solid #fff;
border-radius: 16rpx;
}
}
} }
}
}
// 卡片容器 // 通知徽章 - 超过5个原子类,使用CSS类
.card-container { .user-profile__badge {
margin: 24rpx 30rpx; position: absolute;
overflow: hidden; top: -6rpx;
background-color: #fff; right: -6rpx;
border-radius: 16rpx; z-index: 2;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1); min-width: 32rpx;
} height: 32rpx;
padding: 0 6rpx;
// 卡片头部 font-size: 20rpx;
.card-header { line-height: 32rpx;
display: flex; color: #fff;
align-items: center; text-align: center;
justify-content: space-between; background-color: #ff4757; // 明确的红色
padding: 20rpx 24rpx; border: 2rpx solid #fff;
border-bottom: 1rpx solid #e5e7eb; border-radius: 16rpx;
} }
// 暗色模式下的卡片样式
:deep(.dark) .card-container {
background-color: #1f2937;
}
:deep(.dark) .card-header {
border-bottom-color: #374151;
}
// 工具项
.tool-item {
display: flex;
flex-direction: column;
align-items: center;
width: 25%;
margin-bottom: 30rpx;
}
// 工具图标
.tool-icon {
display: flex;
align-items: center;
justify-content: center;
width: 90rpx;
height: 90rpx;
margin-bottom: 12rpx;
background-color: #f3f4f6;
border-radius: 18rpx;
transition: transform 0.15s ease;
&:active {
transform: scale(0.95);
}
}
// 暗色模式下的工具图标样式
:deep(.dark) .tool-icon {
background-color: #374151;
}
// 数据统计卡片(减少原子类堆叠)
.stats-card {
display: flex;
align-items: center;
padding: 30rpx;
margin: 20rpx 30rpx;
background-color: #ffffff;
border-radius: 16rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
}
:deep(.dark) .stats-card {
background-color: #1f2937;
}
.stats-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
}
.stats-divider {
width: 1px;
margin: 0 20rpx;
background-color: #e5e7eb;
}
:deep(.dark) .stats-divider {
background-color: #374151;
}
// 服务项
.service-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
border-bottom: 1rpx solid #e5e7eb;
transition: background-color 0.15s ease;
&:active {
background-color: #f3f4f6;
}
&.service-item-last {
border-bottom: none;
}
}
// 暗色模式下的服务项样式
:deep(.dark) .service-item {
border-bottom-color: #374151;
&:active {
background-color: rgba(255, 255, 255, 0.1);
} }
} }
@@ -459,14 +357,24 @@ const navigateToSection = (section: string, subSection?: string) => {
justify-content: center; justify-content: center;
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
margin-right: 20rpx; background-color: var(--wot-color-bg-light, #f3f4f6);
background-color: #f3f4f6;
border-radius: 16rpx; border-radius: 16rpx;
} }
// 暗色模式下的服务图标样式 // 工具图标
:deep(.dark) .service-icon { .tool-icon {
background-color: #374151; display: flex;
align-items: center;
justify-content: center;
width: 90rpx;
height: 90rpx;
background-color: var(--wot-color-bg-light, #f3f4f6);
border-radius: 18rpx;
transition: transform 0.15s ease;
&:active {
transform: scale(0.95);
}
} }
// 登录按钮样式 // 登录按钮样式

View File

@@ -1,132 +1,134 @@
<template> <template>
<view class="app-container dark:text-[var(--wot-dark-color)]"> <view class="app-container">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">主题设置</text>
<text class="page-subtitle">个性化您的应用外观</text>
</view>
<!-- 暗黑模式设置 --> <!-- 暗黑模式设置 -->
<wd-card class="setting-section"> <wd-card custom-class="mx-30rpx my-20rpx">
<view class="section-header"> <template #header>
<wd-icon name="moon" size="20" :color="isDarkMode ? '#FFD700' : '#666'" /> <view class="flex-start">
<text class="section-title">外观模式</text> <wd-icon name="moon" size="20" :color="isDarkMode ? '#FFD700' : '#666'" />
</view> <text class="ml-12rpx text-28rpx font-600">外观模式</text>
</view>
</template>
<wd-cell title="暗黑模式" :value="isDarkMode ? '已开启' : '已关闭'"> <wd-cell title="暗黑模式" :value="isDarkMode ? '已开启' : '已关闭'">
<wd-switch :model-value="isDarkMode" @change="handleToggleDarkMode" /> <wd-switch :model-value="isDarkMode" @change="handleToggleDarkMode" />
</wd-cell> </wd-cell>
</wd-card> </wd-card>
<!-- 主题色设置 --> <!-- 主题色设置 -->
<wd-card class="setting-section"> <wd-card custom-class="mx-30rpx my-20rpx">
<view class="section-header"> <template #header>
<wd-icon name="palette" size="20" color="#666" /> <view class="flex-start">
<text class="section-title">主题色彩</text> <wd-icon name="palette" size="20" color="#666" />
</view> <text class="ml-12rpx text-28rpx font-600">主题色彩</text>
</view>
</template>
<!-- 预设颜色选择 --> <!-- 预设颜色选择 -->
<view class="color-section"> <view class="theme-colors">
<text class="color-label">预设主题色</text> <view class="theme-colors__label">预设主题色</view>
<view class="color-grid"> <wd-grid :column="3" border>
<view <wd-grid-item
v-for="(color, index) in themeColorOptions" v-for="(color, index) in themeColorOptions"
:key="index" :key="index"
class="color-item"
:class="{ active: currentThemeColor === color.primary }"
@click="handleSelectColor(color)" @click="handleSelectColor(color)"
> >
<view <view class="theme-colors__item">
class="color-preview" <view
:style="{ class="theme-colors__preview"
backgroundColor: color.primary, :class="{ 'theme-colors__preview--active': currentThemeColor === color.primary }"
border: :style="{ backgroundColor: color.primary }"
currentThemeColor === color.primary ? '3px solid #fff' : '1px solid #e0e0e0', >
}" <text v-if="currentThemeColor === color.primary" class="theme-colors__check">
> ✓
<text v-if="currentThemeColor === color.primary" class="check-icon">✓</text> </text>
</view>
<text class="theme-colors__name">{{ color.name }}</text>
</view> </view>
<text class="color-name">{{ color.name }}</text> </wd-grid-item>
</view> </wd-grid>
</view>
</view> </view>
<!-- 当前主题色显示 --> <!-- 当前主题色显示 -->
<view class="current-theme-section"> <view class="current-theme">
<view class="current-theme-item"> <view class="current-theme__item">
<text class="current-theme-label">当前主题色</text> <view class="current-theme__info">
<view class="current-theme-value">
<view <view
class="current-color-preview" class="current-theme__preview"
:style="{ backgroundColor: currentThemeColor }" :style="{ backgroundColor: currentThemeColor }"
></view> ></view>
<text class="current-color-text">{{ currentThemeColor }}</text> <text class="current-theme__label">当前主题色</text>
</view> </view>
<text class="current-theme__value">{{ currentThemeColor }}</text>
</view> </view>
</view> </view>
<!-- 自定义颜色 --> <!-- 自定义颜色 -->
<wd-cell title="自定义颜色" is-link @click="showCustomInput"> <wd-cell title="自定义颜色" is-link @click="showCustomInput">
<wd-icon name="edit" size="16" color="#999" /> <template #icon>
<wd-icon name="edit" size="16" :color="themeStore.isDark ? '#fff' : '#999'" />
</template>
</wd-cell> </wd-cell>
</wd-card> </wd-card>
<!-- 预览区域 --> <!-- 效果预览 -->
<wd-card class="setting-section"> <wd-card title="效果预览" custom-class="mx-30rpx my-20rpx">
<view class="section-header"> <wd-grid :column="3" border>
<wd-icon name="eye" size="20" />
<text class="section-title">效果预览</text>
</view>
<wd-divider />
<wd-grid :column="2" border>
<wd-grid-item> <wd-grid-item>
<wd-button type="primary">主要按钮</wd-button> <view class="flex-col-center py-20rpx">
<wd-button type="primary" size="small">主要按钮</wd-button>
</view>
</wd-grid-item> </wd-grid-item>
<wd-grid-item> <wd-grid-item>
<text class="preview-text" :style="{ color: currentThemeColor }">主题色文本</text> <view class="flex-col-center py-20rpx">
<text class="text-28rpx font-500" :style="{ color: currentThemeColor }">
主题色文本
</text>
</view>
</wd-grid-item> </wd-grid-item>
<wd-grid-item> <wd-grid-item>
<view class="preview-border" :style="{ borderColor: currentThemeColor }">主题色边框</view> <view class="flex-col-center py-20rpx">
</wd-grid-item> <wd-tag type="primary" size="small">标签</wd-tag>
<wd-grid-item> </view>
<wd-tag type="primary" size="small">标签</wd-tag>
</wd-grid-item> </wd-grid-item>
</wd-grid> </wd-grid>
</wd-card> </wd-card>
<!-- 操作按钮 --> <!-- 操作按钮 -->
<wd-card class="action-section"> <view class="p-30rpx">
<wd-button type="info" size="large" block @click="handleResetTheme">重置为默认主题</wd-button> <wd-button type="info" size="large" block @click="handleResetTheme">重置为默认主题</wd-button>
</wd-card> </view>
<!-- 自定义颜色输入弹窗 --> <!-- 自定义颜色输入弹窗 -->
<wd-popup v-model="showCustomColorInput" position="bottom" :safe-area-inset-bottom="true"> <wd-popup v-model="showCustomColorInput" position="bottom" :safe-area-inset-bottom="true">
<view class="custom-color-popup"> <view class="custom-color-popup">
<view class="popup-header"> <view class="custom-color-popup__header">
<text class="popup-title">自定义主题色</text> <text class="custom-color-popup__title">自定义主题色</text>
<wd-icon name="close" size="20" color="#999" @click="showCustomColorInput = false" /> <wd-icon
name="close"
size="20"
:color="themeStore.isDark ? '#999' : '#666'"
@click="showCustomColorInput = false"
/>
</view> </view>
<wd-divider /> <view class="custom-color-popup__content">
<text class="custom-color-popup__label">请输入十六进制颜色值</text>
<view class="color-input-section"> <view class="custom-color-popup__input-row">
<view class="input-label">请输入十六进制颜色值</view> <view
<view class="input-container"> class="custom-color-popup__preview"
<view class="color-preview-small" :style="{ backgroundColor: customColor }"></view> :style="{ backgroundColor: customColor || '#FF4757' }"
></view>
<wd-input <wd-input
v-model="customColor" v-model="customColor"
placeholder="例如: #165DFF" placeholder="例如: #FF4757"
:maxlength="7" :maxlength="7"
class="color-input" custom-class="custom-color-popup__input"
/> />
</view> </view>
<view class="input-tip">支持格式:#RGB 或 #RRGGBB</view> <text class="custom-color-popup__tip">支持格式:#RGB 或 #RRGGBB</text>
</view> </view>
<wd-divider /> <view class="custom-color-popup__actions">
<view class="popup-actions">
<wd-button type="info" size="large" @click="showCustomColorInput = false">取消</wd-button> <wd-button type="info" size="large" @click="showCustomColorInput = false">取消</wd-button>
<wd-button type="primary" size="large" @click="applyCustomColor">应用</wd-button> <wd-button type="primary" size="large" @click="applyCustomColor">应用</wd-button>
</view> </view>
@@ -198,7 +200,7 @@ const applyCustomColor = () => {
primary: color, primary: color,
}; };
setCurrentThemeColor(customColorOption); setThemeColor(customColorOption);
showCustomColorInput.value = false; showCustomColorInput.value = false;
// 提示 // 提示
@@ -265,217 +267,152 @@ onShow(() => {
</route> </route>
<style lang="scss" scoped> <style lang="scss" scoped>
// 基础布局 // 主题颜色选择区域
.page-header { .theme-colors {
padding: 40rpx 20rpx;
margin-bottom: 30rpx;
text-align: center;
background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #667eea 100%);
border-radius: 16rpx;
.page-title {
display: block;
margin-bottom: 10rpx;
font-size: 36rpx;
font-weight: bold;
color: #fff;
}
.page-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
}
.setting-section {
margin-bottom: 30rpx;
}
.section-header {
display: flex;
align-items: center;
padding: 30rpx 30rpx 20rpx;
border-bottom: 1rpx solid var(--wot-color-border, #f0f0f0);
.section-title {
margin-left: 12rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--wot-color-text, #333);
}
}
// 颜色选择区域
.color-section {
padding: 30rpx; padding: 30rpx;
.color-label { &__label {
display: block;
margin-bottom: 20rpx; margin-bottom: 20rpx;
font-size: 28rpx; font-size: 28rpx;
color: var(--wot-color-text-secondary, #666); color: var(--wot-color-text-secondary);
} }
.color-grid { &__item {
display: flex; display: flex;
flex-wrap: wrap; flex-direction: column;
gap: 20rpx; align-items: center;
justify-content: space-between; padding: 10rpx;
} }
}
.color-item { &__preview {
display: flex;
flex-direction: column;
align-items: center;
width: calc(25% - 15rpx);
padding: 10rpx;
cursor: pointer;
transition: all 0.3s ease;
.color-preview {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 60rpx; width: 60rpx;
height: 60rpx; height: 60rpx;
margin-bottom: 8rpx; margin-bottom: 8rpx;
border: 2rpx solid var(--wot-color-border);
border-radius: 12rpx; border-radius: 12rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s ease; transition: all 0.3s ease;
.check-icon { &--active {
font-size: 24rpx; border-color: var(--wot-color-theme);
font-weight: bold; box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2);
color: #fff; transform: scale(1.05);
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.5);
} }
} }
.color-name { &__check {
font-size: 24rpx;
font-weight: bold;
color: #fff;
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.5);
}
&__name {
font-size: 22rpx; font-size: 22rpx;
color: var(--wot-color-text-secondary); color: var(--wot-color-text-secondary);
text-align: center; text-align: center;
} }
&.active .color-preview {
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2);
transform: scale(1.05);
}
&:active .color-preview {
transform: scale(0.95);
}
} }
// 当前主题色显示 // 当前主题色显示区域
.current-theme-section { .current-theme {
padding: 30rpx; padding: 30rpx;
border-bottom: 1rpx solid var(--wot-color-border);
.current-theme-item { &__item {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.current-theme-label {
font-size: 28rpx;
color: var(--wot-color-text-secondary, #666);
}
.current-theme-value {
display: flex;
align-items: center;
.current-color-preview {
width: 40rpx;
height: 40rpx;
border: 2rpx solid var(--wot-color-border, #f0f0f0);
border-radius: 8rpx;
}
.current-color-text {
margin-left: 10rpx;
font-size: 28rpx;
font-weight: 500;
}
}
} }
}
// 效果预览 &__info {
.preview-text { display: flex;
font-size: 28rpx; align-items: center;
font-weight: 500; }
}
.preview-border { &__preview {
display: flex; width: 40rpx;
align-items: center; height: 40rpx;
justify-content: center; margin-right: 12rpx;
width: 200rpx; border: 2rpx solid var(--wot-color-border);
height: 60rpx; border-radius: 8rpx;
font-size: 26rpx; }
color: var(--wot-color-text-secondary, #666);
border: 2rpx solid; &__label {
border-radius: 8rpx; font-size: 28rpx;
color: var(--wot-color-text);
}
&__value {
font-size: 28rpx;
font-weight: 500;
color: var(--wot-color-text-secondary);
}
} }
// 自定义颜色弹窗 // 自定义颜色弹窗
.custom-color-popup { .custom-color-popup {
padding: 40rpx 30rpx; min-height: 400rpx;
background: var(--wot-popup-bg-color, #fff); background-color: var(--wot-card-bg);
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
.popup-header { &__header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 30rpx; padding: 30rpx;
border-bottom: 1rpx solid var(--wot-color-border);
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: var(--wot-color-text, #333);
}
} }
.color-input-section { &__title {
margin-bottom: 40rpx; font-size: 32rpx;
font-weight: 600;
.input-label { color: var(--wot-color-text);
margin-bottom: 20rpx;
font-size: 28rpx;
color: var(--wot-color-text-secondary, #666);
}
.input-container {
display: flex;
gap: 20rpx;
align-items: center;
margin-bottom: 10rpx;
.color-preview-small {
flex-shrink: 0;
width: 60rpx;
height: 60rpx;
border: 2rpx solid var(--wot-color-border, #f0f0f0);
border-radius: 8rpx;
}
.color-input {
flex: 1;
}
}
.input-tip {
margin-left: 80rpx;
font-size: 24rpx;
color: var(--wot-color-text-placeholder, #999);
}
} }
.popup-actions { &__content {
padding: 40rpx 30rpx;
}
&__label {
display: block;
margin-bottom: 20rpx;
font-size: 28rpx;
color: var(--wot-color-text);
}
&__input-row {
display: flex; display: flex;
gap: 20rpx; gap: 20rpx;
align-items: center;
margin-bottom: 20rpx;
}
&__preview {
flex-shrink: 0;
width: 60rpx;
height: 60rpx;
border: 2rpx solid var(--wot-color-border);
border-radius: 8rpx;
}
&__input {
flex: 1;
}
&__tip {
font-size: 24rpx;
color: var(--wot-color-text-placeholder);
}
&__actions {
display: flex;
gap: 20rpx;
padding: 20rpx 30rpx 30rpx;
border-top: 1rpx solid var(--wot-color-border);
} }
} }
</style> </style>

View File

@@ -1,3 +1,5 @@
@use "./theme";
html, html,
body, body,
#app { #app {

48
src/styles/theme.scss Normal file
View File

@@ -0,0 +1,48 @@
/* 默认主题 (light) */
:root,
page {
/* 官方主题变量 */
--wot-color-theme: #4d80f0;
--wot-color-success: #34d19d;
--wot-color-warning: #f0883a;
--wot-color-danger: #ff4757;
/* 自定义扩展变量 */
--wot-button-normal-bg: #ffffff;
--wot-card-bg: #ffffff;
--wot-color-bg-light: #f3f4f6;
--wot-dark-color: #333333;
/* 文本颜色变量 */
--wot-color-text: #333333;
--wot-color-text-secondary: #666666;
--wot-color-text-placeholder: #999999;
/* 边框和背景变量 */
--wot-color-border: #e5e7eb;
--wot-color-bg-container: #f5f5f5;
}
/* 暗黑主题 (dark) */
.wot-theme-dark {
/* 官方主题变量 */
--wot-color-theme: #1a73e8;
--wot-color-success: #28a745;
--wot-color-warning: #ffc107;
--wot-color-danger: #ff4757;
/* 自定义扩展变量 */
--wot-button-normal-bg: #2a2a2a;
--wot-card-bg: #1b1b1b;
--wot-color-bg-light: #2a2a2a;
--wot-dark-color: #ffffff;
/* 暗黑模式下的文本颜色变量 */
--wot-color-text: #ffffff;
--wot-color-text-secondary: #cccccc;
--wot-color-text-placeholder: #999999;
/* 暗黑模式下的边框和背景变量 */
--wot-color-border: #374151;
--wot-color-bg-container: #111111;
}