refactor: 迁移页面路由配置至 definePage 并重构 tabbar 实现

- 使用 definePage() 替代 <route> 自定义块配置页面路由
- 重构 tabbar 组件,移除 useTabbar 和 uni-mini-router 依赖
- 改用原生 uni.switchTab 实现标签页切换
- 更新相关配置文件和静态资源
This commit is contained in:
Ray.Hao
2026-05-18 17:50:06 +08:00
parent 4465c4d613
commit 819a663081
31 changed files with 281 additions and 416 deletions

View File

@@ -3,21 +3,20 @@
<wd-config-provider :theme-vars="themeVars" :theme="theme === 'dark' ? 'dark' : ''">
<slot />
<wd-tabbar
:model-value="activeTabbar.name"
v-model="active"
bordered
safe-area-inset-bottom
fixed
@change="handleTabbarChange"
>
<wd-tabbar-item
v-for="(item, index) in tabbarList"
:key="index"
:name="item.name"
:value="getTabbarItemValue(item.name)"
:title="item.title"
:icon="item.icon"
/>
</wd-tabbar>
<wd-tabbar-item
v-for="item in tabbarList"
:key="item.name"
:name="item.name"
:title="item.title"
:icon="item.icon"
/>
</wd-tabbar>
<wd-notify />
<wd-toast />
<wd-dialog />
@@ -26,59 +25,53 @@
</template>
<script setup lang="ts">
import { ref, computed, nextTick } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useThemeStore } from "@/store";
import { useTabbar } from "@/composables/useTabbar";
import { useRouter } from "uni-mini-router";
import { storeToRefs } from "pinia";
const router = useRouter();
const themeStore = useThemeStore();
const { themeVars, theme, themeCSSVars } = storeToRefs(themeStore);
const { activeTabbar, getTabbarItemValue, setTabbarItemActive, tabbarList } = useTabbar();
const theme = computed(() => themeStore.theme);
const themeVars = computed(() => themeStore.themeVars);
const themeCSSVars = computed(() => themeStore.themeCSSVars);
/** 页面路径 -> tabbar name 映射(兼容带/不带前缀) */
const ROUTE_TO_TABBAR_NAME: Record<string, string> = {
"/pages/index/index": "home",
"/pages/work/index": "work",
"/pages/mine/index": "mine",
"pages/index/index": "home",
"pages/work/index": "work",
"pages/mine/index": "mine",
};
/** tabbar 配置:name 与页面路径一一对应 */
const tabbarList = [
{ name: "/pages/index/index", title: "首页", icon: "home" },
{ name: "/pages/work/index", title: "工作台", icon: "apps" },
{ name: "/pages/mine/index", title: "我的", icon: "user" },
];
function handleTabbarChange({ value }: { value: string }) {
setTabbarItemActive(value);
router.pushTab({ name: value });
}
/** 当前激活项,用页面路径作为 name初始化时根据当前页面设置 */
const active = ref(tabbarList[0].name);
/** 根据当前页面路径同步 tabbar 激活状态 */
function syncTabbarActive() {
function initActive() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentRoute = (currentPage?.route as string) || "";
if (!currentRoute) return;
const tabName = ROUTE_TO_TABBAR_NAME[currentRoute];
if (tabName && tabName !== activeTabbar.value.name) {
setTabbarItemActive(tabName);
const route = (currentPage?.route as string) || "";
const matched = tabbarList.find((item) => item.name === `/${route}`);
if (matched) {
active.value = matched.name;
}
}
onMounted(() => {
syncTabbarActive();
function handleTabbarChange({ value }: { value: string }) {
active.value = value;
nextTick(() => {
uni.switchTab({ url: value });
});
}
// 小程序 switchTab 时 layout 组件被复用onMounted 不会再次触发
// 使用定时轮询兜底,确保 tabbar 激活状态始终与当前页面一致
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ || MP-KUAISHOU || MP-LARK || MP-XHS || MP-JD
const timer = setInterval(syncTabbarActive, 300);
onUnmounted(() => clearInterval(timer));
// #endif
onMounted(() => {
initActive();
// #ifdef APP-PLUS
uni.hideTabBar();
// #endif
});
onShow(() => {
initActive();
});
</script>
<script lang="ts">

View File

@@ -13,6 +13,7 @@
"animationDuration": 300
},
"pages": [
// GENERATED BY UNI-PAGES, PLATFORM: H5
{
"path": "pages/index/index",
"type": "home",
@@ -222,6 +223,7 @@
"backgroundColor": "@tabBgColor",
"borderStyle": "@tabBorderStyle",
"list": [
// GENERATED BY UNI-PAGES, PLATFORM: H5
{
"pagePath": "pages/index/index"
},

View File

@@ -63,52 +63,52 @@
<!-- 访问趋势图表 -->
<view class="m-24rpx">
<wd-card custom-class="chart-card">
<template #title>
<view class="chart-header">
<text class="chart-header__title">访问趋势</text>
<view class="segment-control">
<view
class="segment-control__item"
:class="{ 'is-active': recentDaysRange === 7 }"
@click="switchRange(7)"
>
近7天
</view>
<view
class="segment-control__item"
:class="{ 'is-active': recentDaysRange === 15 }"
@click="switchRange(15)"
>
近15天
</view>
<view class="chart-wrapper">
<view class="chart-header">
<text class="chart-header__title">访问趋势</text>
<view class="segment-control">
<view
class="segment-control__item"
:class="{ 'is-active': recentDaysRange === 7 }"
@click="switchRange(7)"
>
近7天
</view>
<view
class="segment-control__item"
:class="{ 'is-active': recentDaysRange === 15 }"
@click="switchRange(15)"
>
近15天
</view>
</view>
</template>
<view class="w-full h-600rpx">
</view>
<view class="w-full h-600rpx px-20rpx box-border">
<qiun-data-charts type="area" :chartData="chartData" :opts="chartOpts" />
</view>
</wd-card>
</view>
</view>
</view>
</template>
<script setup lang="ts">
definePage({
name: "home",
style: { navigationStyle: "custom" },
layout: "tabbar",
});
import { computed, ref } from "vue";
import { onReady, onShow } from "@dcloudio/uni-app";
import dayjs from "dayjs";
import { useRouter } from "uni-mini-router";
import { onReady, onShow } from "@dcloudio/uni-app";
import { useUserStore } from "@/store";
import { useNavigation } from "@/composables/useNavigation";
import { menuConfig } from "@/config/menu";
import { isLoggedIn } from "@/utils/auth";
import { hasPermission } from "@/utils/permission";
import LogAPI, { type VisitOverview as ApiVisitOverview, type VisitTrend } from "@/api/log";
import LogAPI, { type VisitOverview, type VisitTrend } from "@/api/log";
import NoticeAPI, { type NoticeItem } from "@/api/notice";
type VisitOverviewVO = ApiVisitOverview;
interface NavItem {
icon: string;
title: string;
@@ -116,28 +116,23 @@ interface NavItem {
perm: string;
}
const router = useRouter();
const userStore = useUserStore();
const { handleNavClick } = useNavigation();
// custom-navbar 组件内部已处理导航栏高度与胶囊避让
const current = ref(0);
const recentDaysRange = ref(7);
const swiperList = ref([
"https://www.youlai.tech/storage/youlai/bg02.png",
"https://www.youlai.tech/storage/blog/banner9.png",
"https://www.youlai.tech/storage/youlai/bg02.png"
]);
const visitOverviewData = ref<VisitOverviewVO>({
/** 访问概览数据 */
const visitOverviewData = ref<VisitOverview>({
todayUvCount: 0,
uvGrowthRate: 0,
totalUvCount: 0,
todayPvCount: 0,
pvGrowthRate: 0,
totalPvCount: 0,
});
} as VisitOverview);
/** 通知公告文本 */
const noticeList = ref<NoticeItem[]>([]);
const noticeText = computed(() => {
const titles = noticeList.value
@@ -147,42 +142,30 @@ const noticeText = computed(() => {
return titles.length ? titles.join(" ") : "暂无通知";
});
// 用户权限列表
const userPerms = computed(() => userStore.userInfo?.perms || []);
// 是否已登录
const isLogged = computed(() => isLoggedIn());
const hasAnyPerm = computed(() => userPerms.value.length > 0);
// 默认菜单(未登录时显示)
/** 默认菜单(未登录时显示) */
const defaultNavList = computed(() => {
const result: { icon: string; title: string; url: string; perm: string }[] = [];
const result: NavItem[] = [];
for (const group of menuConfig) {
for (const item of group.children) {
result.push(item);
if (result.length >= 4) {
return result;
}
if (result.length >= 4) return result;
}
}
return result;
});
// 快捷入口:已登录按权限过滤,未登录显示默认菜单
/** 快捷入口:已登录按权限过滤,未登录显示默认菜单 */
const quickNavList = computed(() => {
if (!isLogged.value || !hasAnyPerm.value) {
return defaultNavList.value;
}
const result: { icon: string; title: string; url: string; perm: string }[] = [];
if (!isLogged.value || !hasAnyPerm.value) return defaultNavList.value;
const result: NavItem[] = [];
for (const group of menuConfig) {
for (const item of group.children) {
if (hasPermission(item.perm)) {
result.push(item);
}
if (result.length >= 4) {
return result;
}
if (hasPermission(item.perm)) result.push(item);
if (result.length >= 4) return result;
}
}
return result;
@@ -191,28 +174,15 @@ const quickNavList = computed(() => {
const chartData = ref({});
const chartOpts = ref({
padding: [20, 0, 20, 0],
xAxis: {
fontSize: 10,
rotateLabel: true,
rotateAngle: 30,
},
yAxis: {
disabled: true,
},
xAxis: { fontSize: 10, rotateLabel: true, rotateAngle: 30 },
yAxis: { disabled: true },
extra: {
area: {
type: "curve",
opacity: 0.2,
addLine: true,
width: 2,
gradient: true,
activeType: "hollow",
},
area: { type: "curve", opacity: 0.2, addLine: true, width: 2, gradient: true, activeType: "hollow" },
},
});
/** 加载通知公告 */
async function loadNoticeData() {
// 未登录时不调用通知接口
if (!isLogged.value) {
noticeList.value = [];
return;
@@ -225,36 +195,30 @@ async function loadNoticeData() {
}
}
async function loadVisitOverviewData() {
try {
visitOverviewData.value = await LogAPI.getVisitOverview();
} catch {
// ignore
}
/** 加载访问概览统计 */
function loadVisitOverviewData() {
LogAPI.getVisitOverview().then((data) => (visitOverviewData.value = data)).catch(() => {});
}
/** 加载访问趋势图表 */
async function loadVisitTrendData() {
const endDate = dayjs().format("YYYY-MM-DD");
const startDate = dayjs()
.subtract(recentDaysRange.value - 1, "day")
.format("YYYY-MM-DD");
const startDate = dayjs().subtract(recentDaysRange.value - 1, "day").format("YYYY-MM-DD");
try {
const data: VisitTrend = await LogAPI.getVisitTrend({ startDate, endDate });
chartData.value = JSON.parse(
JSON.stringify({
categories: (data.dates || []).map((d) => dayjs(d).format("MM-DD")),
series: [
{ name: "访客数", data: data.uvList || [] },
{ name: "浏览量", data: data.pvList || [] },
],
})
);
chartData.value = JSON.parse(JSON.stringify({
categories: (data.dates || []).map((d) => dayjs(d).format("MM-DD")),
series: [
{ name: "访客数", data: data.uvList || [] },
{ name: "浏览量", data: data.pvList || [] },
],
}));
} catch {
chartData.value = { categories: [], series: [] };
}
}
/** 快捷导航点击(未登录跳转登录) */
function handleNavClickWithGuard(item: NavItem) {
if (!isLogged.value || !hasAnyPerm.value) {
uni.navigateTo({ url: "/pages/login/index" });
@@ -263,10 +227,12 @@ function handleNavClickWithGuard(item: NavItem) {
handleNavClick(item);
}
/** 跳转通知公告列表 */
function handleNoticeClick() {
router.push({ path: "/pages/work/notice/index" });
uni.navigateTo({ url: "/pages/work/notice/index" });
}
/** 切换趋势时间范围 */
function switchRange(value: number) {
if (recentDaysRange.value === value) return;
recentDaysRange.value = value;
@@ -279,21 +245,12 @@ onReady(() => {
loadVisitTrendData();
});
// 每次页面显示时刷新数据(登录后跳转回来也能更新)
onShow(() => {
loadVisitOverviewData();
loadVisitTrendData();
});
</script>
<route lang="json">
{
"name": "home",
"style": { "navigationStyle": "custom" },
"layout": "tabbar"
}
</route>
<style lang="scss" scoped>
.hero-fade {
position: absolute;
@@ -311,17 +268,27 @@ onShow(() => {
);
}
:deep(.swiper-box),
:deep(.swiper-box .wd-swiper__item),
:deep(.swiper-box image) {
::deep(.swiper-box),
::deep(.swiper-box .wd-swiper__item),
::deep(.swiper-box image) {
height: 420rpx;
}
.chart-header {
.chart-wrapper {
box-sizing: border-box;
background: var(--color-bg);
border: 1rpx solid var(--color-border);
border-radius: 16rpx;
box-shadow: var(--shadow-sm);
overflow: hidden;
}
.chart-wrapper .chart-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
padding: 24rpx 20rpx;
}
.chart-header__title {

View File

@@ -242,16 +242,15 @@
</view>
</template>
<route lang="json">
{
"name": "login",
"style": { "navigationStyle": "custom", "navigationBarTitleText": "" }
}
</route>
<script lang="ts" setup>
definePage({
name: "login",
style: { navigationStyle: "custom", navigationBarTitleText: "" },
});
import { onLoad, onShow } from "@dcloudio/uni-app";
import { useToast, useDialog } from "@wot-ui/ui";
import { useUserStore } from "@/store/modules/user";
import { useCountdown } from "@/composables/useCountdown";
import AuthAPI from "@/api/auth";

View File

@@ -195,15 +195,13 @@
</view>
</template>
<route lang="json">
{
"name": "mine",
"style": { "navigationStyle": "custom" },
"layout": "tabbar"
}
</route>
<script lang="ts" setup>
definePage({
name: "mine",
style: { navigationStyle: "custom" },
layout: "tabbar",
});
import { computed, ref } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useToast, useDialog } from "@wot-ui/ui";

View File

@@ -21,6 +21,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "official",
style: { navigationBarTitleText: "公众号" },
});
import { onLoad } from "@dcloudio/uni-app";
onLoad(() => {
@@ -28,15 +33,6 @@ onLoad(() => {
});
</script>
<route lang="json">
{
"name": "official",
"style": {
"navigationBarTitleText": "公众号"
}
}
</route>
<style lang="scss" scoped>
.brand {
display: flex;

View File

@@ -20,6 +20,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "theme",
style: { navigationBarTitleText: "用户协议" },
});
const activeNames = ref(["0"]); // 默认展开第一项
const agreementContent = [
@@ -67,15 +72,6 @@ const handleAgree = () => {
};
</script>
<route lang="json">
{
"name": "theme",
"style": {
"navigationBarTitleText": "用户协议"
}
}
</route>
<style lang="scss" scoped>
.agreement__content {
padding: 24rpx 32rpx;

View File

@@ -38,6 +38,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "settings",
style: { navigationBarTitleText: "设置" },
});
import { useUserStore } from "@/store";
import { onLoad } from "@dcloudio/uni-app";
import { useToast } from "@wot-ui/ui";
@@ -176,15 +181,6 @@ onLoad(() => {
});
</script>
<route lang="json">
{
"name": "settings",
"style": {
"navigationBarTitleText": "设置"
}
}
</route>
<style lang="scss" scoped>
.logout-section {
display: flex;

View File

@@ -32,6 +32,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "network",
style: { navigationBarTitleText: "网络测试" },
});
import { onLoad } from "@dcloudio/uni-app";
const result = ref<number | null>(null);
@@ -84,15 +89,6 @@ onLoad(() => {
});
</script>
<route lang="json">
{
"name": "network",
"style": {
"navigationBarTitleText": "网络测试"
}
}
</route>
<style lang="scss" scoped>
.result-card {
background: var(--color-bg);

View File

@@ -20,6 +20,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "privacy",
style: { navigationBarTitleText: "隐私政策" },
});
const activeNames = ref(["0"]); // 默认展开第一项
const privacyContent = [
@@ -82,15 +87,6 @@ const handleAgree = () => {
};
</script>
<route lang="json">
{
"name": "privacy",
"style": {
"navigationBarTitleText": "隐私政策"
}
}
</route>
<style lang="scss" scoped>
.privacy__content {
padding: 24rpx 32rpx;

View File

@@ -110,6 +110,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "theme",
style: { navigationBarTitleText: "主题设置" },
});
import { useTheme } from "@/composables/useTheme";
import { useToast, useDialog } from "@wot-ui/ui";
@@ -225,14 +230,7 @@ onShow(() => {
});
</script>
<route lang="json">
{
"name": "theme",
"style": {
"navigationBarTitleText": "主题设置"
}
}
</route>
<style lang="scss" scoped>
.color-option {

View File

@@ -5,6 +5,11 @@
</template>
<script setup lang="ts">
definePage({
name: "webview",
style: { navigationBarTitleText: "网页" },
});
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
@@ -24,9 +29,4 @@ onLoad((query: any) => {
}
</style>
<route lang="json">
{
"name": "webview",
"style": { "navigationBarTitleText": "网页" }
}
</route>

View File

@@ -91,6 +91,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "config",
style: { navigationBarTitleText: "系统配置" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
@@ -249,11 +254,4 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "config",
"style": {
"navigationBarTitleText": "系统配置"
}
}
</route>

View File

@@ -85,6 +85,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "dept",
style: { navigationBarTitleText: "部门管理" },
});
import { onLoad } from "@dcloudio/uni-app";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
import { useToast, useDialog } from "@wot-ui/ui";
@@ -331,14 +336,7 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "dept",
"style": {
"navigationBarTitleText": "部门管理"
}
}
</route>
<style lang="scss" scoped>
.dept-node {

View File

@@ -89,6 +89,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "dict",
style: { navigationBarTitleText: "字典管理" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { useRouter } from "uni-mini-router";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
@@ -257,11 +262,4 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "dict",
"style": {
"navigationBarTitleText": "字典管理"
}
}
</route>

View File

@@ -97,6 +97,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "dict-item",
style: { navigationBarTitleText: "字典数据" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
@@ -280,11 +285,4 @@ onLoad((query) => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "dict-item",
"style": {
"navigationBarTitleText": "字典数据"
}
}
</route>

View File

@@ -22,6 +22,15 @@
</template>
<script lang="ts" setup>
definePage({
name: "work",
style: {
navigationStyle: "custom",
navigationBarTitleText: "工作台",
},
layout: "tabbar",
});
import { computed } from "vue";
import { useNavbar } from "@/composables/useNavbar";
import { useNavigation } from "@/composables/useNavigation";
@@ -48,13 +57,4 @@ const visibleGridList = computed(() => {
});
</script>
<route lang="json">
{
"name": "work",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "工作台"
},
"layout": "tabbar"
}
</route>

View File

@@ -101,6 +101,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "log",
style: { navigationBarTitleText: "系统日志" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import LogAPI, { type LogPageQuery, LogItem } from "@/api/log";
@@ -168,11 +173,4 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "log",
"style": {
"navigationBarTitleText": "系统日志"
}
}
</route>

View File

@@ -120,6 +120,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "menu",
style: { navigationBarTitleText: "菜单管理" },
});
import { onLoad } from "@dcloudio/uni-app";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
import { useToast, useDialog } from "@wot-ui/ui";
@@ -394,14 +399,7 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "menu",
"style": {
"navigationBarTitleText": "菜单管理"
}
}
</route>
<style lang="scss" scoped>
.menu-node {

View File

@@ -5,6 +5,11 @@
</template>
<script setup lang="ts">
definePage({
name: "monitor",
style: { navigationBarTitleText: "应用监控" },
});
import { ref } from "vue";
// SpringBoot Admin 监控地址
@@ -18,9 +23,4 @@ const monitorUrl = ref("http://localhost:9090/wallboard");
}
</style>
<route lang="json">
{
"name": "monitor",
"style": { "navigationBarTitleText": "应用监控" }
}
</route>

View File

@@ -155,6 +155,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "notice",
style: { navigationBarTitleText: "通知公告" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
@@ -403,14 +408,7 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "notice",
"style": {
"navigationBarTitleText": "通知公告"
}
}
</route>
<style lang="scss" scoped>
.notice-card__main {

View File

@@ -76,8 +76,12 @@
</template>
<script lang="ts" setup>
definePage({
name: "role-assign-perm",
style: { navigationBarTitleText: "分配权限" },
});
import { onLoad } from "@dcloudio/uni-app";
import { useToast } from "@wot-ui/ui";
import MenuAPI, { type MenuItem } from "@/api/menu";
import RoleAPI from "@/api/role";
import CustomTree from "@/components/custom-tree/index.vue";
@@ -284,11 +288,4 @@ export default { options: { styleIsolation: "shared" } };
}
</style>
<route lang="json">
{
"name": "role-assign-perm",
"style": {
"navigationBarTitleText": "分配权限"
}
}
</route>

View File

@@ -109,6 +109,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "role",
style: { navigationBarTitleText: "角色管理" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
@@ -289,14 +294,7 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "role",
"style": {
"navigationBarTitleText": "角色管理"
}
}
</route>
<style lang="scss" scoped>
.role-card__main {

View File

@@ -199,6 +199,11 @@
</template>
<script lang="ts" setup>
definePage({
name: "user",
style: { navigationBarTitleText: "用户管理" },
});
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import { LoadMoreState } from "@wot-ui/ui/components/wd-loadmore/types";
import { FormRules } from "@wot-ui/ui/components/wd-form/types";
@@ -522,14 +527,7 @@ onLoad(() => {
export default { options: { styleIsolation: "shared" } };
</script>
<route lang="json">
{
"name": "user",
"style": {
"navigationBarTitleText": "用户管理"
}
}
</route>
<style lang="scss" scoped>
.user-card__avatar {

View File

@@ -1 +1,8 @@
<svg t="1773314000001" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#409EFF" p-id="10001"></path><path d="M324.408781 655.018925C505.290126 655.018925 651.918244 508.387706 651.918244 327.509463c0-152.138029-103.733293-280.047334-244.329811-316.853972C205.813923 52.463528 47.497011 213.017581 8.987325 415.981977 47.587706 553.880127 174.183098 655.018925 324.408781 655.018925z" fill="#FFFFFF" fill-opacity=".2" p-id="10002"></path><path d="M512 1024c282.766631 0 512-229.233369 512-512 0-31.765705-2.891385-62.853911-8.433853-93.018889C928.057169 336.0999 809.874701 285.26268 679.824375 285.26268c-269.711213 0-488.357305 218.645317-488.357305 488.357305 0 54.959576 9.084221 107.802937 25.822474 157.10377C300.626556 989.489417 402.283167 1024 512 1024z" fill="#FFFFFF" fill-opacity=".15" p-id="10003"></path><path d="M732.535958 756.566238c36.389596 0 65.889478-29.499882 65.889477-65.889478 0 36.389596 29.502983 65.889478 65.889478 65.889478-17.053747 0-65.889478 29.502983-65.889478 65.889477 0-36.386495-29.499882-65.889478-65.889477-65.889477zM159.685087 247.279334c25.686819 0 46.51022-20.8234 46.51022-46.51022 0 25.686819 20.8234 46.51022 46.510219 46.51022-12.03607 0-46.51022 20.8234-46.510219 46.510219 0-25.686819-20.8234-46.51022-46.51022-46.510219z" fill="#FFFFFF" fill-opacity=".5" p-id="10004"></path><path d="M206.195307 333.32324c8.562531 0 15.503407-6.940875 15.503406-15.503407 0 8.562531 6.940875 15.503407 15.503407 15.503407-4.012282 0-15.503407 6.940875-15.503407 15.503406 0-8.562531-6.940875-15.503407-15.503406-15.503406z" fill="#FFFFFF" fill-opacity=".3" p-id="10005"></path><text x="512" y="600" text-anchor="middle" font-size="380" font-weight="bold" fill="#FFFFFF" font-family="monospace">&lt;/&gt;</text></svg>
<svg t="1773314000001" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#409EFF" p-id="10001"></path>
<path d="M324.408781 655.018925C505.290126 655.018925 651.918244 508.387706 651.918244 327.509463c0-152.138029-103.733293-280.047334-244.329811-316.853972C205.813923 52.463528 47.497011 213.017581 8.987325 415.981977 47.587706 553.880127 174.183098 655.018925 324.408781 655.018925z" fill="#FFFFFF" fill-opacity=".2" p-id="10002"></path>
<path d="M512 1024c282.766631 0 512-229.233369 512-512 0-31.765705-2.891385-62.853911-8.433853-93.018889C928.057169 336.0999 809.874701 285.26268 679.824375 285.26268c-269.711213 0-488.357305 218.645317-488.357305 488.357305 0 54.959576 9.084221 107.802937 25.822474 157.10377C300.626556 989.489417 402.283167 1024 512 1024z" fill="#FFFFFF" fill-opacity=".15" p-id="10003"></path>
<path d="M732.535958 756.566238c36.389596 0 65.889478-29.499882 65.889477-65.889478 0 36.389596 29.502983 65.889478 65.889478 65.889478-17.053747 0-65.889478 29.502983-65.889478 65.889477 0-36.386495-29.499882-65.889478-65.889477-65.889477zM159.685087 247.279334c25.686819 0 46.51022-20.8234 46.51022-46.51022 0 25.686819 20.8234 46.51022 46.510219 46.51022-12.03607 0-46.51022 20.8234-46.510219 46.510219 0-25.686819-20.8234-46.51022-46.51022-46.510219z" fill="#FFFFFF" fill-opacity=".5" p-id="10004"></path>
<path d="M206.195307 333.32324c8.562531 0 15.503407-6.940875 15.503406-15.503407 0 8.562531 6.940875 15.503407 15.503407 15.503407-4.012282 0-15.503407 6.940875-15.503407 15.503406 0-8.562531-6.940875-15.503407-15.503406-15.503406z" fill="#FFFFFF" fill-opacity=".3" p-id="10005"></path>
<text x="512" y="512" text-anchor="middle" dominant-baseline="central" font-size="380" font-weight="900" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="18" stroke-linejoin="round" font-family="monospace">&lt;/&gt;</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,63 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="360" viewBox="0 0 1200 360" preserveAspectRatio="xMidYMid slice">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#7CB6FF"/>
<stop offset="0.55" stop-color="#C9D4FF"/>
<stop offset="1" stop-color="#FFD1E8"/>
</linearGradient>
<radialGradient id="glowA" cx="30%" cy="35%" r="60%">
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.65"/>
<stop offset="0.55" stop-color="#FFFFFF" stop-opacity="0.10"/>
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0"/>
</radialGradient>
<radialGradient id="glowB" cx="78%" cy="28%" r="65%">
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.40"/>
<stop offset="0.6" stop-color="#FFFFFF" stop-opacity="0.06"/>
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0"/>
</radialGradient>
<filter id="blur" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="14"/>
</filter>
</defs>
<rect width="1200" height="360" fill="url(#g)"/>
<path d="M -40 280 C 220 180, 520 210, 820 160 C 980 132, 1110 120, 1260 140" fill="none" stroke="#FFFFFF" stroke-opacity="0.18" stroke-width="3"/>
<path d="M -60 310 C 220 230, 520 252, 820 208 C 1020 180, 1140 176, 1280 186" fill="none" stroke="#FFFFFF" stroke-opacity="0.10" stroke-width="2"/>
<circle cx="320" cy="120" r="180" fill="url(#glowA)" filter="url(#blur)"/>
<circle cx="900" cy="90" r="200" fill="url(#glowB)" filter="url(#blur)"/>
<g fill="#FFFFFF" opacity="0.75">
<circle cx="86" cy="74" r="1.4"/>
<circle cx="124" cy="132" r="1.1"/>
<circle cx="182" cy="66" r="1.2"/>
<circle cx="210" cy="156" r="1.0"/>
<circle cx="268" cy="110" r="1.2"/>
<circle cx="312" cy="74" r="1.0"/>
<circle cx="356" cy="148" r="1.3"/>
<circle cx="418" cy="98" r="1.1"/>
<circle cx="472" cy="66" r="1.4"/>
<circle cx="512" cy="128" r="1.0"/>
<circle cx="562" cy="90" r="1.2"/>
<circle cx="612" cy="56" r="1.0"/>
<circle cx="652" cy="120" r="1.4"/>
<circle cx="702" cy="92" r="1.1"/>
<circle cx="742" cy="60" r="1.2"/>
<circle cx="786" cy="138" r="1.0"/>
<circle cx="826" cy="86" r="1.3"/>
<circle cx="872" cy="54" r="1.1"/>
<circle cx="922" cy="132" r="1.4"/>
<circle cx="972" cy="92" r="1.0"/>
<circle cx="1016" cy="58" r="1.2"/>
<circle cx="1062" cy="110" r="1.3"/>
<circle cx="1112" cy="72" r="1.1"/>
</g>
<g fill="#FFFFFF" opacity="0.28">
<circle cx="160" cy="210" r="2.4"/>
<circle cx="520" cy="240" r="2.0"/>
<circle cx="880" cy="220" r="2.2"/>
<circle cx="1040" cy="250" r="1.8"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/static/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -2,6 +2,7 @@ import { defineStore } from "pinia";
import { Storage } from "@/utils/storage";
import { THEME_MODE_KEY, THEME_COLOR_KEY } from "@/constants";
import type { ThemeColorOption, ThemeMode } from "@/composables/types/theme";
import type { ConfigProviderThemeVars } from "@wot-ui/ui";
import { themeColorOptions } from "@/composables/types/theme";
/**
@@ -73,12 +74,12 @@ export const useThemeStore = defineStore("theme", () => {
};
/** 主题变量(计算属性,根据模式动态切换) */
const themeVars = computed(() => {
const themeVars = computed<ConfigProviderThemeVars>(() => {
const base = { colorTheme: currentThemeColor.value.primary };
if (theme.value === "dark") {
return { ...base, ...darkThemeVars };
return { ...base, ...darkThemeVars } as ConfigProviderThemeVars;
}
return base;
return base as ConfigProviderThemeVars;
});
// ==========================================================================