refactor: 暗黑模式适配调整

This commit is contained in:
Ray.Hao
2025-08-15 20:36:20 +08:00
parent d0baa003e1
commit 8b2ae01a9a
20 changed files with 490 additions and 447 deletions

View File

@@ -25,10 +25,9 @@
</template>
<script setup lang="ts">
import { useRoute } from "vue-router";
import { useThemeStore } from "@/store";
import { useTabbar } from "@/composables/useTabbar";
import { useRouter } from "uni-mini-router";
import { useRouter, useRoute } from "uni-mini-router";
import { storeToRefs } from "pinia";
const router = useRouter();
@@ -47,11 +46,8 @@ onMounted(() => {
uni.hideTabBar();
// #endif
nextTick(() => {
if (route.name) {
const routeName = typeof route.name === "string" ? route.name : "";
if (routeName !== activeTabbar.value.name) {
setTabbarItemActive(routeName);
}
if (route.name && route.name !== activeTabbar.value.name) {
setTabbarItemActive(route.name);
}
});
});

View File

@@ -43,7 +43,14 @@
},
{
"path": "pages/mine/feedback/index",
"type": "page"
"type": "page",
"name": "feedback",
"style": {
"navigationBarTitleText": "意见反馈"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/mine/profile/complete-profile",
@@ -117,5 +124,6 @@
}
]
},
"__esModule": true,
"subPackages": []
}
}

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-swiper
v-model:current="current"
:list="swiperList"
@@ -89,6 +89,7 @@
<script setup lang="ts">
import { dayjs } from "wot-design-uni";
import { useRouter } from "uni-mini-router";
// 定义访问统计数据类型
interface VisitStatsVO {
@@ -257,18 +258,6 @@ onReady(() => {
loadVisitStatsData();
loadVisitTrendData();
});
onShow(() => {
// 确保 tabbar 状态正确
const pages = getCurrentPages();
if (pages.length > 0) {
const currentPage = pages[pages.length - 1];
if (currentPage.route === "pages/index/index") {
// 通过事件通知 tabbar 布局更新状态
uni.$emit("updateTabbar", "index");
}
}
});
</script>
<route lang="json">

View File

@@ -12,12 +12,7 @@
<wd-form v-if="loginType === 'account'" ref="loginFormRef" :model="loginFormData">
<!-- 用户名输入框 -->
<view class="form-item">
<wd-icon
name="user"
size="22"
:color="isDarkMode ? '#7AC5FF' : '#333'"
class="input-icon"
/>
<wd-icon name="user" size="22" class="input-icon" />
<input
v-model="loginFormData.username"
class="form-input input-transparent"
@@ -33,7 +28,7 @@
<input
v-model="loginFormData.password"
class="form-input input-transparent"
:type="showPassword ? 'text' : 'password'"
:password="!showPassword"
placeholder="请输入密码"
placeholder-class="input-placeholder"
/>
@@ -135,11 +130,12 @@ const loginFormData = ref<LoginData>({
password: "123456",
});
// 获取重定向参数
// 仅使用 query 作为重定向来源
const redirect = ref("/pages/index/index");
onLoad((options) => {
if (options && options.redirect) {
redirect.value = decodeURIComponent(options.redirect);
const fromQuery = options && options.redirect ? decodeURIComponent(options.redirect) : "";
if (fromQuery && fromQuery !== "/pages/login/index") {
redirect.value = fromQuery;
}
});
@@ -176,11 +172,11 @@ const handleAccountLogin = () => {
.then(() => {
toast.success("登录成功");
console.log("跳转链接", redirect.value);
// 账号密码登录直接跳转到重定向页面
setTimeout(() => {
uni.reLaunch({
url: redirect.value,
});
uni.reLaunch({ url: redirect.value });
}, 1000);
})
.catch((error) => {
@@ -211,16 +207,13 @@ const handleWechatPhoneLogin = async (e: any) => {
if (result.isNewUser || !userStore.isUserInfoComplete()) {
// 跳转到完善信息页面
setTimeout(() => {
uni.navigateTo({
url: `/pages/mine/profile/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
});
// 跳转完善资料,redirect 保持在缓存中供目标页读取
uni.navigateTo({ url: "/pages/mine/profile/complete-profile" });
}, 1000);
} else {
// 跳转到重定向页面
setTimeout(() => {
uni.reLaunch({
url: redirect.value,
});
uni.reLaunch({ url: redirect.value });
}, 1000);
}
} catch (error: any) {
@@ -256,16 +249,12 @@ const handleWechatLogin = async () => {
if (result.isNewUser || !userStore.isUserInfoComplete()) {
// 如果信息不完整,跳转到完善信息页面
setTimeout(() => {
uni.navigateTo({
url: `/pages/mine/profile/complete-profile?redirect=${encodeURIComponent(redirect.value)}`,
});
uni.navigateTo({ url: "/pages/mine/profile/complete-profile" });
}, 1000);
} else {
// 否则直接跳转到重定向页面
setTimeout(() => {
uni.reLaunch({
url: redirect.value,
});
uni.reLaunch({ url: redirect.value });
}, 1000);
}
// #endif

View File

@@ -1,23 +1,29 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-card>
<view class="flex items-center p-2">
<wd-img width="60px" height="60px" src="/static/logo.png" mode="aspectFit" class="mr-4" />
<view class="flex-1">
<text class="text-lg font-bold block mb-1">vue-uniapp-template</text>
<text class="text-xs text-gray-500">版本 {{ version }}</text>
<view class="about-header">
<wd-img
width="120rpx"
height="120rpx"
src="/static/logo.png"
mode="aspectFit"
class="about-logo"
/>
<view class="about-meta">
<text class="app-title">vue-uniapp-template</text>
<text class="app-version">版本 {{ version }}</text>
</view>
</view>
</wd-card>
<!-- 公司信息区域 -->
<wd-card custom-style="margin-top: 20rpx">
<view class="p-4">
<view class="flex items-center mb-3">
<wd-icon name="company" size="18" class="mr-2" />
<text class="text-base font-medium">有来开源组织</text>
<view class="company-section">
<view class="section-title">
<wd-icon name="company" size="18" />
<text>有来开源组织</text>
</view>
<text class="text-sm text-gray-500 block pl-6">专注于快速构建和高效开发的应用解决方案</text>
<text class="section-subtitle">专注于快速构建和高效开发的应用解决方案</text>
</view>
</wd-card>
@@ -25,19 +31,19 @@
<wd-card title="优质项目" custom-style="margin-top: 20rpx">
<wd-cell-group border>
<wd-cell title="vue3-element-admin" icon="desktop">
<view slot="label" class="text-xs text-gray-500 mt-1">
基于 Vue3 + Vite5 + TypeScript5 + Element-Plus + Pinia 构建的中后台管理模板
<view slot="label" class="project-desc">
基于 Vue3 + Vite7 + TypeScript5 + Element-Plus + Pinia 构建的中后台管理模板
</view>
</wd-cell>
<wd-cell title="vue-uniapp-template" icon="mobile">
<view slot="label" class="text-xs text-gray-500 mt-1">
<view slot="label" class="project-desc">
基于 uni-app + Vue 3 + TypeScript,集成多种工具的移动端应用模板
</view>
</wd-cell>
<wd-cell title="youlai-boot" icon="server">
<view slot="label" class="text-xs text-gray-500 mt-1">
<view slot="label" class="project-desc">
基于 Spring Boot 3 + Vue 3 构建的前后端分离单体权限管理系统
</view>
</wd-cell>
@@ -54,9 +60,9 @@
</wd-card>
<!-- 底部版权信息 -->
<view class="text-center py-4">
<text class="block text-xs text-gray-400">Copyright © {{ getYear() }} 有来开源组织</text>
<text class="block text-xs text-gray-400 mt-1">All Rights Reserved</text>
<view class="about-footer">
<text class="copyright">Copyright © {{ getYear() }} 有来开源组织</text>
<text class="copyright copyright-sub">All Rights Reserved</text>
</view>
</view>
</template>
@@ -75,14 +81,73 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
:deep(.wd-card__header) {
font-size: 30rpx;
font-weight: 500;
color: var(--wot-color-text, #333);
.about-header {
display: flex;
align-items: center;
padding: 20rpx;
}
:deep(.wd-cell__icon) {
font-size: 36rpx;
color: var(--wot-color-theme, #409eff);
.about-logo {
margin-right: 16rpx;
}
.about-meta {
flex: 1;
}
.app-title {
display: block;
margin-bottom: 8rpx;
font-size: 32rpx;
font-weight: 700;
}
.app-version {
font-size: 24rpx;
color: #6b7280;
}
.company-section {
padding: 24rpx;
}
.section-title {
display: flex;
align-items: center;
margin-bottom: 12rpx;
font-size: 28rpx;
font-weight: 500;
:deep(.wd-icon) {
margin-right: 12rpx;
}
}
.section-subtitle {
display: block;
padding-left: 32rpx;
font-size: 24rpx;
color: #6b7280;
}
.project-desc {
margin-top: 8rpx;
font-size: 24rpx;
color: #6b7280;
}
.about-footer {
padding: 32rpx 0;
text-align: center;
}
.copyright {
display: block;
font-size: 24rpx;
color: #9ca3af;
}
.copyright-sub {
margin-top: 8rpx;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<view class="faq-container">
<view class="wechat">
<view class="tips">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<view>
<view class="text-center font-600">
<text>长按关注「有来技术」公众号,获取交流群二维码。</text>
</view>
<view class="flex-center">
@@ -12,12 +12,12 @@
mode="aspectFit"
/>
</view>
<view>
<view class="mt-10rpx">
<text>如果交流群的二维码过期,请加微信(</text>
<text :user-select="true" :selectable="true">haoxianrui</text>
<text>)并备注「前端」、「后端」或「全栈」以获取最新二维码。</text>
</view>
<view>
<view class="mt-10rpx">
<text>为确保交流群质量,防止营销广告人群混入,我们采取了此措施。望各位理解!</text>
</view>
</view>
@@ -135,20 +135,4 @@ const pagesStr = ref<string>(`<pre style="background-color: #f9f9fa"><code>
onMounted(() => {});
</script>
<style lang="scss" scoped>
.faq-container {
min-height: 100vh;
background-color: #f5f5f5;
.wechat {
padding: 30rpx;
margin: 20px 0;
font-size: 14px;
color: var(--wot-card-content-color, rgba(0, 0, 0, 0.45));
background-color: #fff;
.tips {
font-weight: bold;
text-align: center;
}
}
}
</style>
<style lang="scss" scoped></style>

View File

@@ -1,11 +1,7 @@
<template>
<view class="app-container">
<wd-navbar title="意见反馈" left-arrow @click-left="handleBack" />
123
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-text size="small">选填,最多上传3张图片</wd-text>
<wd-form ref="formRef" :model="formData" :rules="rules">
<!-- 问题类型选择 -->
<wd-form-item label="问题类型" prop="feedbackType">
<wd-radio-group v-model="formData.feedbackType" inline>
<wd-radio v-for="item in feedbackTypes" :key="item.value" :value="item.value">
@@ -41,7 +37,7 @@
</wd-form-item>
<!-- 提交按钮 -->
<view class="submit-btn">
<view class="mx-30rpx mt-40rpx">
<wd-button type="primary" block :loading="submitting" @click="handleSubmit">
提交反馈
</wd-button>
@@ -50,19 +46,23 @@
</view>
</template>
<route lang="json">
{
"name": "feedback",
"style": {
"navigationBarTitleText": "意见反馈"
},
"meta": { "requireAuth": true }
}
</route>
<script setup lang="ts">
import { checkLogin } from "@/utils/auth";
import { useToast } from "wot-design-uni";
import { FormRules } from "wot-design-uni/components/wd-form/types";
const toast = useToast();
const formRef = ref();
// 检查登录状态
onLoad(() => {
if (!checkLogin()) return;
});
// 问题类型选项
const feedbackTypes = [
{ label: "功能异常", value: "bug" },
@@ -138,51 +138,31 @@ const handleDelete = (detail: { index: number }) => {
// 提交反馈
const handleSubmit = async () => {
// 表单验证
try {
const { valid } = await formRef.value.validate();
const { valid } = await formRef.value.validate();
if (valid) {
submitting.value = true;
try {
// TODO: 调用提交反馈的接口
await new Promise((resolve) => setTimeout(resolve, 1500)); // 模拟提交
toast.success("提交成功");
if (valid) {
submitting.value = true;
try {
// TODO: 调用提交反馈的接口
await new Promise((resolve) => setTimeout(resolve, 1500)); // 模拟提交
toast.success("提交成功");
// 重置表单
formRef.value.reset();
formData.feedbackType = "bug";
formData.description = "";
formData.fileList = [];
formData.contact = "";
// 重置表单
formRef.value.reset();
formData.feedbackType = "bug";
formData.description = "";
formData.fileList = [];
formData.contact = "";
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack();
}, 1500);
} catch (_error) {
toast.error("提交失败,请重试");
} finally {
submitting.value = false;
}
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack();
}, 1500);
} finally {
submitting.value = false;
}
} catch (_error) {
// 表单验证失败
console.log("表单验证失败");
}
};
// 返回
const handleBack = () => {
uni.navigateBack();
};
</script>
<style lang="scss" scoped>
:deep(.wd-form-item) {
margin-bottom: 12rpx;
}
.submit-btn {
margin: 40rpx 30rpx;
}
</style>
<style lang="scss" scoped></style>

View File

@@ -13,7 +13,9 @@
</view>
<view class="user-details">
<block v-if="isLogin">
<view class="nickname">{{ userInfo!.nickname || "匿名用户" }}</view>
<view class="nickname">
{{ userInfo!.nickname || "匿名用户" }}
</view>
<view class="user-id">ID: {{ userInfo?.username || "0000000" }}</view>
</block>
<block v-else>
@@ -41,56 +43,55 @@
</view>
<!-- 数据统计 -->
<view class="stats-container">
<view class="stat-item" @click="navigateToSection('wallet')">
<view class="stat-value">0.00</view>
<view class="">我的余额</view>
<view class="stats-card">
<view class="stats-item" @click="navigateToSection('wallet')">
<view class="mb-8rpx text-36rpx font-600">0.00</view>
<view class="text-26rpx text-gray-500">我的余额</view>
</view>
<view class="divider"></view>
<view class="stat-item" @click="navigateToSection('favorites')">
<view class="stat-value">0</view>
<view class="stat-label">我的收藏</view>
<view class="stats-divider"></view>
<view class="stats-item" @click="navigateToSection('favorites')">
<view class="mb-8rpx text-36rpx font-600">0</view>
<view class="text-26rpx text-gray-500">我的收藏</view>
</view>
<view class="divider"></view>
<view class="stat-item" @click="navigateToSection('history')">
<view class="stat-value">0</view>
<view class="stat-label">浏览历史</view>
<view class="stats-divider"></view>
<view class="stats-item" @click="navigateToSection('history')">
<view class="mb-8rpx text-36rpx font-600">0</view>
<view class="text-26rpx text-gray-500">浏览历史</view>
</view>
</view>
<!-- 常用工具 -->
<view class="card-container">
<view class="card-header">
<view class="card-title">
<view class="flex-start">
<wd-icon name="tools" size="18" :color="currentThemeColor" />
<text>常用工具</text>
<text class="ml-12rpx text-28rpx font-600">常用工具</text>
</view>
</view>
<view class="tools-grid">
<view class="flex flex-wrap p-20rpx pt-20rpx pb-10rpx">
<view class="tool-item" @click="navigateToProfile">
<view class="tool-icon">
<wd-icon name="user" size="24" :color="currentThemeColor" />
</view>
<view class="tool-label">个人资料</view>
<view class="text-24rpx">个人资料</view>
</view>
<view class="tool-item" @click="navigateToFAQ">
<view class="tool-icon">
<wd-icon name="help-circle" size="24" :color="currentThemeColor" />
</view>
<view class="tool-label">常见问题</view>
<view class="text-24rpx">常见问题</view>
</view>
<view class="tool-item" @click="handleQuestionFeedback">
<view class="tool-icon">
<wd-icon name="check-circle" size="24" :color="currentThemeColor" />
</view>
<view class="tool-label">问题反馈</view>
<view class="text-24rpx">问题反馈</view>
</view>
<view class="tool-item" @click="navigateToAbout">
<view class="tool-icon">
<wd-icon name="info-circle" size="24" :color="currentThemeColor" />
</view>
<view class="tool-label">关于我们</view>
<view class="text-24rpx">关于我们</view>
</view>
</view>
</view>
@@ -98,44 +99,47 @@
<!-- 推荐服务 -->
<view class="card-container">
<view class="card-header">
<view class="card-title">
<view class="flex-start">
<wd-icon name="star" size="18" :color="currentThemeColor" />
<text>推荐服务</text>
<text class="ml-12rpx text-28rpx font-600">推荐服务</text>
</view>
</view>
<view class="services-list">
<view>
<view class="service-item" @click="navigateToSection('services', 'vip')">
<view class="service-left">
<view class="flex-start">
<view class="service-icon">
<wd-icon name="dong" size="22" :color="currentThemeColor" />
</view>
<view class="service-info">
<view class="service-name">会员中心</view>
<view class="service-desc">解锁更多特权</view>
<view>
<view class="text-28rpx font-500">会员中心</view>
<view class="mt-8rpx text-24rpx text-gray-500">解锁更多特权</view>
</view>
</view>
<wd-icon name="arrow-right" size="14" />
</view>
<view class="service-item" @click="navigateToSection('services', 'coupon')">
<view class="service-left">
<view class="flex-start">
<view class="service-icon">
<wd-icon name="discount" size="22" :color="currentThemeColor" />
</view>
<view class="service-info">
<view class="service-name">优惠券</view>
<view class="service-desc">查看我的优惠券</view>
<view>
<view class="text-28rpx font-500">优惠券</view>
<view class="mt-8rpx text-24rpx text-gray-500">查看我的优惠券</view>
</view>
</view>
<wd-icon name="arrow-right" size="14" />
</view>
<view class="service-item" @click="navigateToSection('services', 'invite')">
<view class="service-left">
<view
class="service-item service-item-last"
@click="navigateToSection('services', 'invite')"
>
<view class="flex-start">
<view class="service-icon">
<wd-icon name="share" size="22" :color="currentThemeColor" />
</view>
<view class="service-info">
<view class="service-name">邀请有礼</view>
<view class="service-desc">邀请好友得奖励</view>
<view>
<view class="text-28rpx font-500">邀请有礼</view>
<view class="mt-8rpx text-24rpx text-gray-500">邀请好友得奖励</view>
</view>
</view>
<wd-icon name="arrow-right" size="14" />
@@ -144,14 +148,8 @@
</view>
<!-- 退出登录按钮 -->
<view v-if="isLogin" class="logout-btn-wrap">
<wd-button
class="w-full h-80rpx rounded-40rpx font-bold text-32rpx"
plain
@click="handleLogout"
>
退出登录
</wd-button>
<view v-if="isLogin" class="p-30rpx">
<wd-button custom-class="logout-button" plain @click="handleLogout">退出登录</wd-button>
</view>
<wd-toast />
@@ -161,6 +159,7 @@
<script lang="ts" setup>
import { useToast } from "wot-design-uni";
import { useUserStore, useThemeStore } from "@/store";
import { useRouter } from "uni-mini-router";
const toast = useToast();
const userStore = useUserStore();
@@ -170,15 +169,14 @@ const userInfo = computed(() => userStore.userInfo);
const isLogin = computed(() => !!userInfo.value);
const defaultAvatar = "/static/images/default-avatar.png";
const router = useRouter();
// 登录
const navigateToLoginPage = () => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentPagePath = `/${currentPage.route}`;
uni.navigateTo({
url: `/pages/login/index?redirect=${encodeURIComponent(currentPagePath)}`,
});
router.push({ path: "/pages/login/index", query: { redirect: currentPagePath } });
};
// 退出登录
@@ -201,27 +199,27 @@ const navigateToProfile = () => {
navigateToLoginPage();
return;
}
uni.navigateTo({ url: "/pages/mine/profile/index" });
router.push({ path: "/pages/mine/profile/index" });
};
// 常见问题
const navigateToFAQ = () => {
uni.navigateTo({ url: "/pages/mine/faq/index" });
router.push({ path: "/pages/mine/faq/index" });
};
// 关于我们
const navigateToAbout = () => {
uni.navigateTo({ url: "/pages/mine/about/index" });
router.push({ path: "/pages/mine/about/index" });
};
// 设置
const navigateToSettings = () => {
uni.navigateTo({ url: "/pages/mine/settings/index" });
router.push({ path: "/pages/mine/settings/index" });
};
// 问题反馈
const handleQuestionFeedback = () => {
uni.navigateTo({ url: "/pages/mine/feedback/index" });
router.push({ path: "/pages/mine/feedback/index" });
};
// 导航到各个板块
@@ -233,18 +231,6 @@ const navigateToSection = (section: string, subSection?: string) => {
icon: "none",
});
};
onShow(() => {
// 确保 tabbar 状态正确
const pages = getCurrentPages();
if (pages.length > 0) {
const currentPage = pages[pages.length - 1];
if (currentPage.route === "pages/mine/index") {
// 通过事件通知 tabbar 布局更新状态
uni.$emit("updateTabbar", "mine");
}
}
});
</script>
<route lang="json">
@@ -269,7 +255,7 @@ onShow(() => {
left: 0;
z-index: 0;
height: 240rpx;
background: linear-gradient(to bottom, var(--wot-color-theme), var(--primary-color-light));
background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #667eea 100%);
}
.user-info {
@@ -349,213 +335,152 @@ onShow(() => {
}
}
// 数据统计
.stats-container {
display: flex;
padding: 30rpx 20rpx;
margin: 20rpx 30rpx;
background: var(--wot-color-bg-container);
border-radius: 16rpx;
box-shadow: var(--wot-card-shadow);
.stat-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
.stat-value {
margin-bottom: 8rpx;
font-size: 36rpx;
font-weight: 600;
color: var(--wot-color-text);
}
.stat-label {
font-size: 26rpx;
color: var(--wot-color-text-secondary);
}
}
.divider {
width: 1px;
margin: 0 20rpx;
background-color: var(--wot-color-border);
}
}
// 卡片容器通用样式
// 卡片容器
.card-container {
margin: 24rpx 30rpx;
overflow: hidden;
background: var(--wot-color-bg-container);
background-color: #fff;
border-radius: 16rpx;
box-shadow: var(--wot-card-shadow);
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid var(--wot-color-border);
.card-title {
display: flex;
align-items: center;
text {
margin-left: 12rpx;
font-size: 28rpx;
font-weight: 600;
color: var(--wot-color-text);
}
}
.card-action {
display: flex;
align-items: center;
text {
margin-right: 8rpx;
font-size: 24rpx;
color: #999;
}
}
}
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
}
// 订单状态
.order-status {
// 卡片头部
.card-header {
display: flex;
padding: 30rpx 0 20rpx;
.status-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
.status-icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
margin-bottom: 12rpx;
.status-badge {
position: absolute;
top: -10rpx;
right: -10rpx;
z-index: 2;
min-width: 32rpx;
height: 32rpx;
padding: 0 6rpx;
font-size: 20rpx;
line-height: 32rpx;
color: #fff;
text-align: center;
background-color: #ff4d4f;
border-radius: 16rpx;
}
}
.status-label {
font-size: 24rpx;
color: #666;
}
}
align-items: center;
justify-content: space-between;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid #e5e7eb;
}
// 工具网格
.tools-grid {
// 暗色模式下的卡片样式
:deep(.dark) .card-container {
background-color: #1f2937;
}
:deep(.dark) .card-header {
border-bottom-color: #374151;
}
// 工具项
.tool-item {
display: flex;
flex-wrap: wrap;
padding: 20rpx 0 10rpx;
flex-direction: column;
align-items: center;
width: 25%;
margin-bottom: 30rpx;
}
.tool-item {
display: flex;
flex-direction: column;
align-items: center;
width: 25%;
margin-bottom: 30rpx;
// 工具图标
.tool-icon {
display: flex;
align-items: center;
justify-content: center;
width: 90rpx;
height: 90rpx;
margin-bottom: 12rpx;
background-color: #f3f4f6;
border-radius: 18rpx;
transition: transform 0.15s ease;
.tool-icon {
display: flex;
align-items: center;
justify-content: center;
width: 90rpx;
height: 90rpx;
margin-bottom: 12rpx;
background-color: var(--wot-color-bg-light);
border-radius: 18rpx;
transition: transform 0.2s;
&:active {
transform: scale(0.95);
}
}
.tool-label {
font-size: 24rpx;
color: var(--wot-color-text);
}
&:active {
transform: scale(0.95);
}
}
// 服务列表
.services-list {
.service-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
border-bottom: 1rpx solid var(--wot-color-border);
transition: background-color 0.2s;
&:active {
background-color: var(--wot-color-bg-light);
}
&:last-child {
border-bottom: none;
}
.service-left {
display: flex;
align-items: center;
.service-icon {
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
background-color: var(--wot-color-bg-light);
border-radius: 16rpx;
}
.service-info {
.service-name {
font-size: 28rpx;
font-weight: 500;
color: var(--wot-color-text);
}
.service-desc {
margin-top: 8rpx;
font-size: 24rpx;
color: var(--wot-color-text-secondary);
}
}
}
}
// 暗色模式下的工具图标样式
:deep(.dark) .tool-icon {
background-color: #374151;
}
// 退出登录按钮
.logout-btn-wrap {
// 数据统计卡片(减少原子类堆叠)
.stats-card {
display: flex;
align-items: center;
padding: 30rpx;
margin: 20rpx 30rpx;
background-color: #ffffff;
border-radius: 16rpx;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
}
:deep(.dark) .stats-card {
background-color: #1f2937;
}
.stats-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
}
.stats-divider {
width: 1px;
margin: 0 20rpx;
background-color: #e5e7eb;
}
:deep(.dark) .stats-divider {
background-color: #374151;
}
// 服务项
.service-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
border-bottom: 1rpx solid #e5e7eb;
transition: background-color 0.15s ease;
&:active {
background-color: #f3f4f6;
}
&.service-item-last {
border-bottom: none;
}
}
// 暗色模式下的服务项样式
:deep(.dark) .service-item {
border-bottom-color: #374151;
&:active {
background-color: rgba(255, 255, 255, 0.1);
}
}
// 服务图标
.service-icon {
display: flex;
align-items: center;
justify-content: center;
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
background-color: #f3f4f6;
border-radius: 16rpx;
}
// 暗色模式下的服务图标样式
:deep(.dark) .service-icon {
background-color: #374151;
}
// 登录按钮样式
:deep(.btn-login) {
font-size: 24rpx !important;
border-radius: 20rpx !important;
}
// 退出登录按钮样式
:deep(.logout-button) {
width: 100% !important;
height: 80rpx !important;
font-size: 32rpx !important;
font-weight: bold !important;
border-radius: 40rpx !important;
}
</style>

View File

@@ -1,7 +1,5 @@
<template>
<view class="app-container">
<wd-navbar title="完善个人信息" left-arrow @click-left="handleBack" />
<view class="app-container dark:text-[var(--wot-dark-color)]">
<!-- 头部标题 -->
<view class="header">
<view class="title">完善个人信息</view>
@@ -164,7 +162,7 @@ import FileAPI, { type FileInfo } from "@/api/file";
const toast = useToast();
const userStore = useUserStore();
// 页面参数
// 页面参数:使用 query 读取重定向
const redirect = ref("/pages/index/index");
// 表单数据
@@ -356,9 +354,7 @@ const handleComplete = async () => {
// 跳转到目标页面
setTimeout(() => {
uni.reLaunch({
url: redirect.value,
});
uni.reLaunch({ url: redirect.value });
}, 1000);
} catch (error: any) {
console.error("完善信息失败:", error);
@@ -375,18 +371,11 @@ const handleSkip = () => {
content: "跳过信息完善可能会影响部分功能使用,确定要跳过吗?",
success: (res) => {
if (res.confirm) {
uni.reLaunch({
url: redirect.value,
});
uni.reLaunch({ url: redirect.value });
}
},
});
};
// 返回
function handleBack() {
uni.navigateBack();
}
</script>
<style lang="scss" scoped>

View File

@@ -1,7 +1,5 @@
<template>
<view class="app-container">
<wd-navbar title="个人信息" left-arrow @click-left="handleBack" />
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-card v-if="userProfile" custom-style="margin-top: 20rpx">
<wd-cell-group border>
<wd-cell class="avatar-cell" title="头像" center is-link>

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-card>
<wd-cell-group border>
<wd-cell

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-collapse v-model="activeNames" accordion>
<wd-collapse-item
v-for="(section, index) in agreementContent"

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container dark-mode">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-cell-group>
<wd-cell v-if="isLogin" title="个人资料" icon="user" is-link @click="navigateToProfile" />
<wd-cell

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<!-- 网络状态展示 -->
<wd-card>
<wd-cell-group border>

View File

@@ -1,5 +1,5 @@
<template>
<view class="app-container">
<view class="app-container dark:text-[var(--wot-dark-color)]">
<wd-status-tip type="search" tip="建设中..." />
</view>
</template>

View File

@@ -6,7 +6,9 @@ import { createRouter } from "uni-mini-router";
function generateRoutes() {
const routes = pages.map((page: { path: string; [key: string]: any }) => {
const newPath = `/${page.path}`;
return { ...page, path: newPath };
// 透传 meta 字段(如果 pages.json 中定义了)
const meta = page.meta ?? undefined;
return { ...page, path: newPath, meta };
});
// 处理分包路由
@@ -14,7 +16,8 @@ function generateRoutes() {
subPackages.forEach((subPackage: { root: string; pages: any[] }) => {
const subRoutes = subPackage.pages.map((page: any) => {
const newPath = `/${subPackage.root}/${page.path}`;
return { ...page, path: newPath };
const meta = page.meta ?? undefined;
return { ...page, path: newPath, meta };
});
routes.push(...subRoutes);
});
@@ -29,8 +32,10 @@ const router = createRouter({
// 全局前置守卫
router.beforeEach((to, from, next) => {
// 检查页面是否需要登录
if (to.meta && to.meta.requireAuth && !isLoggedIn()) {
const redirectPath = (to.path || "/pages/index/index") as string;
// 先取消本次导航,避免在异步对话框中遗漏 next 导致报错
next(false);
uni.showModal({
title: "提示",
content: "该功能需要登录后使用",
@@ -38,32 +43,20 @@ router.beforeEach((to, from, next) => {
cancelText: "返回",
success: (res) => {
if (res.confirm) {
// 记住原来要去的页面
uni.setStorageSync("redirect", to.fullPath);
// 使用 uni 原生导航而不是 router
uni.navigateTo({
url: "/pages/login/index",
});
} else {
// 取消则返回首页
uni.switchTab({
url: "/pages/index/index",
router.push({
path: "/pages/login/index",
query: { redirect: encodeURIComponent(redirectPath) },
});
}
},
// 确保在取消弹窗时也能调用 next
fail: () => {
next(false);
},
});
} else {
// 继续导航
next();
}
});
router.afterEach((to) => {
console.log("路由跳转完成:", to.path);
router.afterEach((to, from) => {
console.log("🎯 afterEach 钩子触发:", { to, from });
});
export default router;

View File

@@ -7,5 +7,5 @@ body,
}
.app-container {
padding: 0 10rpx;
padding: 10rpx;
}

21
src/types/uni-mini-router.d.ts vendored Normal file
View File

@@ -0,0 +1,21 @@
// 扩展 uni-mini-router 路由类型,支持从 pages.json 注入的 meta 字段
// 该声明文件会被 ts 自动合并到库类型中
import "uni-mini-router";
declare module "uni-mini-router" {
/** 自定义路由元信息类型,可按需扩展 */
interface RouteMeta {
/** 是否需要登录 */
requireAuth?: boolean;
/** 其他自定义字段 */
[key: string]: any;
}
interface Route {
/** 来自 pages.json 的 meta 字段(动态生成时透传) */
meta?: RouteMeta;
}
}
export {};