feat: 优化仪表盘界面样式和交互细节
This commit is contained in:
@@ -30,7 +30,7 @@ const RoleAPI = {
|
||||
},
|
||||
/** 获取角色的部门ID集合(自定义数据权限) */
|
||||
getRoleDeptIds(roleId: string) {
|
||||
return request<any, number[]>({ url: `${ROLE_BASE_URL}/${roleId}/dept-ids`, method: "get" });
|
||||
return request<any, string[]>({ url: `${ROLE_BASE_URL}/${roleId}/dept-ids`, method: "get" });
|
||||
},
|
||||
/** 新增角色 */
|
||||
create(data: RoleForm) {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg t="1733620744216" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13366" width="128" height="128"><path d="M512.956 741.549c24.671-8.545 73.221-25.811 120.072-46.486 12.131-5.394 24.087-12.036 47.412-25.31a109.078 109.078 0 0 0 37.94-29.11 83.344 83.344 0 0 0 12.227-23.053V219.281c-0.096-24.831-20.211-44.936-45.045-45.043-9.34 1.573-22.76 4.209-38.757 8.543 24.439 62.406 18.146 132.708-17.021 189.792-34.498 55.993-92.88 92.712-158.098 99.992-1.275 0.137-2.499 0.463-3.776 0.585v223.354c0.11 24.835 20.213 44.934 45.046 45.045zM378.672 741.549c24.833-0.108 44.939-20.21 45.046-45.047V472.779a213.556 213.556 0 0 1-158.787-101.461c-34.357-56.592-40.495-125.929-16.655-187.697a423.782 423.782 0 0 0-42.873-9.482c-24.833 0.098-44.938 20.214-45.047 45.047v398.308a82.748 82.748 0 0 0 12.242 23.039c10.5 12.524 23.704 22.495 38.591 29.219 23.801 13.273 35.756 20.011 47.424 25.311 46.84 20.673 95.405 37.942 120.059 46.486z" fill="#FFBA00" opacity=".4" p-id="13367"></path><path d="M744.827 708.729a57 57 0 0 0 32.919-11.275 53.974 53.974 0 0 0 17.343-27.226V271.907c-0.066-23.054-17.548-42.33-40.493-44.667 0.528 2.635 0.815 5.297 0.855 7.974v398.309a82.915 82.915 0 0 1-12.227 23.037 108.602 108.602 0 0 1-37.941 29.126c-22.944 12.799-34.805 19.428-46.568 24.752 12.528 0.003 49.706 0.761 86.112-1.709zM141.202 227.432c-22.861 2.335-40.317 21.49-40.495 44.475V670.23a53.882 53.882 0 0 0 17.362 27.4 56.9 56.9 0 0 0 32.902 11.291c36.421 2.471 73.585 1.984 86.112 1.711-11.764-5.324-23.61-11.958-46.565-24.751a108.597 108.597 0 0 1-37.928-29.128 82.787 82.787 0 0 1-12.242-23.036V235.404c0.041-2.676 0.327-5.338 0.854-7.972z" fill="#FFBA00" opacity=".4" p-id="13368"></path><path d="M629.782 372.569c35.172-57.083 41.463-127.383 17.023-189.792-0.007-0.026-0.016-0.066-0.029-0.096-51.497 13.939-127.844 45.508-165.674 117.207a189.132 189.132 0 0 0-13.288 31.87v141.388c1.307-0.123 2.569-0.447 3.872-0.585 65.218-7.28 123.598-44 158.096-99.992zM248.658 183.62c-23.842 61.769-17.701 131.105 16.639 187.697 34.357 56.608 93.013 94.084 158.8 101.461h0.099v-141.02a190.385 190.385 0 0 0-13.273-31.87c-36.989-70.079-110.861-101.855-162.265-116.268z" fill="#FEC744" opacity=".4" p-id="13369"></path><path d="M593.104 570.52v223.357c0.105 24.83 20.215 44.938 45.05 45.046 24.668-8.544 73.218-25.811 120.071-46.488 12.127-5.392 24.086-12.036 47.409-25.306a109.116 109.116 0 0 0 37.941-29.114 83.408 83.408 0 0 0 12.225-23.051v-398.31c-0.092-24.833-20.21-44.938-45.045-45.047-9.481 1.602-23.134 4.265-39.446 8.723 24.355 62.297 18.091 132.42-16.915 189.423a213.388 213.388 0 0 1-161.29 100.767zM330.601 271.513c-24.833 0.094-44.939 20.214-45.048 45.045v398.31a82.678 82.678 0 0 0 12.24 23.039c10.502 12.524 23.708 22.493 38.595 29.22 23.799 13.271 35.753 20.013 47.422 25.307 46.841 20.677 95.404 37.944 120.062 46.488 24.831-0.109 44.938-20.216 45.045-45.046v-223.72c-65.791-7.377-124.448-44.86-158.79-101.463-34.354-56.591-40.496-125.93-16.655-187.696a423.057 423.057 0 0 0-42.871-9.484z" fill="#FFBA00" p-id="13370"></path><path d="M868.422 753.937a108.626 108.626 0 0 1-37.943 29.126c-22.944 12.796-34.805 19.428-46.567 24.75 12.526 0 49.702 0.765 86.112-1.71a56.988 56.988 0 0 0 32.916-11.274 54.009 54.009 0 0 0 17.346-27.228v-398.32c-0.069-23.053-17.552-42.328-40.496-44.667 0.529 2.635 0.815 5.299 0.855 7.974v398.31a83.035 83.035 0 0 1-12.223 23.039zM266.399 324.804c-22.863 2.338-40.319 21.491-40.496 44.477v398.323a53.886 53.886 0 0 0 17.361 27.4 56.879 56.879 0 0 0 32.901 11.291c36.419 2.471 73.587 1.983 86.111 1.708-11.764-5.323-23.608-11.953-46.566-24.75a108.578 108.578 0 0 1-37.928-29.124 82.698 82.698 0 0 1-12.238-23.039V332.779c0.039-2.675 0.326-5.338 0.855-7.975z" fill="#FFBA00" p-id="13371"></path><path d="M771.97 280.058c-51.497 13.939-127.844 45.508-165.675 117.207a188.947 188.947 0 0 0-13.289 31.871v141.386c66.797-6.206 126.786-43.472 161.969-100.58 35.184-57.11 41.473-127.45 16.995-189.884z" fill="#FFBA00" p-id="13372"></path><path d="M771.97 280.058c-51.497 13.939-127.844 45.508-165.675 117.207a188.947 188.947 0 0 0-13.289 31.871v141.386c66.797-6.206 126.786-43.472 161.969-100.58 35.184-57.11 41.473-127.45 16.995-189.884z" fill="#FEC744" p-id="13373"></path><path d="M549.294 570.155h0.095V429.132a189.948 189.948 0 0 0-13.271-31.871c-36.992-70.081-110.863-101.856-162.266-116.268-23.839 61.769-17.701 131.105 16.642 187.696 34.352 56.608 93.012 94.089 158.8 101.466z" fill="#FFBA00" p-id="13374"></path><path d="M549.294 570.155h0.095V429.132a189.948 189.948 0 0 0-13.271-31.871c-36.992-70.081-110.863-101.856-162.266-116.268-23.839 61.769-17.701 131.105 16.642 187.696 34.352 56.608 93.012 94.089 158.8 101.466z" fill="#FEC744" p-id="13375"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.6 KiB |
@@ -1 +0,0 @@
|
||||
<svg t="1733620604471" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1596" width="128" height="128"><path d="M604.766 304.391c55.072 0 101.33 31.359 125.567 76.137v-94.054c0-51.505-41.856-91.812-92.513-91.812H250.118c-50.659 0-92.518 40.307-92.518 91.812v423.255c0 49.268 41.859 89.574 92.518 89.574h171.824c-30.848-11.195-48.466-33.586-50.672-71.662-4.402-85.105 48.465-161.231 90.321-197.066 6.608-6.728 11.01-11.194 17.616-15.685-8.813-20.149-15.421-42.548-15.421-67.176 0-78.385 61.679-143.323 140.98-143.323z" fill="#C4F7F0" p-id="1597"></path><path d="M804.423 349.242c0-51.507-41.855-91.814-92.515-91.814H324.204c-50.658 0-92.514 40.308-92.514 91.814v423.254c0 49.268 41.855 89.576 92.514 89.576h171.828c-30.846-11.197-48.466-33.587-50.67-71.668-4.404-85.101 48.462-161.239 90.319-197.063 6.608-6.727 11.009-11.196 17.617-15.682-8.813-20.152-15.422-42.549-15.422-67.182 0-78.384 61.68-143.318 140.977-143.318 55.071 0 101.336 31.356 125.57 76.133v-94.05zM394.702 638.123h-66.081c-6.612 0-11.024-4.474-11.024-11.187 0-6.729 4.413-11.2 11.024-11.2h66.081c6.608 0 11.008 4.471 11.008 11.2 0 6.713-4.4 11.187-11.008 11.187z m66.081-89.572H328.62c-4.417 0-11.025-4.477-11.025-11.199 0-6.707 4.413-11.189 11.025-11.189h132.163c6.609 0 11.01 4.482 11.01 11.189 0.001 6.72-4.401 11.199-11.01 11.199z m0-89.577H328.62c-4.417 0-11.025-4.481-11.025-11.2s6.608-11.198 11.025-11.198h132.163c6.609 0 11.01 4.481 11.01 11.198 0.001 6.719-4.401 11.2-11.01 11.2z" fill="#00DFC1" p-id="1598"></path><path d="M566.516 620.21c-33.043 26.875-72.692 85.096-70.484 152.288 2.193 67.177 72.686 67.177 176.216 67.177 103.535 0 174.03 0 176.228-67.177 2.205-67.192-39.651-123.183-70.485-152.288-24.239-22.396-44.066-26.868-50.672-26.868 28.64-15.683 46.256-47.039 46.256-82.861 0-53.743-41.841-96.294-94.722-96.294-52.863 0-94.707 42.551-92.511 96.294 0 35.822 17.628 64.951 46.253 82.861H621.59c-0.002 0-22.034 0-55.074 26.868z" fill="#00DFC1" p-id="1599"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -31,9 +31,8 @@ function handleClipboard() {
|
||||
() => {
|
||||
ElMessage.success("Copy successfully");
|
||||
},
|
||||
(error) => {
|
||||
() => {
|
||||
ElMessage.warning("Copy failed");
|
||||
console.log("[CopyButton] Copy failed", error);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
@@ -44,18 +43,17 @@ function handleClipboard() {
|
||||
input.setAttribute("value", props.text);
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
let successful = false;
|
||||
try {
|
||||
successful = document.execCommand("copy");
|
||||
const successful = document.execCommand("copy");
|
||||
|
||||
if (successful) {
|
||||
ElMessage.success("Copy successfully!");
|
||||
} else {
|
||||
ElMessage.warning("Copy failed!");
|
||||
}
|
||||
} finally {
|
||||
document.body.removeChild(input);
|
||||
}
|
||||
|
||||
if (successful) {
|
||||
ElMessage.success("Copy successfully!");
|
||||
} else {
|
||||
ElMessage.warning("Copy failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -89,9 +89,9 @@ export const useTagsViewStore = defineStore("tagsView", () => {
|
||||
}
|
||||
|
||||
function updateVisitedView(view: TagView) {
|
||||
for (let v of visitedViews.value) {
|
||||
for (const v of visitedViews.value) {
|
||||
if (v.path === view.path) {
|
||||
v = Object.assign(v, view);
|
||||
Object.assign(v, view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@ $tags-view-height: 34px;
|
||||
:root {
|
||||
// 菜单
|
||||
--menu-background: #fff;
|
||||
--menu-text: #212121;
|
||||
--menu-text: #606266;
|
||||
--menu-active-text: var(--el-menu-active-color);
|
||||
--menu-hover: #e6f4ff;
|
||||
|
||||
// 侧边栏 Logo
|
||||
--sidebar-logo-background: #f5f5f5;
|
||||
--sidebar-logo-text-color: #333;
|
||||
--sidebar-logo-text-color: #303133;
|
||||
}
|
||||
|
||||
// SCSS 变量映射(供组件使用)
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface RoleForm {
|
||||
/** 数据权限(1-所有数据 2-部门及子部门数据 3-本部门数据 4-本人数据 5-自定义部门数据) */
|
||||
dataScope?: number;
|
||||
/** 自定义数据权限部门ID列表(当dataScope=5时有效) */
|
||||
deptIds?: number[];
|
||||
deptIds?: string[];
|
||||
/** 角色状态 */
|
||||
status?: number;
|
||||
/** 备注 */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="dashboard-container">
|
||||
<div class="relative p-6">
|
||||
<!-- github 角标 -->
|
||||
<github-corner class="github-corner" />
|
||||
<github-corner class="absolute top-0 right-0 z-1 border-0" />
|
||||
|
||||
<el-card shadow="never" class="mt-2">
|
||||
<div class="flex flex-wrap">
|
||||
@@ -15,7 +15,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<p>{{ greetings }}</p>
|
||||
<p class="text-base font-semibold text-[--el-text-color-primary] leading-tight">
|
||||
{{ greetings }}
|
||||
</p>
|
||||
<p class="text-sm text-gray">今日天气晴朗,气温在15℃至25℃之间,东南风。</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,34 +123,45 @@
|
||||
<el-row :gutter="10" class="mt-5">
|
||||
<!-- 在线用户数量 -->
|
||||
<el-col :span="8" :xs="24" class="mb-xs-3">
|
||||
<el-card shadow="never" class="h-full flex flex-col">
|
||||
<el-card
|
||||
shadow="never"
|
||||
class="h-full transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex-x-between">
|
||||
<span class="text-gray">在线用户</span>
|
||||
<el-tag type="danger" size="small">实时</el-tag>
|
||||
<span class="text-xs font-medium text-[--el-text-color-secondary]">在线用户</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span
|
||||
class="inline-flex items-center gap-1.5 px-2.5 py-0.5 text-xs leading-5 rounded-full border select-none"
|
||||
:class="wsStatusClass"
|
||||
>
|
||||
<el-icon class="text-sm">
|
||||
<Loading
|
||||
v-if="
|
||||
!isConnected &&
|
||||
(connectionState === 'CONNECTING' || connectionState === 'RECONNECTING')
|
||||
"
|
||||
/>
|
||||
<CircleCheck v-else-if="isConnected" />
|
||||
<CircleClose v-else />
|
||||
</el-icon>
|
||||
<span class="text-[--el-text-color-secondary]">WebSocket</span>
|
||||
<span class="font-medium">{{ wsStatusText }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="flex-x-between mt-2 flex-1">
|
||||
<div class="flex-y-center">
|
||||
<span class="text-lg transition-all duration-300 hover:scale-110">
|
||||
{{ onlineUserCount }}
|
||||
</span>
|
||||
<span v-if="isConnected" class="ml-2 text-xs text-[#67c23a]">
|
||||
<el-icon><Connection /></el-icon>
|
||||
已连接
|
||||
</span>
|
||||
<span v-else class="ml-2 text-xs text-[#f56c6c]">
|
||||
<el-icon><Failed /></el-icon>
|
||||
未连接
|
||||
</span>
|
||||
<div class="mt-2 flex-1 flex items-end">
|
||||
<div class="flex items-baseline gap-1.5">
|
||||
<span class="text-xl font-semibold tracking-wide">{{ onlineUserCount }}</span>
|
||||
<span class="text-xs text-[--el-text-color-secondary]">人</span>
|
||||
</div>
|
||||
<div class="i-svg:people w-8 h-8 animate-[pulse_2s_infinite]" />
|
||||
</div>
|
||||
|
||||
<div class="flex-x-between mt-2 text-sm text-gray">
|
||||
<span>更新时间</span>
|
||||
<span>{{ formattedTime }}</span>
|
||||
<div class="mt-2 flex justify-between items-center">
|
||||
<span class="text-sm text-gray">更新时间</span>
|
||||
<span class="text-sm">{{ formattedTime }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -176,37 +189,45 @@
|
||||
</el-card>
|
||||
</template>
|
||||
<template v-if="!visitStatsLoading">
|
||||
<el-card shadow="never" class="h-full flex flex-col">
|
||||
<el-card
|
||||
shadow="never"
|
||||
class="h-full transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex-x-between">
|
||||
<span class="text-gray">访客数(UV)</span>
|
||||
<span class="text-xs font-medium text-[--el-text-color-secondary]">
|
||||
访客数 UV
|
||||
</span>
|
||||
<el-tag type="success" size="small">日</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="flex-x-between mt-2 flex-1">
|
||||
<div class="flex-y-center">
|
||||
<span class="text-lg">{{ displayTransitionUvCount }}</span>
|
||||
<div class="mt-2 flex-1 flex items-end">
|
||||
<div class="flex items-baseline gap-1.5">
|
||||
<span class="text-xl font-semibold tracking-wide">
|
||||
{{ displayTransitionUvCount }}
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
'text-xs',
|
||||
'ml-2',
|
||||
computeGrowthRateClass(visitStatsData.uvGrowthRate),
|
||||
]"
|
||||
v-if="uvGrowthText !== null"
|
||||
:class="['text-xs', computeGrowthRateClass(visitStatsData.uvGrowthRate)]"
|
||||
>
|
||||
<el-icon>
|
||||
<el-icon
|
||||
v-if="
|
||||
visitStatsData.uvGrowthRate !== undefined &&
|
||||
visitStatsData.uvGrowthRate !== null
|
||||
"
|
||||
>
|
||||
<Top v-if="visitStatsData.uvGrowthRate > 0" />
|
||||
<Bottom v-else-if="visitStatsData.uvGrowthRate < 0" />
|
||||
</el-icon>
|
||||
{{ formatGrowthRate(visitStatsData.uvGrowthRate) }}
|
||||
{{ uvGrowthText }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="i-svg:visitor w-8 h-8" />
|
||||
</div>
|
||||
|
||||
<div class="flex-x-between mt-2 text-sm text-gray">
|
||||
<span>总访客数</span>
|
||||
<span>{{ displayTransitionTotalUvCount }}</span>
|
||||
<div class="mt-2 flex justify-between items-center">
|
||||
<span class="text-sm text-gray">总访客数</span>
|
||||
<span class="text-sm">{{ displayTransitionTotalUvCount }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -236,37 +257,45 @@
|
||||
</el-card>
|
||||
</template>
|
||||
<template v-if="!visitStatsLoading">
|
||||
<el-card shadow="never" class="h-full flex flex-col">
|
||||
<el-card
|
||||
shadow="never"
|
||||
class="h-full transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex-x-between">
|
||||
<span class="text-gray">浏览量(PV)</span>
|
||||
<span class="text-xs font-medium text-[--el-text-color-secondary]">
|
||||
浏览量 PV
|
||||
</span>
|
||||
<el-tag type="primary" size="small">日</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="flex-x-between mt-2 flex-1">
|
||||
<div class="flex-y-center">
|
||||
<span class="text-lg">{{ displayTransitionPvCount }}</span>
|
||||
<div class="mt-2 flex-1 flex items-end">
|
||||
<div class="flex items-baseline gap-1.5">
|
||||
<span class="text-xl font-semibold tracking-wide">
|
||||
{{ displayTransitionPvCount }}
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
'text-xs',
|
||||
'ml-2',
|
||||
computeGrowthRateClass(visitStatsData.pvGrowthRate),
|
||||
]"
|
||||
v-if="pvGrowthText !== null"
|
||||
:class="['text-xs', computeGrowthRateClass(visitStatsData.pvGrowthRate)]"
|
||||
>
|
||||
<el-icon>
|
||||
<el-icon
|
||||
v-if="
|
||||
visitStatsData.pvGrowthRate !== undefined &&
|
||||
visitStatsData.pvGrowthRate !== null
|
||||
"
|
||||
>
|
||||
<Top v-if="visitStatsData.pvGrowthRate > 0" />
|
||||
<Bottom v-else-if="visitStatsData.pvGrowthRate < 0" />
|
||||
</el-icon>
|
||||
{{ formatGrowthRate(visitStatsData.pvGrowthRate) }}
|
||||
{{ pvGrowthText }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="i-svg:browser w-8 h-8" />
|
||||
</div>
|
||||
|
||||
<div class="flex-x-between mt-2 text-sm text-gray">
|
||||
<span>总浏览量</span>
|
||||
<span>{{ displayTransitionTotalPvCount }}</span>
|
||||
<div class="mt-2 flex justify-between items-center">
|
||||
<span class="text-sm text-gray">总浏览量</span>
|
||||
<span class="text-sm">{{ displayTransitionTotalPvCount }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -295,7 +324,7 @@
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="flex-x-between">
|
||||
<span class="header-title">最新动态</span>
|
||||
<span class="font-semibold">最新动态</span>
|
||||
<el-link
|
||||
type="primary"
|
||||
underline="never"
|
||||
@@ -303,7 +332,7 @@
|
||||
target="_blank"
|
||||
>
|
||||
完整记录
|
||||
<el-icon class="link-icon"><TopRight /></el-icon>
|
||||
<el-icon class="ml-0.5"><TopRight /></el-icon>
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
@@ -319,15 +348,23 @@
|
||||
:hollow="index !== 0"
|
||||
size="large"
|
||||
>
|
||||
<div class="version-item" :class="{ 'latest-item': index === 0 }">
|
||||
<div>
|
||||
<div
|
||||
class="p-4 mb-3 bg-[--el-fill-color-lighter] rounded-lg transition-all duration-200 hover:translate-x-1"
|
||||
:class="{
|
||||
'bg-[--el-color-primary-light-9]! border border-[--el-color-primary-light-5]':
|
||||
index === 0,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<el-text tag="strong">{{ item.title }}</el-text>
|
||||
<el-tag v-if="item.tag" :type="index === 0 ? 'success' : 'info'" size="small">
|
||||
{{ item.tag }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<el-text class="version-content">{{ item.content }}</el-text>
|
||||
<el-text class="mb-3 text-xs leading-relaxed text-[--el-text-color-secondary]">
|
||||
{{ item.content }}
|
||||
</el-text>
|
||||
|
||||
<div v-if="item.link">
|
||||
<el-link
|
||||
@@ -337,7 +374,7 @@
|
||||
underline="never"
|
||||
>
|
||||
详情
|
||||
<el-icon class="link-icon"><TopRight /></el-icon>
|
||||
<el-icon class="ml-0.5"><TopRight /></el-icon>
|
||||
</el-link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,21 +400,11 @@ import type { VisitStatsDetail, VisitTrendDetail } from "@/types/api";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { formatGrowthRate } from "@/utils";
|
||||
import { useTransition, useDateFormat } from "@vueuse/core";
|
||||
import { Connection, Failed } from "@element-plus/icons-vue";
|
||||
import { CircleCheck, CircleClose, Loading } from "@element-plus/icons-vue";
|
||||
import { useOnlineCount } from "@/composables";
|
||||
|
||||
// 在线用户数量组件相关
|
||||
const { onlineUserCount, lastUpdateTime, isConnected } = useOnlineCount();
|
||||
|
||||
// 记录上一次的用户数量用于计算趋势
|
||||
const previousCount = ref(0);
|
||||
|
||||
// 监听用户数量变化,计算趋势
|
||||
watch(onlineUserCount, (newCount, oldCount) => {
|
||||
if (oldCount > 0) {
|
||||
previousCount.value = oldCount;
|
||||
}
|
||||
});
|
||||
const { onlineUserCount, lastUpdateTime, isConnected, connectionState } = useOnlineCount();
|
||||
|
||||
// 格式化时间戳
|
||||
const formattedTime = computed(() => {
|
||||
@@ -385,6 +412,23 @@ const formattedTime = computed(() => {
|
||||
return useDateFormat(lastUpdateTime, "HH:mm:ss").value;
|
||||
});
|
||||
|
||||
const wsStatusText = computed(() => {
|
||||
if (!isConnected.value) {
|
||||
return connectionState.value === "CONNECTING" || connectionState.value === "RECONNECTING"
|
||||
? "连接中"
|
||||
: "未连接";
|
||||
}
|
||||
return "已连接";
|
||||
});
|
||||
|
||||
const wsStatusClass = computed(() => {
|
||||
if (isConnected.value)
|
||||
return "text-[--el-color-success] bg-[--el-color-success-light-9] border-[--el-color-success-light-7]";
|
||||
return connectionState.value === "CONNECTING" || connectionState.value === "RECONNECTING"
|
||||
? "text-[--el-color-warning] bg-[--el-color-warning-light-9] border-[--el-color-warning-light-7]"
|
||||
: "text-[--el-color-danger] bg-[--el-color-danger-light-9] border-[--el-color-danger-light-7]";
|
||||
});
|
||||
|
||||
interface VersionItem {
|
||||
id: string;
|
||||
title: string; // 版本标题(如:v2.4.0)
|
||||
@@ -456,6 +500,26 @@ const visitStatsData = ref<VisitStatsDetail>({
|
||||
totalPvCount: 0,
|
||||
});
|
||||
|
||||
const uvGrowthText = computed(() => {
|
||||
if (
|
||||
visitStatsData.value.uvGrowthRate === undefined ||
|
||||
visitStatsData.value.uvGrowthRate === null
|
||||
) {
|
||||
return "--";
|
||||
}
|
||||
return formatGrowthRate(visitStatsData.value.uvGrowthRate);
|
||||
});
|
||||
|
||||
const pvGrowthText = computed(() => {
|
||||
if (
|
||||
visitStatsData.value.pvGrowthRate === undefined ||
|
||||
visitStatsData.value.pvGrowthRate === null
|
||||
) {
|
||||
return "--";
|
||||
}
|
||||
return formatGrowthRate(visitStatsData.value.pvGrowthRate);
|
||||
});
|
||||
|
||||
// 数字过渡动画
|
||||
const transitionUvCount = useTransition(
|
||||
computed(() => visitStatsData.value.todayUvCount),
|
||||
@@ -640,38 +704,5 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-container {
|
||||
position: relative;
|
||||
padding: 24px;
|
||||
|
||||
.github-corner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.version-item {
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
background: var(--el-fill-color-lighter);
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.latest-item {
|
||||
background: var(--el-color-primary-light-9);
|
||||
border: 1px solid var(--el-color-primary-light-5);
|
||||
}
|
||||
&:hover {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
.version-content {
|
||||
margin-bottom: 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 暂无自定义样式
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user