diff --git a/components.d.ts b/components.d.ts index 1560d44..8d00a5d 100644 --- a/components.d.ts +++ b/components.d.ts @@ -27,6 +27,7 @@ declare module 'vue' { WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.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'] + WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.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'] WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default'] diff --git a/src/App.vue b/src/App.vue index 39fedec..fbac276 100644 --- a/src/App.vue +++ b/src/App.vue @@ -20,25 +20,4 @@ onHide(() => { }); - + diff --git a/src/composables/useTheme.ts b/src/composables/useTheme.ts index 2f7ea7c..ecc120e 100644 --- a/src/composables/useTheme.ts +++ b/src/composables/useTheme.ts @@ -1,4 +1,4 @@ -import { ref, watch } from "vue"; +import { ref, watch, computed } from "vue"; import type { ConfigProviderThemeVars } from "wot-design-uni"; /* 默认的主题色列表 */ @@ -41,83 +41,79 @@ const getStoredThemeColor = (): string => { } }; -/* 保存主题模式到存储 */ -const saveThemeToStorage = (theme: "light" | "dark") => { - try { - uni.setStorageSync(THEME_STORAGE_KEY, theme); - } catch (error) { - console.error("保存主题模式失败:", error); - } -}; +/* 主题状态 */ +export const theme = ref<"light" | "dark">(getStoredTheme()); +export const currentThemeColor = ref(getStoredThemeColor()); -/* 保存主题色到存储 */ -const saveThemeColorToStorage = (color: string) => { - try { - uni.setStorageSync(THEME_COLOR_STORAGE_KEY, color); - } catch (error) { - console.error("保存主题色失败:", error); - } -}; +/* 主题变量(供 ConfigProvider 使用) */ +export const themeVars = computed(() => ({ + colorTheme: currentThemeColor.value, + // 按钮颜色 + buttonPrimaryBgColor: currentThemeColor.value, + buttonPrimaryColor: "#ffffff", + // 开关颜色 + switchOnBgColor: currentThemeColor.value, + // 其他组件颜色 + cellIconColor: currentThemeColor.value, + tagPrimaryBgColor: currentThemeColor.value, + tagPrimaryColor: "#ffffff", +})); + +/* 应用主题到根元素 */ +const applyThemeToRoot = () => { + // 获取根元素 + const root = document.documentElement; + const body = document.body; -/* 应用暗黑模式的 body 样式 */ -const applyDarkModeBodyStyle = (isDark: boolean) => { // #ifdef H5 - if (typeof document !== "undefined") { - const body = document.body; - if (isDark) { - body.style.backgroundColor = "#1a1a1a"; - body.style.color = "#f5f5f5"; - body.classList.add("wot-theme-dark"); - } else { - body.style.backgroundColor = "#f8f8f8"; - body.style.color = "#333"; - body.classList.remove("wot-theme-dark"); - } + // 应用暗黑模式 + if (theme.value === "dark") { + root.setAttribute("data-theme", "dark"); + body.classList.add("wot-theme-dark"); + } else { + root.removeAttribute("data-theme"); + body.classList.remove("wot-theme-dark"); } + + // 应用主题色类 + // 移除所有主题色类 + root.className = root.className.replace(/theme-color-\w+/g, "").trim(); + // 添加当前主题色类 + const colorClass = `theme-color-${currentThemeColor.value.replace("#", "")}`; + root.classList.add(colorClass); // #endif // #ifdef MP - // 小程序环境中设置页面样式 - try { - const pages = getCurrentPages(); - if (pages.length > 0) { - const currentPage = pages[pages.length - 1]; - if (currentPage && currentPage.$vm) { - // 这里可以根据需要设置页面样式 - console.log("小程序暗黑模式:", isDark ? "开启" : "关闭"); - } + // 小程序环境下通过设置页面的 data-theme 属性 + const pages = getCurrentPages(); + if (pages.length > 0) { + const currentPage = pages[pages.length - 1] as any; + if (currentPage) { + currentPage.setData?.({ + "data-theme": theme.value, + themeColor: currentThemeColor.value, + }); } - } catch (error) { - console.error("设置小程序页面样式失败:", error); } // #endif }; -/* 主题状态 */ -export const theme = ref<"light" | "dark">(getStoredTheme()); - -/* 主题变量 */ -export const themeVars = ref({ - colorTheme: getStoredThemeColor(), -}); - -/* 监听主题模式变化,应用 body 样式 */ +/* 监听主题模式变化 */ watch( theme, (newTheme) => { - saveThemeToStorage(newTheme); - applyDarkModeBodyStyle(newTheme === "dark"); + uni.setStorageSync(THEME_STORAGE_KEY, newTheme); + applyThemeToRoot(); }, { immediate: true } ); -/* 监听主题色变化,保存到存储 */ +/* 监听主题色变化 */ watch( - () => themeVars.value.colorTheme, + currentThemeColor, (newColor) => { - if (newColor) { - saveThemeColorToStorage(newColor); - } + uni.setStorageSync(THEME_COLOR_STORAGE_KEY, newColor); + applyThemeToRoot(); }, { immediate: true } ); @@ -129,31 +125,21 @@ export const toggleTheme = () => { /* 设置主题色 */ export const setThemeColor = (color: string) => { - themeVars.value = { - ...themeVars.value, - colorTheme: color, - }; + currentThemeColor.value = color; }; /* 重置主题 */ export const resetTheme = () => { theme.value = "light"; - setThemeColor(colorColumns[0].value); + currentThemeColor.value = colorColumns[0].value; }; /* 初始化主题 */ export const initTheme = () => { - // 应用当前主题的 body 样式 - applyDarkModeBodyStyle(theme.value === "dark"); - - // 确保主题变量已正确设置 - if (!themeVars.value.colorTheme) { - themeVars.value.colorTheme = getStoredThemeColor(); - } - + applyThemeToRoot(); console.log("主题初始化完成:", { mode: theme.value, - color: themeVars.value.colorTheme, + color: currentThemeColor.value, }); }; @@ -162,6 +148,7 @@ export const useTheme = () => { return { theme, themeVars, + currentThemeColor, toggleTheme, setThemeColor, resetTheme, diff --git a/src/main.ts b/src/main.ts index 5a1b638..0f7d7f6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,8 +2,7 @@ import { createSSRApp } from "vue"; import App from "./App.vue"; import "uno.css"; -import "@/styles/global.scss"; -import "@/styles/wot-theme.scss"; +import "@/styles/theme.scss"; import { setupStore } from "@/store"; diff --git a/src/pages/mine/index.vue b/src/pages/mine/index.vue index 29aeb89..2d55c98 100644 --- a/src/pages/mine/index.vue +++ b/src/pages/mine/index.vue @@ -62,33 +62,33 @@ - + 常用工具 - + 个人资料 - + 常见问题 - + 问题反馈 - + 关于我们 @@ -99,7 +99,7 @@ - + 推荐服务 @@ -107,7 +107,7 @@ - + 会员中心 @@ -119,7 +119,7 @@ - + 优惠券 @@ -131,7 +131,7 @@ - + 邀请有礼 @@ -152,14 +152,15 @@ @@ -255,384 +154,180 @@ onShow(() => { .theme-settings-container { min-height: 100vh; padding: 20rpx; - background-color: var(--wot-color-bg-light, #f8f9fa); - transition: background-color 0.3s ease; - - // 强制 Wot 组件应用暗黑模式样式 - :deep(.wd-card) { - background: var(--wot-card-bg-color, #fff); - border-radius: 16rpx; - box-shadow: var(--wot-card-shadow, 0 2rpx 12rpx rgba(0, 0, 0, 0.05)); - transition: background-color 0.3s ease; - } - - :deep(.wd-cell) { - color: var(--wot-color-text, #333); - background-color: var(--wot-card-bg-color, #fff); - - .wd-cell__title { - color: var(--wot-color-text, #333) !important; - } - - .wd-cell__value { - color: var(--wot-color-text-secondary, #666) !important; - } - - .wd-cell__right-icon { - color: var(--wot-color-text-secondary, #999) !important; - } - } - - :deep(.wd-grid-item) { - color: var(--wot-color-text, #333) !important; - background-color: var(--wot-card-bg-color, #fff) !important; - } - - // 专门为颜色预览块重置背景色 - :deep(.color-item) { - background-color: transparent !important; - - .color-preview { - background-color: inherit !important; - } - } - - :deep(.wd-button) { - &[type="primary"] { - color: #fff !important; - background-color: var(--wot-color-theme, #165dff) !important; - } - - &[type="info"] { - color: #fff !important; - background-color: var(--wot-color-info, #909399) !important; - } - } - - :deep(.wd-input) { - color: var(--wot-color-text, #333) !important; - background-color: var(--wot-card-bg-color, #fff) !important; - } - - :deep(.wd-popup) { - background-color: var(--wot-popup-bg-color, #fff) !important; - } - - .custom-color-popup { - padding: 40rpx 30rpx; - background: var(--wot-popup-bg-color, #fff); - border-radius: 20rpx 20rpx 0 0; - } + background-color: var(--wot-color-bg-page); } .page-header { padding: 40rpx 20rpx; margin-bottom: 30rpx; text-align: center; - background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #667eea 100%); + background: linear-gradient(135deg, var(--wot-color-theme) 0%, var(--primary-color-light) 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); + } } -.page-title { - display: block; - margin-bottom: 10rpx; - font-size: 36rpx; - font-weight: bold; - color: #fff; +.setting-card { + margin-bottom: 20rpx; + background-color: var(--wot-color-bg-container) !important; + border-radius: 16rpx !important; + + :deep(.wd-card__body) { + padding: 30rpx !important; + } } -.page-subtitle { - font-size: 26rpx; - color: rgba(255, 255, 255, 0.8); -} - -.setting-section { - margin-bottom: 30rpx; -} - -.section-header { +.setting-item { display: flex; align-items: center; - padding: 30rpx 30rpx 20rpx; - border-bottom: 1rpx solid var(--wot-color-border, #f0f0f0); + justify-content: space-between; + + .setting-info { + display: flex; + gap: 20rpx; + align-items: center; + } + + .setting-label { + font-size: 30rpx; + color: var(--wot-color-text); + } } -.section-title { - margin-left: 12rpx; - font-size: 32rpx; - font-weight: 600; - color: var(--wot-color-text, #333); -} +.setting-header { + display: flex; + gap: 20rpx; + align-items: center; + margin-bottom: 30rpx; -.color-section { - padding: 30rpx; -} - -.color-label { - margin-bottom: 20rpx; - font-size: 28rpx; - color: var(--wot-color-text-secondary, #666); + .setting-title { + font-size: 30rpx; + font-weight: 600; + color: var(--wot-color-text); + } } .color-grid { - display: flex; - flex-wrap: wrap; + display: grid; + grid-template-columns: repeat(4, 1fr); gap: 20rpx; - justify-content: space-between; } .color-item { - position: relative; display: flex; flex-direction: column; + gap: 10rpx; align-items: center; - justify-content: center; - width: calc(25% - 15rpx); padding: 10rpx; cursor: pointer; - transition: all 0.3s ease; - .color-preview { - position: relative; + &.active .color-box { + box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.15); + transform: scale(1.1); + } + + .color-box { display: flex; align-items: center; justify-content: center; width: 60rpx; height: 60rpx; - margin-bottom: 8rpx; border-radius: 12rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); transition: all 0.3s ease; - } - .check-icon { - font-size: 24rpx; - font-weight: bold; - color: #fff; - text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.5); - } - - .color-name { - font-size: 22rpx; - line-height: 1.2; - color: var(--wot-color-text-secondary, #666); - 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 { - padding: 30rpx; -} - -.current-theme-item { - display: flex; - align-items: center; - 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; -} - -.preview-text { - font-size: 28rpx; - font-weight: 500; -} - -.preview-border { - display: flex; - align-items: center; - justify-content: center; - width: 200rpx; - height: 60rpx; - font-size: 26rpx; - color: var(--wot-color-text-secondary, #666); - border: 2rpx solid; - border-radius: 8rpx; -} - -.action-section { - :deep(.wd-card) { - padding: 30rpx; - background: var(--wot-card-bg-color, #fff); - border-radius: 16rpx; - box-shadow: var(--wot-card-shadow, 0 2rpx 12rpx rgba(0, 0, 0, 0.05)); - } -} - -.popup-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 30rpx; -} - -.popup-title { - font-size: 32rpx; - font-weight: 600; - color: var(--wot-color-text, #333); -} - -.color-input-section { - margin-bottom: 40rpx; -} - -.input-label { - 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 { - display: flex; - gap: 20rpx; -} - -/* 响应式布局 */ -@media (max-width: 750rpx) { - .color-grid { - grid-template-columns: repeat(3, 1fr); - } -} - -@media (max-width: 600rpx) { - .color-grid { - grid-template-columns: repeat(2, 1fr); - } -} - -// 全局暗黑模式适配(针对当前页面) -:global([data-theme="dark"]) .theme-settings-container { - color: var(--wot-color-text, #fff) !important; - background-color: var(--wot-color-bg, #1a1a1a) !important; - - .page-header { - background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #4a5568 100%); - } - - .section-title { - color: var(--wot-color-text, #fff) !important; + &.small { + width: 40rpx; + height: 40rpx; + } } .color-label { - color: var(--wot-color-text-secondary, #d1d5db) !important; + font-size: 22rpx; + color: var(--wot-color-text-secondary); + } +} + +.custom-color-preview { + display: flex; + gap: 15rpx; + align-items: center; + + .color-value { + font-size: 26rpx; + color: var(--wot-color-text-secondary); + } +} + +.preview-section { + .preview-title { + display: block; + margin-bottom: 20rpx; + font-size: 28rpx; + color: var(--wot-color-text-secondary); } - .preview-text { - color: var(--wot-color-text, #fff) !important; + .preview-items { + display: flex; + flex-wrap: wrap; + gap: 20rpx; + align-items: center; } +} - .preview-border { - color: var(--wot-color-text-secondary, #d1d5db) !important; - } +.action-buttons { + padding: 0 20rpx; + margin-top: 40rpx; +} - .popup-title { - color: var(--wot-color-text, #fff) !important; - } +.custom-color-popup { + padding: 40rpx 30rpx; + background-color: var(--wot-color-bg-container); - .input-label { - color: var(--wot-color-text-secondary, #d1d5db) !important; - } + .popup-header { + margin-bottom: 40rpx; + text-align: center; - .input-tip { - color: var(--wot-color-text-placeholder, #9ca3af) !important; - } - - :deep(.wd-card) { - background: var(--wot-card-bg-color, #2a2a2a) !important; - } - - :deep(.wd-cell) { - color: var(--wot-color-text, #fff) !important; - background-color: var(--wot-card-bg-color, #2a2a2a) !important; - - .wd-cell__title { - color: var(--wot-color-text, #fff) !important; - } - - .wd-cell__value { - color: var(--wot-color-text-secondary, #d1d5db) !important; - } - - .wd-cell__right-icon { - color: var(--wot-color-text-secondary, #9ca3af) !important; + .popup-title { + font-size: 32rpx; + font-weight: 600; + color: var(--wot-color-text); } } - :deep(.wd-grid-item) { - color: var(--wot-color-text, #fff) !important; - background-color: var(--wot-card-bg-color, #2a2a2a) !important; + .color-input-section { + margin-bottom: 40rpx; + + .color-preview-large { + width: 100%; + height: 120rpx; + margin-bottom: 30rpx; + border: 2rpx solid var(--wot-color-border); + border-radius: 16rpx; + } + + .input-tip { + display: block; + margin-top: 15rpx; + font-size: 24rpx; + color: var(--wot-color-text-placeholder); + text-align: center; + } } - // 专门为颜色预览块重置背景色 - :deep(.color-item) { - background-color: transparent !important; - } - - :deep(.wd-input) { - color: var(--wot-color-text, #fff) !important; - background-color: var(--wot-card-bg-color, #2a2a2a) !important; - } - - :deep(.wd-popup) { - background-color: var(--wot-popup-bg-color, #2a2a2a) !important; - } - - .custom-color-popup { - background: var(--wot-popup-bg-color, #2a2a2a) !important; + .popup-actions { + display: flex; + gap: 20rpx; } } diff --git a/src/services/wechat.service.ts b/src/services/wechat.service.ts new file mode 100644 index 0000000..11178a5 --- /dev/null +++ b/src/services/wechat.service.ts @@ -0,0 +1,148 @@ +/** + * 微信授权服务 + * 处理微信登录授权、获取用户信息等功能 + */ + +import { ref } from "vue"; +import { getAccessToken } from "@/utils/auth"; + +// 定义微信授权状态 +export const wxAuthState = ref({ + isLogining: false, + authDenied: false, +}); + +/** + * 获取微信登录凭证 + * @returns Promise 返回登录凭证code + */ +export function getWxLoginCode(): Promise { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: "weixin", + success: (res) => { + if (res.code) { + resolve(res.code); + } else { + reject(new Error("获取微信登录凭证失败")); + } + }, + fail: (err) => { + reject(err); + }, + }); + // #endif + + // #ifndef MP-WEIXIN + reject(new Error("当前环境不支持微信登录")); + // #endif + }); +} + +/** + * 获取微信用户手机号 + * @param e 微信授权返回的事件对象 + * @returns Promise 返回包含加密数据的对象 + */ +export function getWxPhoneNumber( + e: any +): Promise<{ code: string; encryptedData?: string; iv?: string }> { + return new Promise((resolve, reject) => { + wxAuthState.value.isLogining = true; + + // 判断授权是否成功 + if (e.detail.errMsg !== "getPhoneNumber:ok") { + wxAuthState.value.isLogining = false; + wxAuthState.value.authDenied = true; + reject(new Error("用户拒绝授权")); + return; + } + + // 获取登录凭证code + getWxLoginCode() + .then((code) => { + // 在微信小程序环境下,可以获取encryptedData和iv + // #ifdef MP-WEIXIN + resolve({ + code, + encryptedData: e.detail.encryptedData, + iv: e.detail.iv, + }); + // #endif + + // 其他环境或新版本接口 + // #ifndef MP-WEIXIN + resolve({ + code, + // 新版本接口在e.detail.code中包含手机号获取凭证 + ...(e.detail.code ? { phoneCode: e.detail.code } : {}), + }); + // #endif + }) + .catch((err) => { + reject(err); + }) + .finally(() => { + wxAuthState.value.isLogining = false; + }); + }); +} + +/** + * 检查微信会话有效性 + * 检查本地token是否存在,如存在则检查其有效性 + */ +export function checkWxSession(): Promise { + return new Promise((resolve) => { + const token = getAccessToken(); + + if (!token) { + resolve(false); + return; + } + + // 调用后端接口验证token有效性 + uni.request({ + url: "/api/v1/auth/check-session", + method: "GET", + header: { + Authorization: `Bearer ${token}`, + }, + success: (res: any) => { + if (res.statusCode === 200 && res.data.valid) { + resolve(true); + } else { + resolve(false); + } + }, + fail: () => { + resolve(false); + }, + }); + }); +} + +/** + * 获取微信用户信息(如头像、昵称等) + * 注意:此接口在2021年4月后的小程序新版本中需要额外授权 + */ +export function getWxUserProfile(): Promise { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.getUserProfile({ + desc: "用于完善用户资料", + success: (res) => { + resolve(res.userInfo); + }, + fail: (err) => { + reject(err); + }, + }); + // #endif + + // #ifndef MP-WEIXIN + reject(new Error("当前环境不支持获取用户信息")); + // #endif + }); +} diff --git a/src/styles/global.scss b/src/styles/global.scss deleted file mode 100644 index 3277c14..0000000 --- a/src/styles/global.scss +++ /dev/null @@ -1,244 +0,0 @@ -/** - * 全局样式变量 - */ - -/* - * 主题颜色 - 会被theme.ts中的动态设置覆盖 - * 这里作为默认值和IDE提示 - */ -:root { - /* 主色 */ - --primary-color: #165dff; - --primary-color-light: #94bfff; - --primary-color-dark: #0e3c9b; - - /* 功能色 */ - --success-color: #0fc6c2; - --warning-color: #ff7d00; - --danger-color: #f5222d; - --info-color: #86909c; - - /* 文字颜色 */ - --text-primary: #1d2129; - --text-regular: #4e5969; - --text-secondary: #86909c; - --text-placeholder: #c9cdd4; - --text-inverse: #ffffff; - - /* 边框颜色 */ - --border-color: #e5e6eb; - --border-light: #f2f3f5; - - /* 背景颜色 */ - --bg-white: #ffffff; - --bg-light: #f2f3f5; - --bg-gray: #f7f8fa; -} - -/** - * 主题相关的通用类 - */ - -/* 主色文本 */ -.text-primary { - color: var(--primary-color) !important; -} - -/* 主色背景 */ -.bg-primary { - color: #fff; - background-color: var(--primary-color) !important; -} - -/* 主色边框 */ -.border-primary { - border-color: var(--primary-color) !important; -} - -/* 主色按钮样式 */ -.btn-primary { - color: #fff; - background-color: var(--primary-color); - border: none; - border-radius: 8rpx; - transition: opacity 0.3s; - - &:active { - opacity: 0.8; - } -} - -/* 圆角按钮 */ -.btn-rounded { - border-radius: 45rpx !important; -} - -/* 次级按钮 */ -.btn-secondary { - color: var(--primary-color); - background-color: #fff; - border: 1px solid var(--primary-color); - border-radius: 8rpx; - transition: background-color 0.3s; - - &:active { - background-color: rgba(22, 93, 255, 0.05); - } -} - -/** - * 字体大小 - */ -.font-xs { - font-size: 24rpx; -} - -.font-sm { - font-size: 28rpx; -} - -.font-md { - font-size: 32rpx; -} - -.font-lg { - font-size: 36rpx; -} - -.font-xl { - font-size: 40rpx; -} - -/** - * 边距辅助类 - */ -.mt-10 { - margin-top: 10rpx; -} -.mt-20 { - margin-top: 20rpx; -} -.mt-30 { - margin-top: 30rpx; -} -.mt-40 { - margin-top: 40rpx; -} - -.mb-10 { - margin-bottom: 10rpx; -} -.mb-20 { - margin-bottom: 20rpx; -} -.mb-30 { - margin-bottom: 30rpx; -} -.mb-40 { - margin-bottom: 40rpx; -} - -.ml-10 { - margin-left: 10rpx; -} -.ml-20 { - margin-left: 20rpx; -} -.ml-30 { - margin-left: 30rpx; -} -.ml-40 { - margin-left: 40rpx; -} - -.mr-10 { - margin-right: 10rpx; -} -.mr-20 { - margin-right: 20rpx; -} -.mr-30 { - margin-right: 30rpx; -} -.mr-40 { - margin-right: 40rpx; -} - -.p-10 { - padding: 10rpx; -} -.p-20 { - padding: 20rpx; -} -.p-30 { - padding: 30rpx; -} -.p-40 { - padding: 40rpx; -} - -/** - * 布局辅助类 - */ -.flex { - display: flex; -} -.flex-wrap { - flex-wrap: wrap; -} -.flex-column { - flex-direction: column; -} -.items-center { - align-items: center; -} -.items-start { - align-items: flex-start; -} -.items-end { - align-items: flex-end; -} -.justify-center { - justify-content: center; -} -.justify-between { - justify-content: space-between; -} -.justify-around { - justify-content: space-around; -} -.justify-start { - justify-content: flex-start; -} -.justify-end { - justify-content: flex-end; -} - -/** - * 其他辅助类 - */ -.text-center { - text-align: center; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} - -.rounded-sm { - border-radius: 4rpx; -} -.rounded { - border-radius: 8rpx; -} -.rounded-lg { - border-radius: 16rpx; -} -.rounded-xl { - border-radius: 24rpx; -} -.rounded-full { - border-radius: 9999rpx; -} diff --git a/src/styles/theme.scss b/src/styles/theme.scss new file mode 100644 index 0000000..613f706 --- /dev/null +++ b/src/styles/theme.scss @@ -0,0 +1,186 @@ +/** + * 统一主题系统 + * 简洁易懂,一个文件搞定所有主题 + */ + +/* 亮色主题(默认) */ +:root, +page { + /* ===== 主题色 ===== */ + --wot-color-theme: #165dff; + --primary-color: var(--wot-color-theme); + --primary-color-light: #94bfff; + --primary-color-dark: #0e3c9b; + + /* ===== 功能色 ===== */ + --wot-color-success: #0fc6c2; + --wot-color-warning: #ff7d00; + --wot-color-danger: #f5222d; + --wot-color-info: #86909c; + + /* ===== 文本颜色 ===== */ + --wot-color-text: #1d2129; + --wot-color-text-secondary: #4e5969; + --wot-color-text-placeholder: #86909c; + --wot-color-text-disabled: #c9cdd4; + + /* ===== 背景颜色 ===== */ + --wot-color-bg: #ffffff; + --wot-color-bg-page: #f5f7fa; + --wot-color-bg-light: #f8f9fa; + --wot-color-bg-container: #ffffff; + + /* ===== 边框颜色 ===== */ + --wot-color-border: #e5e6eb; + --wot-color-border-light: #f2f3f5; + + /* ===== 组件专用变量 ===== */ + --wot-card-bg-color: var(--wot-color-bg-container); + --wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); + --wot-cell-bg-color: var(--wot-color-bg-container); + --wot-popup-bg-color: var(--wot-color-bg-container); + --wot-navbar-bg-color: var(--wot-color-bg-container); + --wot-tabbar-bg-color: var(--wot-color-bg-container); +} + +/* 暗黑主题 */ +[data-theme="dark"], +[data-theme="dark"] page, +.wot-theme-dark, +.wot-theme-dark page { + /* ===== 主题色(暗黑模式下稍微调亮) ===== */ + --wot-color-theme: #4080ff; + --primary-color: var(--wot-color-theme); + --primary-color-light: #6fa0ff; + --primary-color-dark: #2060df; + + /* ===== 功能色 ===== */ + --wot-color-success: #1dd1cc; + --wot-color-warning: #ff8c1a; + --wot-color-danger: #ff4757; + --wot-color-info: #9ca3af; + + /* ===== 文本颜色 ===== */ + --wot-color-text: #ffffff; + --wot-color-text-secondary: #d1d5db; + --wot-color-text-placeholder: #9ca3af; + --wot-color-text-disabled: #6b7280; + + /* ===== 背景颜色 ===== */ + --wot-color-bg: #1a1a1a; + --wot-color-bg-page: #0f0f0f; + --wot-color-bg-light: #2a2a2a; + --wot-color-bg-container: #1f1f1f; + + /* ===== 边框颜色 ===== */ + --wot-color-border: #404040; + --wot-color-border-light: #606060; + + /* ===== 组件专用变量 ===== */ + --wot-card-bg-color: var(--wot-color-bg-container); + --wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.3); + --wot-cell-bg-color: var(--wot-color-bg-container); + --wot-popup-bg-color: var(--wot-color-bg-container); + --wot-navbar-bg-color: var(--wot-color-bg-container); + --wot-tabbar-bg-color: var(--wot-color-bg-container); +} + +/* 动态主题色类(这些会被 useTheme 动态应用到根元素) */ +.theme-color-165DFF { + --wot-color-theme: #165dff; + --primary-color: #165dff; +} +.theme-color-0FC6C2 { + --wot-color-theme: #0fc6c2; + --primary-color: #0fc6c2; +} +.theme-color-722ED1 { + --wot-color-theme: #722ed1; + --primary-color: #722ed1; +} +.theme-color-F5222D { + --wot-color-theme: #f5222d; + --primary-color: #f5222d; +} +.theme-color-FA8C16 { + --wot-color-theme: #fa8c16; + --primary-color: #fa8c16; +} +.theme-color-FADB14 { + --wot-color-theme: #fadb14; + --primary-color: #fadb14; +} +.theme-color-52C41A { + --wot-color-theme: #52c41a; + --primary-color: #52c41a; +} +.theme-color-EB2F96 { + --wot-color-theme: #eb2f96; + --primary-color: #eb2f96; +} +.theme-color-13C2C2 { + --wot-color-theme: #13c2c2; + --primary-color: #13c2c2; +} +.theme-color-1890FF { + --wot-color-theme: #1890ff; + --primary-color: #1890ff; +} +.theme-color-CD5C5C { + --wot-color-theme: #cd5c5c; + --primary-color: #cd5c5c; +} +.theme-color-228B22 { + --wot-color-theme: #228b22; + --primary-color: #228b22; +} + +/* 全局基础样式 */ +page { + color: var(--wot-color-text); + background-color: var(--wot-color-bg-page); + transition: + background-color 0.3s ease, + color 0.3s ease; +} + +/* H5 环境下的 body 样式 */ +/* #ifdef H5 */ +body { + color: var(--wot-color-text); + background-color: var(--wot-color-bg-page); + transition: + background-color 0.3s ease, + color 0.3s ease; +} +/* #endif */ + +/* 通用组件样式重置 */ +view, +text, +button, +input, +textarea { + transition: + background-color 0.3s ease, + color 0.3s ease, + border-color 0.3s ease; +} + +/* 确保所有 Wot 组件使用主题变量 */ +:deep(.wd-button--primary) { + background-color: var(--wot-color-theme) !important; + border-color: var(--wot-color-theme) !important; +} + +:deep(.wd-cell) { + background-color: var(--wot-cell-bg-color) !important; +} + +:deep(.wd-navbar) { + background-color: var(--wot-navbar-bg-color) !important; +} + +:deep(.wd-tabbar) { + background-color: var(--wot-tabbar-bg-color) !important; +} diff --git a/src/styles/wot-theme.scss b/src/styles/wot-theme.scss deleted file mode 100644 index d85bc50..0000000 --- a/src/styles/wot-theme.scss +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Wot Design Uni 主题变量定制 - * 基于 ConfigProvider 的 CSS 变量系统 - */ - -/* - * 全局 Wot 主题变量 - * 这些变量会被 ConfigProvider 自动应用到所有 Wot 组件 - */ -:root, -page { - /* ===== 主题色系 ===== */ - --wot-color-theme: #165dff; - --wot-color-success: #0fc6c2; - --wot-color-warning: #ff7d00; - --wot-color-danger: #f5222d; - --wot-color-info: #86909c; - - /* ===== 中性色系 ===== */ - --wot-color-white: #ffffff; - --wot-color-black: #000000; - --wot-color-gray-1: #f7f8fa; - --wot-color-gray-2: #f2f3f5; - --wot-color-gray-3: #e5e6eb; - --wot-color-gray-4: #c9cdd4; - --wot-color-gray-5: #86909c; - --wot-color-gray-6: #4e5969; - --wot-color-gray-7: #272e3b; - --wot-color-gray-8: #1d2129; - - /* ===== 文本颜色 ===== */ - --wot-color-text: #1d2129; - --wot-color-text-secondary: #4e5969; - --wot-color-text-placeholder: #86909c; - --wot-color-text-disabled: #c9cdd4; - - /* ===== 背景颜色 ===== */ - --wot-color-bg: #ffffff; - --wot-color-bg-light: #f7f8fa; - --wot-color-bg-dark: #f2f3f5; - - /* ===== 边框颜色 ===== */ - --wot-color-border: #e5e6eb; - --wot-color-border-light: #f2f3f5; - - /* ===== 按钮相关变量 ===== */ - --wot-button-primary-bg-color: var(--wot-color-theme); - --wot-button-primary-color: #ffffff; - --wot-button-primary-border-color: var(--wot-color-theme); - - --wot-button-success-bg-color: var(--wot-color-success); - --wot-button-success-color: #ffffff; - --wot-button-success-border-color: var(--wot-color-success); - - --wot-button-warning-bg-color: var(--wot-color-warning); - --wot-button-warning-color: #ffffff; - --wot-button-warning-border-color: var(--wot-color-warning); - - --wot-button-danger-bg-color: var(--wot-color-danger); - --wot-button-danger-color: #ffffff; - --wot-button-danger-border-color: var(--wot-color-danger); - - --wot-button-info-bg-color: var(--wot-color-info); - --wot-button-info-color: #ffffff; - --wot-button-info-border-color: var(--wot-color-info); - - /* ===== 输入框相关变量 ===== */ - --wot-input-border-color: var(--wot-color-border); - --wot-input-focus-border-color: var(--wot-color-theme); - --wot-input-placeholder-color: var(--wot-color-text-placeholder); - --wot-input-disabled-bg-color: var(--wot-color-bg-light); - - /* ===== 开关相关变量 ===== */ - --wot-switch-on-bg-color: var(--wot-color-theme); - --wot-switch-off-bg-color: var(--wot-color-gray-3); - - /* ===== 卡片相关变量 ===== */ - --wot-card-bg-color: #ffffff; - --wot-card-border-color: var(--wot-color-border); - --wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); - - /* ===== Cell 相关变量 ===== */ - --wot-cell-bg-color: #ffffff; - --wot-cell-border-color: var(--wot-color-border); - --wot-cell-title-color: var(--wot-color-text); - --wot-cell-value-color: var(--wot-color-text-secondary); - - /* ===== 标签相关变量 ===== */ - --wot-tag-primary-bg-color: var(--wot-color-theme); - --wot-tag-primary-color: #ffffff; - --wot-tag-success-bg-color: var(--wot-color-success); - --wot-tag-success-color: #ffffff; - --wot-tag-warning-bg-color: var(--wot-color-warning); - --wot-tag-warning-color: #ffffff; - --wot-tag-danger-bg-color: var(--wot-color-danger); - --wot-tag-danger-color: #ffffff; - - /* ===== 图标相关变量 ===== */ - --wot-icon-color: var(--wot-color-text-secondary); - - /* ===== 分割线相关变量 ===== */ - --wot-divider-color: var(--wot-color-border); - - /* ===== 弹窗相关变量 ===== */ - --wot-popup-bg-color: #ffffff; - --wot-popup-border-radius: 16rpx; - - /* ===== 网格相关变量 ===== */ - --wot-grid-border-color: var(--wot-color-border); -} - -/* ===== 暗黑模式变量 ===== */ -[data-theme="dark"], -.wot-theme-dark { - /* 主题色在暗黑模式下稍微调亮 */ - --wot-color-theme: #4080ff; - --wot-color-success: #1dd1cc; - --wot-color-warning: #ff8c1a; - --wot-color-danger: #ff4757; - --wot-color-info: #9ca3af; - - /* 中性色系 - 暗黑模式 */ - --wot-color-white: #1a1a1a; - --wot-color-black: #ffffff; - --wot-color-gray-1: #2a2a2a; - --wot-color-gray-2: #404040; - --wot-color-gray-3: #606060; - --wot-color-gray-4: #808080; - --wot-color-gray-5: #9ca3af; - --wot-color-gray-6: #d1d5db; - --wot-color-gray-7: #e5e7eb; - --wot-color-gray-8: #f3f4f6; - - /* 文本颜色 - 暗黑模式 */ - --wot-color-text: #ffffff; - --wot-color-text-secondary: #d1d5db; - --wot-color-text-placeholder: #9ca3af; - --wot-color-text-disabled: #6b7280; - - /* 背景颜色 - 暗黑模式 */ - --wot-color-bg: #1a1a1a; - --wot-color-bg-light: #2a2a2a; - --wot-color-bg-dark: #404040; - - /* 边框颜色 - 暗黑模式 */ - --wot-color-border: #404040; - --wot-color-border-light: #606060; - - /* 卡片相关变量 - 暗黑模式 */ - --wot-card-bg-color: #2a2a2a; - --wot-card-border-color: var(--wot-color-border); - --wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.3); - - /* Cell 相关变量 - 暗黑模式 */ - --wot-cell-bg-color: #2a2a2a; - - /* 弹窗相关变量 - 暗黑模式 */ - --wot-popup-bg-color: #2a2a2a; - - /* 输入框相关变量 - 暗黑模式 */ - --wot-input-disabled-bg-color: var(--wot-color-bg-light); -} - -/* ===== 动态主题色支持 ===== */ -/* 这些变量会被 useTheme composable 动态设置 */ -.theme-blue { - --wot-color-theme: #165dff; -} - -.theme-green { - --wot-color-theme: #0fc6c2; -} - -.theme-orange { - --wot-color-theme: #ff7d00; -} - -.theme-red { - --wot-color-theme: #f5222d; -} - -.theme-purple { - --wot-color-theme: #722ed1; -} - -.theme-pink { - --wot-color-theme: #eb2f96; -} - -.theme-cyan { - --wot-color-theme: #13c2c2; -} - -.theme-yellow { - --wot-color-theme: #faad14; -} - -.theme-lime { - --wot-color-theme: #a0d911; -} - -.theme-indigo { - --wot-color-theme: #2f54eb; -} - -.theme-teal { - --wot-color-theme: #08979c; -} - -.theme-brown { - --wot-color-theme: #8c6239; -} - -/* ===== 全局样式增强 ===== */ -/* 确保暗黑模式下的全局样式 */ -[data-theme="dark"] { - color: var(--wot-color-text); - background-color: var(--wot-color-bg); -} - -/* H5 环境下的 body 样式 */ -/* #ifdef H5 */ -body.dark { - color: #ffffff !important; - background-color: #1a1a1a !important; -} -/* #endif */ - -/* 小程序环境下的 page 样式 */ -/* #ifndef H5 */ -page.dark { - color: #ffffff !important; - background-color: #1a1a1a !important; -} -/* #endif */