feat: 重构主题管理并优化UI样式
重构主题管理逻辑,将useTheme composable迁移至pinia store中管理 更新页面布局和样式,调整边距和卡片样式 添加新的主题配置文件并移除旧的主题图片资源 优化登录页和设置页的UI交互 更新unocss配置添加更多flex快捷类
@@ -7,7 +7,7 @@ VITE_APP_ENV=development
|
||||
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
|
||||
|
||||
@@ -93,68 +93,6 @@
|
||||
"watchSyncEffect": true,
|
||||
"DirectiveBinding": true,
|
||||
"MaybeRef": 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
|
||||
"MaybeRefOrGetter": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"],
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
@@ -23,8 +23,6 @@ declare module 'vue' {
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
@@ -32,15 +30,12 @@ declare module 'vue' {
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
@@ -49,8 +44,6 @@ declare module 'vue' {
|
||||
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']
|
||||
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']
|
||||
WdUpload: typeof import('wot-design-uni/components/wd-upload/wd-upload.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,6 @@ export default [
|
||||
"**/u-charts/**",
|
||||
"**/qiun-**/**",
|
||||
"**/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 全局对象
|
||||
UniApp: "readonly", // uni-app 全局对象
|
||||
PageResult: "readonly", // 分页结果数据类型
|
||||
PageQuery: "readonly", // 分页查询数据类型
|
||||
OptionType: "readonly", // 选项类型
|
||||
getCurrentPages: "readonly", // uni-app 全局 API
|
||||
ApiResponse: "readonly", // 统一响应数据类型
|
||||
PageQuery: "readonly", // 分页查询数据类型
|
||||
PageResult: "readonly", // 分页结果数据类型
|
||||
OptionType: "readonly", // 选项类型
|
||||
creatorType: "readonly", // 创建人类型
|
||||
UploadFileResult: "readonly", // 上传文件返回类型
|
||||
Todo: "readonly", // 待办事项
|
||||
TodoState: "readonly", // 待办事项状态
|
||||
plus: true, // HTML5+ 运行时环境
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
Before Width: | Height: | Size: 3.0 MiB |
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,16 @@
|
||||
<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 lang="ts">
|
||||
|
||||
@@ -26,12 +26,15 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter, useRoute } from "uni-mini-router";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import { useTabbar } from "@/composables/useTabbar";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
|
||||
const useTheme = useThemeStore();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { themeVars, theme } = useTheme();
|
||||
let theme = useTheme.theme;
|
||||
let themeVars = useTheme.themeVars;
|
||||
const { activeTabbar, getTabbarItemValue, setTabbarItemActive, tabbarList } = useTabbar();
|
||||
|
||||
function handleTabbarChange({ value }: { value: string }) {
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
@@ -19,7 +11,11 @@
|
||||
},
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"type": "page"
|
||||
"type": "page",
|
||||
"name": "login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/index",
|
||||
@@ -127,20 +123,27 @@
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "@navBgColor",
|
||||
"navigationBarTextStyle": "@navTxtStyle",
|
||||
"navigationBarTitleText": "FastApp",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
"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": "#474747",
|
||||
"selectedColor": "#3B8DFF",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"borderStyle": "black",
|
||||
"color": "@tabColor",
|
||||
"selectedColor": "@tabSelectedColor",
|
||||
"backgroundColor": "@tabBgColor",
|
||||
"borderStyle": "@tabBorderStyle",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index"
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
|
||||
<wd-card>
|
||||
<wd-card type="rectangle">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view>访问趋势</view>
|
||||
@@ -76,7 +76,7 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="w-full h-360px mb-40rpx">
|
||||
<view class="h-330px mb-2rpx">
|
||||
<qiun-data-charts type="area" :chartData="chartData" :opts="chartOpts" />
|
||||
</view>
|
||||
</wd-card>
|
||||
@@ -135,11 +135,7 @@ const chartOpts = ref({
|
||||
// 日期范围
|
||||
const recentDaysRange = ref(7);
|
||||
|
||||
const swiperList = ref([
|
||||
"/static/images/banner02.jpg",
|
||||
"/static/images/banner03.jpg",
|
||||
"/static/images/banner01.png",
|
||||
]);
|
||||
const swiperList = ref(["/static/images/banner01.jpg", "/static/images/banner02.jpg"]);
|
||||
|
||||
// 快捷导航列表
|
||||
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 () => {
|
||||
// 模拟异步加载
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<!-- Logo和标题区域 -->
|
||||
<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="subtitle">欢迎使用移动端管理平台</text>
|
||||
</view>
|
||||
@@ -174,15 +174,17 @@
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { useUserStore } from "@/store";
|
||||
import { useToast } from "wot-design-uni";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import AuthAPI, { type LoginFormData, type CaptchaInfo } from "@/api/auth";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
|
||||
const useTheme = useThemeStore();
|
||||
|
||||
const loginFormRef = ref();
|
||||
const toast = useToast();
|
||||
const loading = ref(false);
|
||||
const userStore = useUserStore();
|
||||
const loginType = ref<"account" | "phone">("account");
|
||||
const { theme } = useTheme();
|
||||
let theme = useTheme.theme;
|
||||
|
||||
// 登录表单数据
|
||||
const loginFormData = ref<LoginFormData>({
|
||||
@@ -281,7 +283,7 @@ const handleWechatLogin = async () => {
|
||||
};
|
||||
|
||||
// 是否暗黑模式
|
||||
const isDarkMode = computed(() => theme.value === "dark");
|
||||
const isDarkMode = computed(() => theme === "dark");
|
||||
|
||||
// 导航函数
|
||||
const navigateToUserAgreement = () => {
|
||||
@@ -314,14 +316,21 @@ onLoad((options) => {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<route lang="json">
|
||||
{
|
||||
"name": "login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
}
|
||||
</route>
|
||||
<style lang="scss" scoped>
|
||||
.app-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--wot-color-bg-container);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<wd-img
|
||||
width="120rpx"
|
||||
height="120rpx"
|
||||
src="/static/logo.png"
|
||||
src="./static/logo.png"
|
||||
mode="aspectFit"
|
||||
class="about-logo"
|
||||
/>
|
||||
|
||||
@@ -47,16 +47,24 @@
|
||||
<wd-collapse v-model="activeNames" accordion>
|
||||
<wd-collapse-item title="常见问题" name="faq">
|
||||
<view class="faq-list">
|
||||
<view v-for="(item, index) in faqList" :key="index" class="faq-item" :class="{
|
||||
active: currentFaq === index,
|
||||
}" @tap="toggleFaq(index)">
|
||||
<view
|
||||
v-for="(item, index) in faqList"
|
||||
:key="index"
|
||||
class="faq-item"
|
||||
:class="{ active: currentFaq === index }"
|
||||
@tap="toggleFaq(index)"
|
||||
>
|
||||
<view class="faq-header">
|
||||
<view class="faq-question">
|
||||
<wd-icon name="question-filled" size="28rpx" color="#ff9500" />
|
||||
<text class="question-text">{{ item.question }}</text>
|
||||
</view>
|
||||
<wd-icon name="arrow-down-bold" size="24rpx" color="#999"
|
||||
:custom-class="currentFaq === index ? 'rotate-180' : ''" />
|
||||
<wd-icon
|
||||
name="arrow-down-bold"
|
||||
size="24rpx"
|
||||
color="#999"
|
||||
:custom-class="currentFaq === index ? 'rotate-180' : ''"
|
||||
/>
|
||||
</view>
|
||||
<view v-if="currentFaq === index" class="faq-answer">
|
||||
<text class="answer-text">{{ item.answer }}</text>
|
||||
|
||||
@@ -10,14 +10,32 @@
|
||||
</wd-radio>
|
||||
</wd-radio-group>
|
||||
|
||||
<wd-textarea v-model="formData.description" label="问题描述" prop="description" placeholder="请详细描述您遇到的问题或建议..."
|
||||
:maxlength="120" show-word-limit />
|
||||
<wd-textarea
|
||||
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"
|
||||
@delete="handleDelete" />
|
||||
<wd-upload
|
||||
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
|
||||
:border="false" />
|
||||
<wd-input
|
||||
v-model="formData.contact"
|
||||
label="联系方式"
|
||||
prop="contact"
|
||||
placeholder="请输入您的手机号或邮箱"
|
||||
clearable
|
||||
:border="false"
|
||||
/>
|
||||
<wd-text size="small">选填,便于我们与您联系</wd-text>
|
||||
</wd-cell-group>
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ watch(
|
||||
|
||||
// 卡片容器
|
||||
.card-container {
|
||||
margin: 24rpx 30rpx;
|
||||
margin: 24rpx 12rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
@@ -419,7 +419,7 @@ watch(
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
margin: 20rpx 30rpx;
|
||||
margin: 24rpx 12rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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="secured" is-link @click="navigateToAccount" />
|
||||
<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="info-circle" is-link @click="navigateToAbout" />
|
||||
<wd-cell title="进入官网" icon="internet" is-link @click="navigateToOfficialWebsite" />
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-style="margin-top:40rpx">
|
||||
<wd-divider />
|
||||
<wd-cell title="网络测试" icon="wifi" is-link @click="navigateToNetworkTest" />
|
||||
<wd-cell title="清空缓存" icon="delete1" :value="cacheSize" clickable @click="handleClearCache" />
|
||||
</wd-cell-group>
|
||||
@@ -214,7 +212,7 @@ onLoad(() => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 20rpx;
|
||||
margin-top: 60rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
<text class="color-label">预设主题色</text>
|
||||
<view class="color-grid">
|
||||
<view
|
||||
v-for="(color, index) in themeColorOptions"
|
||||
v-for="(color, index) in useTheme.themeColorOptions"
|
||||
:key="index"
|
||||
class="color-item"
|
||||
:class="{ active: currentThemeColor === color.primary }"
|
||||
:class="{ active: color.primary }"
|
||||
@click="handleSelectColor(color)"
|
||||
>
|
||||
<view
|
||||
@@ -113,13 +113,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
|
||||
// 使用主题组合函数
|
||||
const { isDark, themeVars, themeColorOptions, toggleTheme, setThemeColor } = useTheme();
|
||||
const useTheme = useThemeStore();
|
||||
|
||||
// 创建响应式的计算属性
|
||||
const isDarkMode = computed(() => isDark.value);
|
||||
const isDarkMode = computed(() => useTheme.isDark);
|
||||
|
||||
// 自定义颜色输入
|
||||
const customColor = ref("");
|
||||
@@ -127,12 +126,12 @@ const showCustomColorInput = ref(false);
|
||||
|
||||
// 当前选中的主题色
|
||||
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]) => {
|
||||
setThemeColor(color);
|
||||
const handleSelectColor = (color: (typeof useTheme.themeColorOptions)[0]) => {
|
||||
useTheme.setCurrentThemeColor(color);
|
||||
customColor.value = color.primary;
|
||||
|
||||
// 提示
|
||||
@@ -175,7 +174,7 @@ const applyCustomColor = () => {
|
||||
primary: color,
|
||||
};
|
||||
|
||||
setThemeColor(customColorOption);
|
||||
useTheme.setCurrentThemeColor(customColorOption);
|
||||
showCustomColorInput.value = false;
|
||||
|
||||
// 提示
|
||||
@@ -193,8 +192,8 @@ const handleResetTheme = () => {
|
||||
content: "确定要重置为默认主题吗?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
setThemeColor(themeColorOptions.value[0]);
|
||||
customColor.value = themeColorOptions.value[0].primary;
|
||||
useTheme.setCurrentThemeColor(useTheme.themeColorOptions[0]);
|
||||
customColor.value = useTheme.themeColorOptions[0].primary;
|
||||
|
||||
uni.showToast({
|
||||
title: "已重置为默认主题",
|
||||
@@ -208,7 +207,7 @@ const handleResetTheme = () => {
|
||||
|
||||
// 切换暗黑模式
|
||||
const handleToggleDarkMode = () => {
|
||||
toggleTheme();
|
||||
useTheme.toggleTheme();
|
||||
nextTick(() => {
|
||||
uni.showToast({
|
||||
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 {
|
||||
padding: 40rpx 30rpx;
|
||||
|
||||
@@ -22,7 +22,12 @@
|
||||
<text class="section-subtitle">常用功能一键直达</text>
|
||||
</view>
|
||||
<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' }">
|
||||
<wd-icon :name="action.icon" :color="action.color" size="28" />
|
||||
</view>
|
||||
@@ -38,7 +43,12 @@
|
||||
<text class="section-subtitle">{{ pendingTodos.length }} 项待处理</text>
|
||||
</view>
|
||||
<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="priority-dot"></view>
|
||||
</view>
|
||||
|
||||
@@ -32,7 +32,6 @@ const router = createRouter({
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 检查页面是否需要登录
|
||||
if (to.meta && to.meta.requireAuth && !isLoggedIn()) {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
|
||||
|
After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 37 KiB |
|
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 |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
import type { ConfigProviderThemeVars } from "wot-design-uni";
|
||||
import { useStorage } from "@uni-helper/uni-use";
|
||||
import type { ConfigProviderThemeVars } from "wot-design-uni";
|
||||
import { nextTick, reactive, computed } from "vue";
|
||||
|
||||
// 主题色选项接口
|
||||
export interface ThemeColorOption {
|
||||
@@ -46,12 +47,6 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
// 计算属性
|
||||
const isDark = computed(() => theme.value === "dark");
|
||||
|
||||
// 切换主题, 指定主题模式,不传则自动切换
|
||||
const toggleTheme = (mode?: ThemeMode) => {
|
||||
theme.value = mode || (theme.value === "light" ? "dark" : "light");
|
||||
setNavigationBarColor();
|
||||
};
|
||||
|
||||
// 设置导航栏颜色
|
||||
const setNavigationBarColor = () => {
|
||||
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) => {
|
||||
currentThemeColor.value = color;
|
||||
@@ -79,6 +80,10 @@ export const useThemeStore = defineStore("appTheme", () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 注意:全局主题管理已在App.vue中处理
|
||||
// 包括:系统主题监听、导航栏颜色同步等
|
||||
// 组件中一般不需要再调用initTheme(),除非有特殊需求
|
||||
|
||||
return {
|
||||
// 状态
|
||||
theme,
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -326,7 +326,6 @@ declare module 'vue' {
|
||||
readonly useStomp: UnwrapRef<typeof import('../composables/useStomp')['useStomp']>
|
||||
readonly useTabbar: UnwrapRef<typeof import('../composables/useTabbar')['useTabbar']>
|
||||
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 useToast: UnwrapRef<typeof import('wot-design-uni')['useToast']>
|
||||
readonly useUserStore: UnwrapRef<typeof import('../store/modules/user.store')['useUserStore']>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -12,10 +12,20 @@ export default {
|
||||
],
|
||||
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-end": "flex justify-end 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",
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import uni from "@dcloudio/vite-plugin-uni";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import UniLayouts from "@uni-helper/vite-plugin-uni-layouts";
|
||||
import UniPages from "@uni-helper/vite-plugin-uni-pages";
|
||||
|
||||
import Components from "@uni-helper/vite-plugin-uni-components";
|
||||
import { WotResolver } from "@uni-helper/vite-plugin-uni-components/resolvers";
|
||||
|
||||
|
||||
@@ -587,7 +587,6 @@ declare module 'vue' {
|
||||
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
|
||||
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
|
||||
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 useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
|
||||
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']>
|
||||
|
||||