feat: 添加系统设置页面,集成应用更新和缓存管理功能,优化用户体验
This commit is contained in:
4
auto-imports.d.ts
vendored
4
auto-imports.d.ts
vendored
@@ -134,6 +134,7 @@ declare global {
|
|||||||
const until: typeof import('@vueuse/core').until
|
const until: typeof import('@vueuse/core').until
|
||||||
const useActiveElement: typeof import('@vueuse/core').useActiveElement
|
const useActiveElement: typeof import('@vueuse/core').useActiveElement
|
||||||
const useAnimate: typeof import('@vueuse/core').useAnimate
|
const useAnimate: typeof import('@vueuse/core').useAnimate
|
||||||
|
const useAppUpdate: typeof import('./src/composables/useAppUpdate').useAppUpdate
|
||||||
const useArrayDifference: typeof import('@vueuse/core').useArrayDifference
|
const useArrayDifference: typeof import('@vueuse/core').useArrayDifference
|
||||||
const useArrayEvery: typeof import('@vueuse/core').useArrayEvery
|
const useArrayEvery: typeof import('@vueuse/core').useArrayEvery
|
||||||
const useArrayFilter: typeof import('@vueuse/core').useArrayFilter
|
const useArrayFilter: typeof import('@vueuse/core').useArrayFilter
|
||||||
@@ -156,6 +157,7 @@ declare global {
|
|||||||
const useBreakpoints: typeof import('@vueuse/core').useBreakpoints
|
const useBreakpoints: typeof import('@vueuse/core').useBreakpoints
|
||||||
const useBroadcastChannel: typeof import('@vueuse/core').useBroadcastChannel
|
const useBroadcastChannel: typeof import('@vueuse/core').useBroadcastChannel
|
||||||
const useBrowserLocation: typeof import('@vueuse/core').useBrowserLocation
|
const useBrowserLocation: typeof import('@vueuse/core').useBrowserLocation
|
||||||
|
const useCacheSize: typeof import('./src/composables/useCacheSize').useCacheSize
|
||||||
const useCached: typeof import('@vueuse/core').useCached
|
const useCached: typeof import('@vueuse/core').useCached
|
||||||
const useClipboard: typeof import('@vueuse/core').useClipboard
|
const useClipboard: typeof import('@vueuse/core').useClipboard
|
||||||
const useClipboardItems: typeof import('@vueuse/core').useClipboardItems
|
const useClipboardItems: typeof import('@vueuse/core').useClipboardItems
|
||||||
@@ -476,6 +478,7 @@ declare module 'vue' {
|
|||||||
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
|
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
|
||||||
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
|
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
|
||||||
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
|
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
|
||||||
|
readonly useAppUpdate: UnwrapRef<typeof import('./src/composables/useAppUpdate')['useAppUpdate']>
|
||||||
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
|
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
|
||||||
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
|
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
|
||||||
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
|
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
|
||||||
@@ -498,6 +501,7 @@ declare module 'vue' {
|
|||||||
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
|
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
|
||||||
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
|
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
|
||||||
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
|
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
|
||||||
|
readonly useCacheSize: UnwrapRef<typeof import('./src/composables/useCacheSize')['useCacheSize']>
|
||||||
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
|
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
|
||||||
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
|
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
|
||||||
readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
|
readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
|
||||||
|
|||||||
2
components.d.ts
vendored
2
components.d.ts
vendored
@@ -40,6 +40,7 @@ declare module 'vue' {
|
|||||||
IonItem: typeof import('@ionic/vue')['IonItem']
|
IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
IonList: typeof import('@ionic/vue')['IonList']
|
IonList: typeof import('@ionic/vue')['IonList']
|
||||||
|
IonListHeader: typeof import('@ionic/vue')['IonListHeader']
|
||||||
IonModal: typeof import('@ionic/vue')['IonModal']
|
IonModal: typeof import('@ionic/vue')['IonModal']
|
||||||
IonNote: typeof import('@ionic/vue')['IonNote']
|
IonNote: typeof import('@ionic/vue')['IonNote']
|
||||||
IonPage: typeof import('@ionic/vue')['IonPage']
|
IonPage: typeof import('@ionic/vue')['IonPage']
|
||||||
@@ -106,6 +107,7 @@ declare global {
|
|||||||
const IonItem: typeof import('@ionic/vue')['IonItem']
|
const IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
const IonList: typeof import('@ionic/vue')['IonList']
|
const IonList: typeof import('@ionic/vue')['IonList']
|
||||||
|
const IonListHeader: typeof import('@ionic/vue')['IonListHeader']
|
||||||
const IonModal: typeof import('@ionic/vue')['IonModal']
|
const IonModal: typeof import('@ionic/vue')['IonModal']
|
||||||
const IonNote: typeof import('@ionic/vue')['IonNote']
|
const IonNote: typeof import('@ionic/vue')['IonNote']
|
||||||
const IonPage: typeof import('@ionic/vue')['IonPage']
|
const IonPage: typeof import('@ionic/vue')['IonPage']
|
||||||
|
|||||||
103
src/composables/useAppUpdate.ts
Normal file
103
src/composables/useAppUpdate.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* 应用更新检查组合式函数
|
||||||
|
*/
|
||||||
|
export function useAppUpdate() {
|
||||||
|
const isChecking = ref(false);
|
||||||
|
const hasUpdate = ref(false);
|
||||||
|
const latestVersion = ref("");
|
||||||
|
const currentVersion = ref("1.0.0"); // 从 package.json 或环境变量读取
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否有新版本
|
||||||
|
*/
|
||||||
|
async function checkForUpdate(): Promise<{
|
||||||
|
hasUpdate: boolean;
|
||||||
|
currentVersion: string;
|
||||||
|
latestVersion?: string;
|
||||||
|
}> {
|
||||||
|
isChecking.value = true;
|
||||||
|
try {
|
||||||
|
// 方案1: 从服务器检查版本(需要后端 API)
|
||||||
|
// const response = await fetch('/api/version');
|
||||||
|
// const { version } = await response.json();
|
||||||
|
// latestVersion.value = version;
|
||||||
|
|
||||||
|
// 方案2: 检查 Service Worker 更新(PWA 应用)
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
const registration = await navigator.serviceWorker.getRegistration();
|
||||||
|
if (registration) {
|
||||||
|
await registration.update();
|
||||||
|
const hasNewWorker = registration.waiting !== null || registration.installing !== null;
|
||||||
|
hasUpdate.value = hasNewWorker;
|
||||||
|
|
||||||
|
if (hasNewWorker) {
|
||||||
|
return {
|
||||||
|
hasUpdate: true,
|
||||||
|
currentVersion: currentVersion.value,
|
||||||
|
latestVersion: "新版本可用",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟检查(实际应用中需要替换为真实的 API 调用)
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
// 暂时返回无更新
|
||||||
|
return {
|
||||||
|
hasUpdate: false,
|
||||||
|
currentVersion: currentVersion.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("检查更新失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isChecking.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用更新(重新加载应用)
|
||||||
|
*/
|
||||||
|
async function applyUpdate(): Promise<void> {
|
||||||
|
if ("serviceWorker" in navigator) {
|
||||||
|
const registration = await navigator.serviceWorker.getRegistration();
|
||||||
|
if (registration?.waiting) {
|
||||||
|
// 通知 Service Worker 跳过等待,立即激活
|
||||||
|
registration.waiting.postMessage({ type: "SKIP_WAITING" });
|
||||||
|
|
||||||
|
// 等待 Service Worker 激活后重新加载页面
|
||||||
|
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有 Service Worker,直接重新加载
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制刷新应用(清除缓存后重新加载)
|
||||||
|
*/
|
||||||
|
async function forceReload(): Promise<void> {
|
||||||
|
if ("caches" in window) {
|
||||||
|
const cacheNames = await caches.keys();
|
||||||
|
await Promise.all(cacheNames.map(name => caches.delete(name)));
|
||||||
|
}
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isChecking,
|
||||||
|
hasUpdate,
|
||||||
|
currentVersion,
|
||||||
|
latestVersion,
|
||||||
|
checkForUpdate,
|
||||||
|
applyUpdate,
|
||||||
|
forceReload,
|
||||||
|
};
|
||||||
|
}
|
||||||
122
src/composables/useCacheSize.ts
Normal file
122
src/composables/useCacheSize.ts
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
* 获取应用缓存大小的组合式函数
|
||||||
|
*/
|
||||||
|
export function useCacheSize() {
|
||||||
|
const cacheSize = ref<string>("计算中...");
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算当前应用使用的缓存大小
|
||||||
|
*/
|
||||||
|
async function calculateCacheSize() {
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
if ("storage" in navigator && "estimate" in navigator.storage) {
|
||||||
|
// 使用 Storage API 获取精确的存储使用量
|
||||||
|
const estimate = await navigator.storage.estimate();
|
||||||
|
const usageInMB = ((estimate.usage || 0) / (1024 * 1024)).toFixed(2);
|
||||||
|
cacheSize.value = `${usageInMB} MB`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 降级方案:计算 localStorage 大小
|
||||||
|
let totalSize = 0;
|
||||||
|
for (const key in localStorage) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(localStorage, key)) {
|
||||||
|
totalSize += localStorage[key].length + key.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sizeInKB = (totalSize / 1024).toFixed(2);
|
||||||
|
cacheSize.value = `${sizeInKB} KB (仅 localStorage)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("计算缓存大小失败:", error);
|
||||||
|
cacheSize.value = "未知";
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存大小的原始字节数
|
||||||
|
*/
|
||||||
|
async function getCacheSizeInBytes(): Promise<number> {
|
||||||
|
try {
|
||||||
|
if ("storage" in navigator && "estimate" in navigator.storage) {
|
||||||
|
const estimate = await navigator.storage.estimate();
|
||||||
|
return estimate.usage || 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let totalSize = 0;
|
||||||
|
for (const key in localStorage) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(localStorage, key)) {
|
||||||
|
totalSize += localStorage[key].length + key.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("获取缓存大小失败:", error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除应用缓存
|
||||||
|
*/
|
||||||
|
async function clearCache(): Promise<void> {
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
// 清除 localStorage
|
||||||
|
localStorage.clear();
|
||||||
|
|
||||||
|
// 清除 sessionStorage
|
||||||
|
sessionStorage.clear();
|
||||||
|
|
||||||
|
// 清除 Cache API 缓存
|
||||||
|
if ("caches" in window) {
|
||||||
|
const cacheNames = await caches.keys();
|
||||||
|
await Promise.all(
|
||||||
|
cacheNames.map(cacheName => caches.delete(cacheName)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除 IndexedDB(如果需要)
|
||||||
|
if ("indexedDB" in window) {
|
||||||
|
const databases = await indexedDB.databases();
|
||||||
|
await Promise.all(
|
||||||
|
databases.map((db) => {
|
||||||
|
if (db.name) {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
const request = indexedDB.deleteDatabase(db.name!);
|
||||||
|
request.onsuccess = () => resolve();
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新计算缓存大小
|
||||||
|
await calculateCacheSize();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("清除缓存失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cacheSize,
|
||||||
|
isLoading,
|
||||||
|
calculateCacheSize,
|
||||||
|
getCacheSizeInBytes,
|
||||||
|
clearCache,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -53,6 +53,10 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
path: "/user/settings",
|
path: "/user/settings",
|
||||||
component: () => import("@/views/user/settings.vue"),
|
component: () => import("@/views/user/settings.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/system-settings",
|
||||||
|
component: () => import("@/views/system-settings/index.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/issue/issuing-apply",
|
path: "/issue/issuing-apply",
|
||||||
props: ({ query, params }) => ({ query, params }),
|
props: ({ query, params }) => ({ query, params }),
|
||||||
|
|||||||
164
src/views/system-settings/index.vue
Normal file
164
src/views/system-settings/index.vue
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { alertController, toastController } from "@ionic/vue";
|
||||||
|
import { checkbox, close, information, languageOutline, refresh } from "ionicons/icons";
|
||||||
|
|
||||||
|
const { cacheSize, calculateCacheSize, clearCache } = useCacheSize();
|
||||||
|
const { isChecking, checkForUpdate } = useAppUpdate();
|
||||||
|
|
||||||
|
function handleClearCache() {
|
||||||
|
clearCache();
|
||||||
|
calculateCacheSize();
|
||||||
|
toastController.create({
|
||||||
|
message: "缓存已清除",
|
||||||
|
duration: 2000,
|
||||||
|
icon: checkbox,
|
||||||
|
position: "bottom",
|
||||||
|
color: "success",
|
||||||
|
}).then(toast => toast.present());
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCheckUpdate() {
|
||||||
|
try {
|
||||||
|
const result = await checkForUpdate();
|
||||||
|
|
||||||
|
if (result.hasUpdate) {
|
||||||
|
const alert = await alertController.create({
|
||||||
|
header: "发现新版本",
|
||||||
|
message: `当前版本: ${result.currentVersion}\n最新版本: ${result.latestVersion || "新版本"}`,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: "取消",
|
||||||
|
role: "cancel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "立即更新",
|
||||||
|
handler: () => {
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const toast = await toastController.create({
|
||||||
|
message: "已是最新版本",
|
||||||
|
duration: 2000,
|
||||||
|
icon: checkbox,
|
||||||
|
position: "bottom",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
await toast.present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
const toast = await toastController.create({
|
||||||
|
message: "检查更新失败",
|
||||||
|
duration: 2000,
|
||||||
|
position: "bottom",
|
||||||
|
color: "danger",
|
||||||
|
});
|
||||||
|
await toast.present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
calculateCacheSize();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar class="ui-toolbar">
|
||||||
|
<ion-back-button slot="start" />
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content :fullscreen="true" class="ion-padding">
|
||||||
|
<ion-list lines="full">
|
||||||
|
<ion-list-header>
|
||||||
|
<ion-label>设置</ion-label>
|
||||||
|
</ion-list-header>
|
||||||
|
<ion-item button>
|
||||||
|
<div class="flex justify-between w-full items-center">
|
||||||
|
<div class="flex-center space-x-2">
|
||||||
|
<div class="icon">
|
||||||
|
<ion-icon :icon="languageOutline" class="text-lg" />
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">
|
||||||
|
语言
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="end">
|
||||||
|
简体中文
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button>
|
||||||
|
<div class="flex justify-between w-full items-center">
|
||||||
|
<div class="flex-center space-x-2">
|
||||||
|
<div class="icon">
|
||||||
|
<ion-icon :icon="information" class="text-lg" />
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">
|
||||||
|
关于我们
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button @click="handleClearCache">
|
||||||
|
<div class="flex justify-between w-full items-center">
|
||||||
|
<div class="flex-center space-x-2">
|
||||||
|
<div class="icon">
|
||||||
|
<ion-icon :icon="close" class="text-lg" />
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">
|
||||||
|
清除缓存
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="end">
|
||||||
|
{{ cacheSize }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button @click="handleCheckUpdate">
|
||||||
|
<div class="flex justify-between w-full items-center">
|
||||||
|
<div class="flex-center space-x-2">
|
||||||
|
<div class="icon">
|
||||||
|
<ion-icon :icon="refresh" class="text-lg" :class="{ 'animate-spin': isChecking }" />
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold">
|
||||||
|
检查更新
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
@reference "tailwindcss";
|
||||||
|
|
||||||
|
ion-item {
|
||||||
|
--padding-start: 0;
|
||||||
|
--padding-end: 0;
|
||||||
|
--padding-top: 6px;
|
||||||
|
--padding-bottom: 6px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.end {
|
||||||
|
@apply text-sm text-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@apply bg-[#1c1c1c] text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@apply rounded-lg p-2 w-7 h-7 flex items-center justify-center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,14 +6,14 @@ const { user } = useAuth();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="user-info-container">
|
<div class="user-info-container">
|
||||||
<div class="user-info">
|
<div class="user-info" @click="$router.push('/user/settings')">
|
||||||
<ui-avatar class="size-18" />
|
<ui-avatar class="size-18" />
|
||||||
<div>
|
<div>
|
||||||
<div class="user-name">
|
<div class="user-name">
|
||||||
{{ user?.email }}
|
{{ user?.email }}
|
||||||
</div>
|
</div>
|
||||||
<div class="user-uid mt-2 text-sm text-text-100">
|
<div class="user-uid mt-1 text-xs text-text-100">
|
||||||
UID: 95223143 <ion-icon :icon="copyOutline" />
|
UID: 95223143
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ async function handleRefresh(event: RefresherCustomEvent) {
|
|||||||
<ion-button fill="clear">
|
<ion-button fill="clear">
|
||||||
<ion-icon slot="icon-only" :icon="notificationsOutline" />
|
<ion-icon slot="icon-only" :icon="notificationsOutline" />
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button fill="clear" router-link="/user/settings">
|
<ion-button fill="clear" router-link="/system-settings">
|
||||||
<ion-icon slot="icon-only" :icon="settingsOutline" />
|
<ion-icon slot="icon-only" :icon="settingsOutline" />
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user