feat: 重构主题管理并优化UI样式

重构主题管理逻辑,将useTheme composable迁移至pinia store中管理
更新页面布局和样式,调整边距和卡片样式
添加新的主题配置文件并移除旧的主题图片资源
优化登录页和设置页的UI交互
更新unocss配置添加更多flex快捷类
This commit is contained in:
zhangtao
2025-08-28 01:14:29 +08:00
parent b93d1c61cb
commit 01387a53b4
41 changed files with 259 additions and 257 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ VITE_APP_ENV=development
VITE_APP_TITLE=fastapiadmin VITE_APP_TITLE=fastapiadmin
# 网络请求公用地址 # 网络请求公用地址
VITE_API_BASE_URL=http://localhost:8001 VITE_API_BASE_URL=https://service.fastapiadmin.com
# 代理前缀 # 代理前缀
VITE_APP_BASE_API=/api/v1 VITE_APP_BASE_API=/api/v1
+1 -63
View File
@@ -93,68 +93,6 @@
"watchSyncEffect": true, "watchSyncEffect": true,
"DirectiveBinding": true, "DirectiveBinding": true,
"MaybeRef": true, "MaybeRef": true,
"MaybeRefOrGetter": true, "MaybeRefOrGetter": true
"CommonUtil": true,
"Storage": true,
"acceptHMRUpdate": true,
"applyThemeOnPageShow": true,
"applyThemeToMiniProgram": true,
"auth": true,
"checkLogin": true,
"clearAll": true,
"clearToken": true,
"clearTokens": true,
"clearUserInfo": true,
"createPinia": true,
"createRouter": true,
"debounce": true,
"defineStore": true,
"dept": true,
"dict": true,
"file": true,
"getAccessToken": true,
"getActivePinia": true,
"getDarkerColor": true,
"getLighterColor": true,
"getRefreshToken": true,
"getToken": true,
"getUserInfo": true,
"isLoggedIn": true,
"log": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"menu": true,
"notice": true,
"request": true,
"requireLogin": true,
"role": true,
"setAccessToken": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"setRefreshToken": true,
"setToken": true,
"setUserInfo": true,
"setupStore": true,
"store": true,
"storeToRefs": true,
"useDictStore": true,
"useMessage": true,
"useNotify": true,
"useRoute": true,
"useRouter": true,
"useThemeStore": true,
"useToast": true,
"useUserStore": true,
"user": true,
"config": true,
"extendedColorOptions": true,
"themeColorOptions": true,
"useStomp": true,
"useTabbar": true,
"useTheme": true,
"useWechat": true
} }
} }
+7 -1
View File
@@ -1,5 +1,11 @@
{ {
"extends": ["stylelint-config-recommended", "stylelint-config-recommended-scss", "stylelint-config-recommended-vue/scss", "stylelint-config-html/vue", "stylelint-config-recess-order"], "extends": [
"stylelint-config-recommended",
"stylelint-config-recommended-scss",
"stylelint-config-recommended-vue/scss",
"stylelint-config-html/vue",
"stylelint-config-recess-order"
],
"plugins": ["stylelint-prettier"], "plugins": ["stylelint-prettier"],
"overrides": [ "overrides": [
{ {
-7
View File
@@ -23,8 +23,6 @@ declare module 'vue' {
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default'] WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default'] WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default'] WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default']
WdCollapse: typeof import('wot-design-uni/components/wd-collapse/wd-collapse.vue')['default']
WdCollapseItem: typeof import('wot-design-uni/components/wd-collapse-item/wd-collapse-item.vue')['default']
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']
@@ -32,15 +30,12 @@ declare module 'vue' {
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']
WdImg: typeof import('wot-design-uni/components/wd-img/wd-img.vue')['default'] WdImg: typeof import('wot-design-uni/components/wd-img/wd-img.vue')['default']
WdImgCropper: typeof import('wot-design-uni/components/wd-img-cropper/wd-img-cropper.vue')['default']
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']
WdSwiper: typeof import('wot-design-uni/components/wd-swiper/wd-swiper.vue')['default'] WdSwiper: typeof import('wot-design-uni/components/wd-swiper/wd-swiper.vue')['default']
@@ -49,8 +44,6 @@ declare module 'vue' {
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'] 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']
} }
} }
+3 -9
View File
@@ -29,10 +29,6 @@ export default [
"**/u-charts/**", "**/u-charts/**",
"**/qiun-**/**", "**/qiun-**/**",
"**/auto-imports.d.ts", "**/auto-imports.d.ts",
// unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
"src/types/auto-imports.d.ts",
// vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore
"uni-pages.d.ts",
], ],
}, },
// 检查文件的配置 // 检查文件的配置
@@ -47,15 +43,13 @@ export default [
...{ ...{
uni: "readonly", // uni-app 全局对象 uni: "readonly", // uni-app 全局对象
UniApp: "readonly", // uni-app 全局对象 UniApp: "readonly", // uni-app 全局对象
PageResult: "readonly", // 分页结果数据类型
PageQuery: "readonly", // 分页查询数据类型
OptionType: "readonly", // 选项类型
getCurrentPages: "readonly", // uni-app 全局 API getCurrentPages: "readonly", // uni-app 全局 API
ApiResponse: "readonly", // 统一响应数据类型 ApiResponse: "readonly", // 统一响应数据类型
PageQuery: "readonly", // 分页查询数据类型
PageResult: "readonly", // 分页结果数据类型
OptionType: "readonly", // 选项类型
creatorType: "readonly", // 创建人类型 creatorType: "readonly", // 创建人类型
UploadFileResult: "readonly", // 上传文件返回类型 UploadFileResult: "readonly", // 上传文件返回类型
Todo: "readonly", // 待办事项
TodoState: "readonly", // 待办事项状态
plus: true, // HTML5+ 运行时环境 plus: true, // HTML5+ 运行时环境
}, },
}, },
+42
View File
@@ -0,0 +1,42 @@
// pages.config.ts
import { defineUniPages } from "@uni-helper/vite-plugin-uni-pages";
export default defineUniPages({
// 你也可以定义 pages 字段,它具有最高的优先级。
pages: [],
globalStyle: {
navigationBarBackgroundColor: "@navBgColor",
navigationBarTextStyle: "@navTxtStyle",
navigationBarTitleText: "FastApp",
backgroundColor: "@bgColor",
backgroundTextStyle: "@bgTxtStyle",
backgroundColorTop: "@bgColorTop",
backgroundColorBottom: "@bgColorBottom",
enablePullDownRefresh: false,
onReachBottomDistance: 50,
animationType: "pop-in",
animationDuration: 300,
},
tabBar: {
custom: true,
customize: true,
overlay: true,
height: "0",
color: "@tabColor",
selectedColor: "@tabSelectedColor",
backgroundColor: "@tabBgColor",
borderStyle: "@tabBorderStyle",
list: [
{
pagePath: "pages/index/index",
},
{
pagePath: "pages/work/index",
},
{
pagePath: "pages/mine/index",
},
],
},
});
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

