mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
feat:站点数据展示
This commit is contained in:
@@ -60,19 +60,25 @@ export const prefixWithPlus = (value: number) => (value > 0 ? `+${value}` : valu
|
|||||||
export const formatSeason = (value: string) => (value ? `S${value.padStart(2, '0')}` : '')
|
export const formatSeason = (value: string) => (value ? `S${value.padStart(2, '0')}` : '')
|
||||||
|
|
||||||
// 格式化为xx[TGMK]B
|
// 格式化为xx[TGMK]B
|
||||||
export function formatFileSize(bytes: number, decimals = 2) {
|
export function formatFileSize(bytes: number, decimals = 2, prefix = false) {
|
||||||
if (bytes < 0) throw new Error('字节数不能为负数。')
|
// 负数标记
|
||||||
|
let negative = false
|
||||||
|
let size = bytes
|
||||||
|
if (bytes < 0) {
|
||||||
|
negative = true
|
||||||
|
size = Math.abs(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||||
let size = bytes
|
|
||||||
let unitIndex = 0
|
let unitIndex = 0
|
||||||
|
|
||||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||||
size /= 1024
|
size /= 1024
|
||||||
unitIndex++
|
unitIndex++
|
||||||
}
|
}
|
||||||
|
if (negative) return `-${size.toFixed(decimals)} ${units[unitIndex]}`
|
||||||
return `${size.toFixed(decimals)} ${units[unitIndex]}`
|
else
|
||||||
|
return prefix ? `+${size.toFixed(decimals)} ${units[unitIndex]}` : `${size.toFixed(decimals)} ${units[unitIndex]}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将时间秒格式化为时分秒
|
// 将时间秒格式化为时分秒
|
||||||
|
|||||||
@@ -471,6 +471,10 @@ export interface SiteUserData {
|
|||||||
message_unread_contents?: any[] // 默认为空数组
|
message_unread_contents?: any[] // 默认为空数组
|
||||||
// 错误信息
|
// 错误信息
|
||||||
err_msg?: string | null // 默认为 null
|
err_msg?: string | null // 默认为 null
|
||||||
|
// 更新日期
|
||||||
|
updated_day?: string
|
||||||
|
// 更新时间
|
||||||
|
updated_time?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 正在下载
|
// 正在下载
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { Site, SiteUserData } from '@/api/types'
|
import type { Site, SiteUserData } from '@/api/types'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay, useTheme } from 'vuetify'
|
||||||
|
import { VAvatar, VCardText, VIcon } from 'vuetify/lib/components/index.mjs'
|
||||||
|
import { formatFileSize } from '@/@core/utils/formatters'
|
||||||
|
import VueApexCharts from 'vue3-apexcharts'
|
||||||
|
import { hexToRgb } from '@/@layouts/utils'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
@@ -14,30 +18,360 @@ const props = defineProps({
|
|||||||
// 注册事件
|
// 注册事件
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
const vuetifyTheme = useTheme()
|
||||||
|
|
||||||
|
const currentTheme = controlledComputed(
|
||||||
|
() => vuetifyTheme.name.value,
|
||||||
|
() => vuetifyTheme.current.value.colors,
|
||||||
|
)
|
||||||
|
const variableTheme = controlledComputed(
|
||||||
|
() => vuetifyTheme.name.value,
|
||||||
|
() => vuetifyTheme.current.value.variables,
|
||||||
|
)
|
||||||
|
|
||||||
// 站点数据列表
|
// 站点数据列表
|
||||||
const siteDatas = ref<SiteUserData[]>([])
|
const siteDatas = ref<SiteUserData[]>([])
|
||||||
|
|
||||||
|
// 最新一天的数据,按时间倒序排序后取第一条记录
|
||||||
|
const siteData = computed(() => siteDatas.value[0])
|
||||||
|
|
||||||
|
// 站点数据列表中的上传量、下载量数据生成图形使用的数据
|
||||||
|
const series = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: '上传量',
|
||||||
|
data: siteDatas.value.map(item => Math.round((item.upload ?? 0) / 1024 / 1024 / 1024)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '下载量',
|
||||||
|
data: siteDatas.value.map(item => Math.round((item.download ?? 0) / 1024 / 1024 / 1024)),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 图形选项
|
||||||
|
const chartOptions = controlledComputed(
|
||||||
|
() => vuetifyTheme.name.value,
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
parentHeightOffset: 0,
|
||||||
|
toolbar: { show: false },
|
||||||
|
animations: { enabled: true },
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
enabled: true,
|
||||||
|
tooltip: {
|
||||||
|
x: {
|
||||||
|
format: 'dd/MM/yy HH:mm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: `rgba(${hexToRgb(String(variableTheme.value['border-color']))},${
|
||||||
|
variableTheme.value['border-opacity']
|
||||||
|
})`,
|
||||||
|
strokeDashArray: 6,
|
||||||
|
xaxis: {
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: 'GB',
|
||||||
|
},
|
||||||
|
lines: { show: true },
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
top: -10,
|
||||||
|
left: -7,
|
||||||
|
right: 5,
|
||||||
|
bottom: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
width: 3,
|
||||||
|
lineCap: 'butt',
|
||||||
|
curve: 'smooth',
|
||||||
|
},
|
||||||
|
colors: [currentTheme.value.success, currentTheme.value.warning],
|
||||||
|
markers: {
|
||||||
|
size: 6,
|
||||||
|
offsetY: 4,
|
||||||
|
offsetX: -2,
|
||||||
|
strokeWidth: 3,
|
||||||
|
colors: ['transparent'],
|
||||||
|
strokeColors: 'transparent',
|
||||||
|
discrete: [
|
||||||
|
{
|
||||||
|
size: 5.5,
|
||||||
|
seriesIndex: 0,
|
||||||
|
strokeColor: currentTheme.value.primary,
|
||||||
|
fillColor: currentTheme.value.surface,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hover: { size: 7 },
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
type: 'datetime',
|
||||||
|
categories: siteDatas.value.map(item => `${item.updated_day}T${item.updated_time}.000Z`),
|
||||||
|
labels: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
title: {
|
||||||
|
text: 'GB',
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
formatter: function (val: number) {
|
||||||
|
return val.toLocaleString()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 根据传入属性,计算列表数据中第一条与第二条的差值,如果没有第二条则差值为全部
|
||||||
|
const diffData: { [key: string]: any } = computed(() => {
|
||||||
|
if (siteDatas.value.length < 2) {
|
||||||
|
return siteData.value
|
||||||
|
}
|
||||||
|
const first = siteDatas.value[0]
|
||||||
|
const second = siteDatas.value[1]
|
||||||
|
return {
|
||||||
|
bonus: (first.bonus ?? 0) - (second.bonus ?? 0),
|
||||||
|
ratio: (first.ratio ?? 0) - (second.ratio ?? 0),
|
||||||
|
upload: (first.upload ?? 0) - (second.upload ?? 0),
|
||||||
|
download: (first.download ?? 0) - (second.download ?? 0),
|
||||||
|
seeding: (first.seeding ?? 0) - (second.seeding ?? 0),
|
||||||
|
seeding_size: (first.seeding_size ?? 0) - (second.seeding_size ?? 0),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化差值
|
||||||
|
function getDiffString(diff: number | undefined, format: boolean = true) {
|
||||||
|
if (diff === undefined) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
if (format) {
|
||||||
|
return diff > 0 ? `+${diff.toLocaleString()}` : diff.toLocaleString()
|
||||||
|
}
|
||||||
|
return diff > 0 ? `+${diff}` : diff
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据差值的正负,返回不同的样式
|
||||||
|
function getDiffClass(diff: number | undefined) {
|
||||||
|
if (diff === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (diff == 0) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return diff > 0 ? 'text-success' : 'text-error'
|
||||||
|
}
|
||||||
|
|
||||||
// 查询站点用户数据
|
// 查询站点用户数据
|
||||||
async function fetchSiteUserData() {
|
async function fetchSiteUserData() {
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.get(`site/userdata/${props.site?.id}`)
|
const result: { [key: string]: any } = await api.get(`site/userdata/${props.site?.id}`)
|
||||||
if (result.success) siteDatas.value = result.data
|
if (result.success) {
|
||||||
console.log(result)
|
siteDatas.value = result.data.sort((a: { updated_day: any }, b: { updated_day: any }) =>
|
||||||
|
(b.updated_day || '').localeCompare(a.updated_day || ''),
|
||||||
|
)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onBeforeMount(async () => {
|
||||||
fetchSiteUserData()
|
await fetchSiteUserData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VDialog scrollable eager max-width="50rem" :fullscreen="!display.mdAndUp.value">
|
<VDialog scrollable eager max-width="80rem" :fullscreen="!display.mdAndUp.value">
|
||||||
<VCard :title="`数据 - ${props.site?.name}`" class="rounded-t">
|
<VCard :title="`数据 - ${props.site?.name}`" class="rounded-t">
|
||||||
<DialogCloseBtn @click="emit('close')" />
|
<DialogCloseBtn @click="emit('close')" />
|
||||||
<VCardText> </VCardText>
|
<VCardText>
|
||||||
|
<VRow class="match-height">
|
||||||
|
<!-- 用户信息 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">用户等级</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ siteData?.user_level || '无' }}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-account"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 积分 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">积分</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ siteData?.bonus?.toLocaleString() }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.bonus)">
|
||||||
|
({{ getDiffString(diffData?.bonus) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-scoreboard"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 分享率 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">分享率</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ siteData?.ratio }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.ratio)">
|
||||||
|
({{ getDiffString(diffData?.ratio) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-percent"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 总上传量 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">总上传量</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ formatFileSize(siteData?.upload || 0) }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.upload)">
|
||||||
|
({{ formatFileSize(diffData?.upload || 0, 2, true) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-upload"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 总下载量 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">总下载量</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ formatFileSize(siteData?.download || 0) }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.download)">
|
||||||
|
({{ formatFileSize(diffData?.download || 0, 2, true) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-download"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 总做种数 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">总做种数</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ siteData?.seeding?.toLocaleString() }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.seeding)">
|
||||||
|
({{ getDiffString(diffData?.seeding) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-seed"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 总做种体积 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">总做种体积</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ formatFileSize(siteData?.seeding_size || 0) }}
|
||||||
|
<span class="text-base font-weight-regular" :class="getDiffClass(diffData?.seeding_size)">
|
||||||
|
({{ formatFileSize(diffData?.seeding_size || 0, 2, true) }})
|
||||||
|
</span>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-database"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
<!-- 加入时间 -->
|
||||||
|
<VCol cols="6" md="3">
|
||||||
|
<VCard>
|
||||||
|
<VCardText class="d-flex align-center">
|
||||||
|
<div class="d-flex justify-space-between" style="inline-size: 100%">
|
||||||
|
<div class="d-flex flex-column gap-y-1">
|
||||||
|
<span class="text-base text-high-emphasis">加入时间</span>
|
||||||
|
<h5 class="text-h5 d-flex align-center gap-2">
|
||||||
|
{{ siteData?.join_at?.split(' ')[0] }}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<VAvatar variant="tonal" size="42" rounded>
|
||||||
|
<VIcon icon="mdi-calendar"></VIcon>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
<VRow>
|
||||||
|
<VCol>
|
||||||
|
<VCard title="历史数据">
|
||||||
|
<VCardText>
|
||||||
|
<VueApexCharts type="line" :options="chartOptions" :series="series" :height="300" />
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -218,14 +218,14 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
<input ref="refInputEl" type="file" name="file" accept=".jpeg,.png,.jpg,GIF" hidden @input="changeAvatar" />
|
<input ref="refInputEl" type="file" name="file" accept=".jpeg,.png,.jpg,GIF" hidden @input="changeAvatar" />
|
||||||
|
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="restoreNowAvatar">
|
<VBtn type="reset" color="info" variant="tonal" @click="restoreNowAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-refresh" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">还原当前头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">重置</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-image-sync-outline" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">重置默认头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">默认</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {useToast} from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from 'qrcode.vue'
|
||||||
import {VForm} from 'vuetify/lib/components/index.mjs'
|
import { VForm } from 'vuetify/lib/components/index.mjs'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type {User} from '@/api/types'
|
import type { User } from '@/api/types'
|
||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import {useDisplay} from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import store from "@/store";
|
import store from '@/store'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
@@ -99,7 +99,7 @@ async function loadAccountInfo() {
|
|||||||
if (!accountInfo.value.avatar) {
|
if (!accountInfo.value.avatar) {
|
||||||
accountInfo.value.avatar = avatar1
|
accountInfo.value.avatar = avatar1
|
||||||
}
|
}
|
||||||
nowAvatar.value = accountInfo.value.avatar
|
nowAvatar.value = accountInfo.value.avatar
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -122,11 +122,10 @@ async function saveAccountInfo() {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success('用户信息保存成功!')
|
$toast.success('用户信息保存成功!')
|
||||||
if (oldAvatar !== nowAvatar.value) {
|
if (oldAvatar !== nowAvatar.value) {
|
||||||
// 通知 localStorage 中的用户头像发生变化
|
// 通知 localStorage 中的用户头像发生变化
|
||||||
store.commit('auth/setAvatar', nowAvatar.value)
|
store.commit('auth/setAvatar', nowAvatar.value)
|
||||||
}
|
}
|
||||||
}
|
} else $toast.error(`用户信息保存失败:${result.message}!`)
|
||||||
else $toast.error(`用户信息保存失败:${result.message}!`)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
@@ -204,9 +203,12 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 监听 localStorage 中的用户头像变化
|
// 监听 localStorage 中的用户头像变化
|
||||||
watch(() => store.state.auth.avatar, () => {
|
watch(
|
||||||
nowAvatar.value = store.state.auth.avatar
|
() => store.state.auth.avatar,
|
||||||
})
|
() => {
|
||||||
|
nowAvatar.value = store.state.auth.avatar
|
||||||
|
},
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -235,18 +237,18 @@ watch(() => store.state.auth.avatar, () => {
|
|||||||
@input="changeAvatar"
|
@input="changeAvatar"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="restoreNowAvatar">
|
<VBtn type="reset" color="info" variant="tonal" @click="restoreNowAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-refresh" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">还原当前头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">重置</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
<VBtn type="reset" color="error" variant="tonal" @click="resetDefaultAvatar">
|
||||||
<VIcon icon="mdi-refresh" />
|
<VIcon icon="mdi-image-sync-outline" />
|
||||||
<span v-if="display.mdAndUp.value" class="ms-2">重置默认头像</span>
|
<span v-if="display.mdAndUp.value" class="ms-2">默认</span>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
|
|
||||||
<VBtn
|
<VBtn
|
||||||
:color="accountInfo.is_otp ? 'error' : 'info'"
|
:color="accountInfo.is_otp ? 'warning' : 'success'"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click.stop="accountInfo.is_otp ? disableOtp() : getOtpUri()"
|
@click.stop="accountInfo.is_otp ? disableOtp() : getOtpUri()"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user