-48
View File
@@ -1,48 +0,0 @@
import { useThemeStore, ThemeMode, ThemeColorOption } from "@/store";
export function useTheme() {
const store = useThemeStore();
/**
* 切换暗黑模式
* @param mode 指定主题模式,不传则自动切换
*/
function toggleTheme(mode?: ThemeMode) {
store.toggleTheme(mode);
}
/**
* 设置主题色
* @param option 主题色选项
*/
function setThemeColor(option: ThemeColorOption) {
store.setCurrentThemeColor(option);
}
/**
* 初始化主题
*/
function initTheme() {
store.initTheme();
}
// 注意:全局主题管理已在App.vue中处理
// 包括:系统主题监听、导航栏颜色同步等
// 组件中一般不需要再调用initTheme(),除非有特殊需求
return {
// 状态
theme: computed(() => store.theme),
isDark: computed(() => store.isDark),
currentThemeColor: computed(() => store.currentThemeColor),
themeVars: computed(() => store.themeVars),
// 主题选项
themeColorOptions: computed(() => store.themeColorOptions),
// 方法
initTheme,
toggleTheme,
setThemeColor,
};
}
+11 -2
View File
@@ -1,7 +1,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useTheme } from "@/composables/useTheme"; import { onLoad } from "@dcloudio/uni-app";
import { useThemeStore } from "@/store/modules/theme.store";
const { theme, themeVars } = useTheme(); const useTheme = useThemeStore();
let theme = useTheme.theme;
let themeVars = useTheme.themeVars;
onLoad(() => {
theme = useTheme.theme;
themeVars = useTheme.themeVars;
});
</script> </script>
<script lang="ts"> <script lang="ts">
+5 -2
View File
@@ -26,12 +26,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRouter, useRoute } from "uni-mini-router"; import { useRouter, useRoute } from "uni-mini-router";
import { useTheme } from "@/composables/useTheme";
import { useTabbar } from "@/composables/useTabbar"; import { useTabbar } from "@/composables/useTabbar";
import { useThemeStore } from "@/store/modules/theme.store";
const useTheme = useThemeStore();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const { themeVars, theme } = useTheme(); let theme = useTheme.theme;
let themeVars = useTheme.themeVars;
const { activeTabbar, getTabbarItemValue, setTabbarItemActive, tabbarList } = useTabbar(); const { activeTabbar, getTabbarItemValue, setTabbarItemActive, tabbarList } = useTabbar();
function handleTabbarChange({ value }: { value: string }) { function handleTabbarChange({ value }: { value: string }) {
+19 -16
View File
@@ -1,12 +1,4 @@
{ {
"easycom": {
"autoscan": true,
"custom": {
"^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue",
"^cu-(.*)": "@/components/cu-$1/index.vue"
}
},
"pages": [ "pages": [
{ {
"path": "pages/index/index", "path": "pages/index/index",
@@ -19,7 +11,11 @@
}, },
{ {
"path": "pages/login/index", "path": "pages/login/index",
"type": "page" "type": "page",
"name": "login",
"style": {
"navigationBarTitleText": "登录"
}
}, },
{ {
"path": "pages/mine/index", "path": "pages/mine/index",
@@ -127,20 +123,27 @@
} }
], ],
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarBackgroundColor": "@navBgColor",
"navigationBarTextStyle": "@navTxtStyle",
"navigationBarTitleText": "FastApp", "navigationBarTitleText": "FastApp",
"navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "@bgColor",
"backgroundColor": "#F8F8F8" "backgroundTextStyle": "@bgTxtStyle",
"backgroundColorTop": "@bgColorTop",
"backgroundColorBottom": "@bgColorBottom",
"enablePullDownRefresh": false,
"onReachBottomDistance": 50,
"animationType": "pop-in",
"animationDuration": 300
}, },
"tabBar": { "tabBar": {
"custom": true, "custom": true,
"customize": true, "customize": true,
"overlay": true, "overlay": true,
"height": "0", "height": "0",
"color": "#474747", "color": "@tabColor",
"selectedColor": "#3B8DFF", "selectedColor": "@tabSelectedColor",
"backgroundColor": "#F8F8F8", "backgroundColor": "@tabBgColor",
"borderStyle": "black", "borderStyle": "@tabBorderStyle",
"list": [ "list": [
{ {
"pagePath": "pages/index/index" "pagePath": "pages/index/index"
+3 -14
View File
@@ -58,7 +58,7 @@
</wd-grid-item> </wd-grid-item>
</wd-grid> </wd-grid>
<wd-card> <wd-card type="rectangle">
<template #title> <template #title>
<view class="flex-between"> <view class="flex-between">
<view>访问趋势</view> <view>访问趋势</view>
@@ -76,7 +76,7 @@
</view> </view>
</template> </template>
<view class="w-full h-360px mb-40rpx"> <view class="h-330px mb-2rpx">
<qiun-data-charts type="area" :chartData="chartData" :opts="chartOpts" /> <qiun-data-charts type="area" :chartData="chartData" :opts="chartOpts" />
</view> </view>
</wd-card> </wd-card>
@@ -135,11 +135,7 @@ const chartOpts = ref({
// 日期范围 // 日期范围
const recentDaysRange = ref(7); const recentDaysRange = ref(7);
const swiperList = ref([ const swiperList = ref(["/static/images/banner01.jpg", "/static/images/banner02.jpg"]);
"/static/images/banner02.jpg",
"/static/images/banner03.jpg",
"/static/images/banner01.png",
]);
// 快捷导航列表 // 快捷导航列表
const navList = reactive([ const navList = reactive([
@@ -194,13 +190,6 @@ const generateStaticTrendData = (days: number) => {
}; };
}; };
function handleClick(e: any) {
console.log(e);
}
function onChange(e: any) {
console.log(e);
}
// 加载访问统计数据(使用静态数据) // 加载访问统计数据(使用静态数据)
const loadVisitStatsData = async () => { const loadVisitStatsData = async () => {
// 模拟异步加载 // 模拟异步加载
+15 -6
View File
@@ -5,7 +5,7 @@
<!-- Logo和标题区域 --> <!-- Logo和标题区域 -->
<view class="header"> <view class="header">
<wd-img src="/static/logo.png" class="logo" mode="aspectFit" /> <wd-img src="./static/logo.png" class="logo" mode="aspectFit" />
<text class="title">FastApp管理系统</text> <text class="title">FastApp管理系统</text>
<text class="subtitle">欢迎使用移动端管理平台</text> <text class="subtitle">欢迎使用移动端管理平台</text>
</view> </view>
@@ -174,15 +174,17 @@
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import { useUserStore } from "@/store"; import { useUserStore } from "@/store";
import { useToast } from "wot-design-uni"; import { useToast } from "wot-design-uni";
import { useTheme } from "@/composables/useTheme";
import AuthAPI, { type LoginFormData, type CaptchaInfo } from "@/api/auth"; import AuthAPI, { type LoginFormData, type CaptchaInfo } from "@/api/auth";
import { useThemeStore } from "@/store/modules/theme.store";
const useTheme = useThemeStore();
const loginFormRef = ref(); const loginFormRef = ref();
const toast = useToast(); const toast = useToast();
const loading = ref(false); const loading = ref(false);
const userStore = useUserStore(); const userStore = useUserStore();
const loginType = ref<"account" | "phone">("account"); const loginType = ref<"account" | "phone">("account");
const { theme } = useTheme(); let theme = useTheme.theme;
// 登录表单数据 // 登录表单数据
const loginFormData = ref<LoginFormData>({ const loginFormData = ref<LoginFormData>({
@@ -281,7 +283,7 @@ const handleWechatLogin = async () => {
}; };
// 是否暗黑模式 // 是否暗黑模式
const isDarkMode = computed(() => theme.value === "dark"); const isDarkMode = computed(() => theme === "dark");
// 导航函数 // 导航函数
const navigateToUserAgreement = () => { const navigateToUserAgreement = () => {
@@ -314,14 +316,21 @@ onLoad((options) => {
} }
}); });
</script> </script>
<route lang="json">
{
"name": "login",
"style": {
"navigationBarTitleText": "登录"
}
}
</route>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-container { .app-container {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
height: 100%; height: 100vh;
min-height: 100%; min-height: 100%;
overflow: hidden; overflow: hidden;
background-color: var(--wot-color-bg-container); background-color: var(--wot-color-bg-container);
+1 -1
View File
@@ -5,7 +5,7 @@
<wd-img <wd-img
width="120rpx" width="120rpx"
height="120rpx" height="120rpx"
src="/static/logo.png" src="./static/logo.png"
mode="aspectFit" mode="aspectFit"
class="about-logo" class="about-logo"
/> />
+13 -5
View File
@@ -47,16 +47,24 @@
<wd-collapse v-model="activeNames" accordion> <wd-collapse v-model="activeNames" accordion>
<wd-collapse-item title="常见问题" name="faq"> <wd-collapse-item title="常见问题" name="faq">
<view class="faq-list"> <view class="faq-list">
<view v-for="(item, index) in faqList" :key="index" class="faq-item" :class="{ <view
active: currentFaq === index, v-for="(item, index) in faqList"
}" @tap="toggleFaq(index)"> :key="index"
class="faq-item"
:class="{ active: currentFaq === index }"
@tap="toggleFaq(index)"
>
<view class="faq-header"> <view class="faq-header">
<view class="faq-question"> <view class="faq-question">
<wd-icon name="question-filled" size="28rpx" color="#ff9500" /> <wd-icon name="question-filled" size="28rpx" color="#ff9500" />
<text class="question-text">{{ item.question }}</text> <text class="question-text">{{ item.question }}</text>
</view> </view>
<wd-icon name="arrow-down-bold" size="24rpx" color="#999" <wd-icon
:custom-class="currentFaq === index ? 'rotate-180' : ''" /> name="arrow-down-bold"
size="24rpx"
color="#999"
:custom-class="currentFaq === index ? 'rotate-180' : ''"
/>
</view> </view>
<view v-if="currentFaq === index" class="faq-answer"> <view v-if="currentFaq === index" class="faq-answer">
<text class="answer-text">{{ item.answer }}</text> <text class="answer-text">{{ item.answer }}</text>
+24 -6
View File
@@ -10,14 +10,32 @@
</wd-radio> </wd-radio>
</wd-radio-group> </wd-radio-group>
<wd-textarea v-model="formData.description" label="问题描述" prop="description" placeholder="请详细描述您遇到的问题或建议..." <wd-textarea
:maxlength="120" show-word-limit /> v-model="formData.description"
label="问题描述"
prop="description"
placeholder="请详细描述您遇到的问题或建议..."
:maxlength="120"
show-word-limit
/>
<wd-upload v-model="formData.fileList" label="相关截图" prop="fileList" :max-count="3" :before-read="beforeRead" <wd-upload
@delete="handleDelete" /> v-model="formData.fileList"
label="相关截图"
prop="fileList"
:max-count="3"
:before-read="beforeRead"
@delete="handleDelete"
/>
<wd-input v-model="formData.contact" label="联系方式" prop="contact" placeholder="请输入您的手机号或邮箱" clearable <wd-input
:border="false" /> v-model="formData.contact"
label="联系方式"
prop="contact"
placeholder="请输入您的手机号或邮箱"
clearable
:border="false"
/>
<wd-text size="small">选填便于我们与您联系</wd-text> <wd-text size="small">选填便于我们与您联系</wd-text>
</wd-cell-group> </wd-cell-group>
+2 -2
View File
@@ -358,7 +358,7 @@ watch(
// 卡片容器 // 卡片容器
.card-container { .card-container {
margin: 24rpx 30rpx; margin: 24rpx 12rpx;
overflow: hidden; overflow: hidden;
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
@@ -419,7 +419,7 @@ watch(
display: flex; display: flex;
align-items: center; align-items: center;
padding: 30rpx; padding: 30rpx;
margin: 20rpx 30rpx; margin: 24rpx 12rpx;
background-color: #ffffff; background-color: #ffffff;
border-radius: 16rpx; border-radius: 16rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1); box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
+3 -5
View File
@@ -1,6 +1,6 @@
<template> <template>
<view class="app-container"> <view class="app-container">
<wd-cell-group custom-style="margin-top: 20rpx"> <wd-cell-group>
<wd-cell v-if="isLogin" title="个人资料" icon="user" is-link @click="navigateToProfile" /> <wd-cell v-if="isLogin" title="个人资料" icon="user" is-link @click="navigateToProfile" />
<wd-cell v-if="isLogin" title="账号和安全" icon="secured" is-link @click="navigateToAccount" /> <wd-cell v-if="isLogin" title="账号和安全" icon="secured" is-link @click="navigateToAccount" />
<wd-cell title="主题设置" icon="setting1" is-link @click="navigateToTheme" /> <wd-cell title="主题设置" icon="setting1" is-link @click="navigateToTheme" />
@@ -8,9 +8,7 @@
<wd-cell title="隐私政策" icon="folder" is-link @click="navigateToPrivacy" /> <wd-cell title="隐私政策" icon="folder" is-link @click="navigateToPrivacy" />
<wd-cell title="关于我们" icon="info-circle" is-link @click="navigateToAbout" /> <wd-cell title="关于我们" icon="info-circle" is-link @click="navigateToAbout" />
<wd-cell title="进入官网" icon="internet" is-link @click="navigateToOfficialWebsite" /> <wd-cell title="进入官网" icon="internet" is-link @click="navigateToOfficialWebsite" />
</wd-cell-group> <wd-divider />
<wd-cell-group custom-style="margin-top:40rpx">
<wd-cell title="网络测试" icon="wifi" is-link @click="navigateToNetworkTest" /> <wd-cell title="网络测试" icon="wifi" is-link @click="navigateToNetworkTest" />
<wd-cell title="清空缓存" icon="delete1" :value="cacheSize" clickable @click="handleClearCache" /> <wd-cell title="清空缓存" icon="delete1" :value="cacheSize" clickable @click="handleClearCache" />
</wd-cell-group> </wd-cell-group>
@@ -214,7 +212,7 @@ onLoad(() => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 20rpx; padding: 0 20rpx;
margin-top: 60rpx; margin-top: 40rpx;
} }
.logout-btn { .logout-btn {
+12 -25
View File
@@ -29,10 +29,10 @@
<text class="color-label">预设主题色</text> <text class="color-label">预设主题色</text>
<view class="color-grid"> <view class="color-grid">
<view <view
v-for="(color, index) in themeColorOptions" v-for="(color, index) in useTheme.themeColorOptions"
:key="index" :key="index"
class="color-item" class="color-item"
:class="{ active: currentThemeColor === color.primary }" :class="{ active: color.primary }"
@click="handleSelectColor(color)" @click="handleSelectColor(color)"
> >
<view <view
@@ -113,13 +113,12 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useTheme } from "@/composables/useTheme"; import { useThemeStore } from "@/store/modules/theme.store";
// 使用主题组合函数 const useTheme = useThemeStore();
const { isDark, themeVars, themeColorOptions, toggleTheme, setThemeColor } = useTheme();
// 创建响应式的计算属性 // 创建响应式的计算属性
const isDarkMode = computed(() => isDark.value); const isDarkMode = computed(() => useTheme.isDark);
// 自定义颜色输入 // 自定义颜色输入
const customColor = ref(""); const customColor = ref("");
@@ -127,12 +126,12 @@ const showCustomColorInput = ref(false);
// 当前选中的主题色 // 当前选中的主题色
const currentThemeColor = computed(() => { const currentThemeColor = computed(() => {
return themeVars.value.colorTheme || themeColorOptions.value[0].primary; return useTheme.themeVars.colorTheme || useTheme.themeColorOptions[0].primary;
}); });
// 选择预设颜色 // 选择预设颜色
const handleSelectColor = (color: (typeof themeColorOptions.value)[0]) => { const handleSelectColor = (color: (typeof useTheme.themeColorOptions)[0]) => {
setThemeColor(color); useTheme.setCurrentThemeColor(color);
customColor.value = color.primary; customColor.value = color.primary;
// 提示 // 提示
@@ -175,7 +174,7 @@ const applyCustomColor = () => {
primary: color, primary: color,
}; };
setThemeColor(customColorOption); useTheme.setCurrentThemeColor(customColorOption);
showCustomColorInput.value = false; showCustomColorInput.value = false;
// 提示 // 提示
@@ -193,8 +192,8 @@ const handleResetTheme = () => {
content: "确定要重置为默认主题吗?", content: "确定要重置为默认主题吗?",
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
setThemeColor(themeColorOptions.value[0]); useTheme.setCurrentThemeColor(useTheme.themeColorOptions[0]);
customColor.value = themeColorOptions.value[0].primary; customColor.value = useTheme.themeColorOptions[0].primary;
uni.showToast({ uni.showToast({
title: "已重置为默认主题", title: "已重置为默认主题",
@@ -208,7 +207,7 @@ const handleResetTheme = () => {
// 切换暗黑模式 // 切换暗黑模式
const handleToggleDarkMode = () => { const handleToggleDarkMode = () => {
toggleTheme(); useTheme.toggleTheme();
nextTick(() => { nextTick(() => {
uni.showToast({ uni.showToast({
title: `已切换到${isDarkMode.value ? "暗黑" : "浅色"}模式`, title: `已切换到${isDarkMode.value ? "暗黑" : "浅色"}模式`,
@@ -378,18 +377,6 @@ onShow(() => {
} }
} }
.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;
}
// 自定义颜色弹窗 // 自定义颜色弹窗
.custom-color-popup { .custom-color-popup {
padding: 40rpx 30rpx; padding: 40rpx 30rpx;
+12 -2
View File
@@ -22,7 +22,12 @@
<text class="section-subtitle">常用功能一键直达</text> <text class="section-subtitle">常用功能一键直达</text>
</view> </view>
<view class="actions-grid"> <view class="actions-grid">
<view class="action-item" v-for="(action, index) in quickActions" :key="index" @tap="handleQuickAction(action)"> <view
v-for="(action, index) in quickActions"
:key="index"
class="action-item"
@tap="handleQuickAction(action)"
>
<view class="action-icon" :style="{ backgroundColor: action.color + '15' }"> <view class="action-icon" :style="{ backgroundColor: action.color + '15' }">
<wd-icon :name="action.icon" :color="action.color" size="28" /> <wd-icon :name="action.icon" :color="action.color" size="28" />
</view> </view>
@@ -38,7 +43,12 @@
<text class="section-subtitle">{{ pendingTodos.length }} 项待处理</text> <text class="section-subtitle">{{ pendingTodos.length }} 项待处理</text>
</view> </view>
<view class="todo-list"> <view class="todo-list">
<view class="todo-item" v-for="(todo, index) in pendingTodos" :key="index" @tap="handleTodoItem(todo)"> <view
v-for="(todo, index) in pendingTodos"
:key="index"
class="todo-item"
@tap="handleTodoItem(todo)"
>
<view class="todo-priority" :class="'priority-' + todo.priority"> <view class="todo-priority" :class="'priority-' + todo.priority">
<view class="priority-dot"></view> <view class="priority-dot"></view>
</view> </view>
-1
View File
@@ -32,7 +32,6 @@ const router = createRouter({
// 全局前置守卫 // 全局前置守卫
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
// 检查页面是否需要登录
if (to.meta && to.meta.requireAuth && !isLoggedIn()) { if (to.meta && to.meta.requireAuth && !isLoggedIn()) {
uni.showModal({ uni.showModal({
title: "提示", title: "提示",
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

@@ -1,31 +0,0 @@
<svg width="100%" height="100%" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
<!-- 背景渐变 -->
<defs>
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#94BFFF" />
<stop offset="100%" stop-color="#165DFF" />
</linearGradient>
<!-- 图形渐变 -->
<linearGradient id="shapeGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ffffff" stop-opacity="0.3" />
<stop offset="100%" stop-color="#ffffff" stop-opacity="0.15" />
</linearGradient>
</defs>
<!-- 透明背景,不完全填充 -->
<rect width="100%" height="50%" fill="url(#bgGradient)" />
<!-- 左侧方块装饰 -->
<rect x="100" y="150" width="120" height="120" rx="15" fill="url(#shapeGradient)" transform="rotate(-10, 160, 210)" opacity="0.7" />
<rect x="190" y="90" width="80" height="80" rx="10" fill="url(#shapeGradient)" transform="rotate(15, 230, 130)" opacity="0.6" />
<rect x="60" y="250" width="100" height="100" rx="10" fill="url(#shapeGradient)" transform="rotate(-5, 110, 300)" opacity="0.5" />
<!-- 右侧圆形装饰 -->
<circle cx="750" cy="150" r="60" fill="url(#shapeGradient)" opacity="0.7" />
<circle cx="820" cy="230" r="90" fill="url(#shapeGradient)" opacity="0.5" />
<circle cx="690" cy="250" r="40" fill="url(#shapeGradient)" opacity="0.6" />
<!-- 底部波浪 -->
<path d="M0,900 C200,800 350,950 550,870 C750,790 850,900 1000,850 L1000,1000 L0,1000 Z" fill="#ffffff" />
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

+12 -7
View File
@@ -1,6 +1,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import type { ConfigProviderThemeVars } from "wot-design-uni";
import { useStorage } from "@uni-helper/uni-use"; import { useStorage } from "@uni-helper/uni-use";
import type { ConfigProviderThemeVars } from "wot-design-uni";
import { nextTick, reactive, computed } from "vue";
// 主题色选项接口 // 主题色选项接口
export interface ThemeColorOption { export interface ThemeColorOption {
@@ -46,12 +47,6 @@ export const useThemeStore = defineStore("appTheme", () => {
// 计算属性 // 计算属性
const isDark = computed(() => theme.value === "dark"); const isDark = computed(() => theme.value === "dark");
// 切换主题, 指定主题模式,不传则自动切换
const toggleTheme = (mode?: ThemeMode) => {
theme.value = mode || (theme.value === "light" ? "dark" : "light");
setNavigationBarColor();
};
// 设置导航栏颜色 // 设置导航栏颜色
const setNavigationBarColor = () => { const setNavigationBarColor = () => {
console.log("设置导航栏颜色", theme.value); console.log("设置导航栏颜色", theme.value);
@@ -61,6 +56,12 @@ export const useThemeStore = defineStore("appTheme", () => {
}); });
}; };
// 切换主题, 指定主题模式,不传则自动切换
const toggleTheme = (mode?: ThemeMode) => {
theme.value = mode || (theme.value === "light" ? "dark" : "light");
setNavigationBarColor();
};
// 设置主题色 // 设置主题色
const setCurrentThemeColor = (color: ThemeColorOption) => { const setCurrentThemeColor = (color: ThemeColorOption) => {
currentThemeColor.value = color; currentThemeColor.value = color;
@@ -79,6 +80,10 @@ export const useThemeStore = defineStore("appTheme", () => {
}); });
}; };
// 注意:全局主题管理已在App.vue中处理
// 包括:系统主题监听、导航栏颜色同步等
// 组件中一般不需要再调用initTheme(),除非有特殊需求
return { return {
// 状态 // 状态
theme, theme,
+26
View File
@@ -0,0 +1,26 @@
{
"light": {
"bgColor": "#F8F8F8",
"bgColorBottom": "#F8F8F8",
"bgColorTop": "#F8F8F8",
"bgTxtStyle": "dark",
"navBgColor": "#FFF",
"navTxtStyle": "black",
"tabBgColor": "#ffffff",
"tabBorderStyle": "black",
"tabColor": "#bfbfbf",
"tabSelectedColor": "#0165FF"
},
"dark": {
"bgColor": "#000",
"bgColorBottom": "#000",
"bgColorTop": "#000",
"bgTxtStyle": "light",
"navBgColor": "#000000",
"navTxtStyle": "white",
"tabBgColor": "#1a1a1a",
"tabBorderStyle": "white",
"tabColor": "#bfbfbf",
"tabSelectedColor": "#0165FF"
}
}
-1
View File
@@ -326,7 +326,6 @@ declare module 'vue' {
readonly useStomp: UnwrapRef<typeof import('../composables/useStomp')['useStomp']> readonly useStomp: UnwrapRef<typeof import('../composables/useStomp')['useStomp']>
readonly useTabbar: UnwrapRef<typeof import('../composables/useTabbar')['useTabbar']> readonly useTabbar: UnwrapRef<typeof import('../composables/useTabbar')['useTabbar']>
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']> readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
readonly useTheme: UnwrapRef<typeof import('../composables/useTheme')['useTheme']>
readonly useThemeStore: UnwrapRef<typeof import('../store/modules/theme.store')['useThemeStore']> readonly useThemeStore: UnwrapRef<typeof import('../store/modules/theme.store')['useThemeStore']>
readonly useToast: UnwrapRef<typeof import('wot-design-uni')['useToast']> readonly useToast: UnwrapRef<typeof import('wot-design-uni')['useToast']>
readonly useUserStore: UnwrapRef<typeof import('../store/modules/user.store')['useUserStore']> readonly useUserStore: UnwrapRef<typeof import('../store/modules/user.store')['useUserStore']>
+35
View File
@@ -0,0 +1,35 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by vite-plugin-uni-pages
interface NavigateToOptions {
url: "/pages/index/index" |
"/pages/login/index" |
"/pages/mine/index" |
"/pages/work/index" |
"/pages/mine/about/index" |
"/pages/mine/faq/index" |
"/pages/mine/feedback/index" |
"/pages/mine/profile/complete-profile" |
"/pages/mine/profile/index" |
"/pages/mine/settings/index" |
"/pages/mine/settings/account/index" |
"/pages/mine/settings/agreement/index" |
"/pages/mine/settings/network/index" |
"/pages/mine/settings/theme/index";
}
interface RedirectToOptions extends NavigateToOptions {}
interface SwitchTabOptions {
url: "/pages/index/index" | "/pages/mine/index"
}
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;
declare interface Uni {
navigateTo(options: UniNamespace.NavigateToOptions & NavigateToOptions): void;
redirectTo(options: UniNamespace.RedirectToOptions & RedirectToOptions): void;
switchTab(options: UniNamespace.SwitchTabOptions & SwitchTabOptions): void;
reLaunch(options: UniNamespace.ReLaunchOptions & ReLaunchOptions): void;
}
+11 -1
View File
@@ -12,10 +12,20 @@ export default {
], ],
shortcuts: [ shortcuts: [
{ {
"flex-center": "flex justify-center items-center flex-wrap", "flex-center": "flex justify-center items-center",
"flex-start": "flex justify-start items-center", "flex-start": "flex justify-start items-center",
"flex-end": "flex justify-end items-center", "flex-end": "flex justify-end items-center",
"flex-between": "flex justify-between items-center", "flex-between": "flex justify-between items-center",
"flex-around": "flex justify-around items-center",
"flex-evenly": "flex justify-evenly items-center",
"flex-stretch": "flex justify-stretch items-center",
"flex-baseline": "flex justify-baseline items-center",
"flex-column": "flex flex-col",
"flex-row": "flex flex-row",
// 垂直布局并居中对齐
"flex-col-center": "flex flex-col items-center",
}, },
], ],
+1
View File
@@ -3,6 +3,7 @@ import uni from "@dcloudio/vite-plugin-uni";
import AutoImport from "unplugin-auto-import/vite"; import AutoImport from "unplugin-auto-import/vite";
import UniLayouts from "@uni-helper/vite-plugin-uni-layouts"; import UniLayouts from "@uni-helper/vite-plugin-uni-layouts";
import UniPages from "@uni-helper/vite-plugin-uni-pages"; import UniPages from "@uni-helper/vite-plugin-uni-pages";
import Components from "@uni-helper/vite-plugin-uni-components"; import Components from "@uni-helper/vite-plugin-uni-components";
import { WotResolver } from "@uni-helper/vite-plugin-uni-components/resolvers"; import { WotResolver } from "@uni-helper/vite-plugin-uni-components/resolvers";
-1
View File
@@ -587,7 +587,6 @@ declare module 'vue' {
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']> readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']> readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']> readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']>
readonly useTimeAgoIntl: UnwrapRef<typeof import('@vueuse/core')['useTimeAgoIntl']>
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']> readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']>
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']> readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']>