feat:进度条公共组件

This commit is contained in:
jxxghp
2024-04-25 15:07:35 +08:00
parent cdbcef5232
commit 5895cea587
10 changed files with 139 additions and 309 deletions
+20 -66
View File
@@ -6,6 +6,7 @@ import type { Plugin } from '@/api/types'
import noImage from '@images/logos/plugin.png' import noImage from '@images/logos/plugin.png'
import { getDominantColor } from '@/@core/utils/image' import { getDominantColor } from '@/@core/utils/image'
import { isNullOrEmptyObject } from '@/@core/utils' import { isNullOrEmptyObject } from '@/@core/utils'
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
@@ -57,15 +58,12 @@ async function installPlugin() {
progressDialog.value = true progressDialog.value = true
progressText.value = `正在安装 ${props.plugin?.plugin_name} v${props?.plugin?.plugin_version} ...` progressText.value = `正在安装 ${props.plugin?.plugin_name} v${props?.plugin?.plugin_version} ...`
const result: { [key: string]: any } = await api.get( const result: { [key: string]: any } = await api.get(`plugin/install/${props.plugin?.id}`, {
`plugin/install/${props.plugin?.id}`,
{
params: { params: {
repo_url: props.plugin?.repo_url, repo_url: props.plugin?.repo_url,
force: props.plugin?.has_update, force: props.plugin?.has_update,
}, },
}, })
)
// 隐藏等待提示框 // 隐藏等待提示框
progressDialog.value = false progressDialog.value = false
@@ -75,20 +73,17 @@ async function installPlugin() {
// 通知父组件刷新 // 通知父组件刷新
emit('install') emit('install')
} } else {
else {
$toast.error(`插件 ${props.plugin?.plugin_name} 安装失败:${result.message}`) $toast.error(`插件 ${props.plugin?.plugin_name} 安装失败:${result.message}`)
} }
} } catch (error) {
catch (error) {
console.error(error) console.error(error)
} }
} }
// 计算图标路径 // 计算图标路径
const iconPath: Ref<string> = computed(() => { const iconPath: Ref<string> = computed(() => {
if (imageLoadError.value) if (imageLoadError.value) return noImage
return noImage
// 如果是网络图片则使用代理后返回 // 如果是网络图片则使用代理后返回
if (props.plugin?.plugin_icon?.startsWith('http')) if (props.plugin?.plugin_icon?.startsWith('http'))
return `${import.meta.env.VITE_API_BASE_URL}system/img/1?imgurl=${encodeURIComponent(props.plugin?.plugin_icon)}` return `${import.meta.env.VITE_API_BASE_URL}system/img/1?imgurl=${encodeURIComponent(props.plugin?.plugin_icon)}`
@@ -102,22 +97,18 @@ function visitPluginPage() {
let repoUrl = props.plugin?.repo_url let repoUrl = props.plugin?.repo_url
if (repoUrl) { if (repoUrl) {
if (repoUrl.includes('raw.githubusercontent.com')) { if (repoUrl.includes('raw.githubusercontent.com')) {
if (!repoUrl.endsWith('/')) if (!repoUrl.endsWith('/')) repoUrl += '/'
repoUrl += '/'
if (repoUrl.split('/').length < 6) if (repoUrl.split('/').length < 6) repoUrl = `${repoUrl}main/`
repoUrl = `${repoUrl}main/`
try { try {
const [user, repo] = repoUrl.split('/').slice(-4, -2) const [user, repo] = repoUrl.split('/').slice(-4, -2)
repoUrl = `https://github.com/${user}/${repo}` repoUrl = `https://github.com/${user}/${repo}`
} } catch (error) {
catch (error) {
return return
} }
} }
} } else {
else {
repoUrl = props.plugin?.author_url repoUrl = props.plugin?.author_url
} }
window.open(repoUrl, '_blank') window.open(repoUrl, '_blank')
@@ -138,7 +129,8 @@ const dropdownItems = ref([
prependIcon: 'mdi-github', prependIcon: 'mdi-github',
click: visitPluginPage, click: visitPluginPage,
}, },
}, { },
{
title: '更新说明', title: '更新说明',
value: 2, value: 2,
show: !isNullOrEmptyObject(props.plugin?.history || {}), show: !isNullOrEmptyObject(props.plugin?.history || {}),
@@ -151,22 +143,12 @@ const dropdownItems = ref([
</script> </script>
<template> <template>
<VCard <VCard :width="props.width" :height="props.height" @click="installPlugin">
:width="props.width" <div class="relative pa-4 text-center card-cover-blurred" :style="{ background: `${backgroundColor}` }">
:height="props.height"
@click="installPlugin"
>
<div
class="relative pa-4 text-center card-cover-blurred"
:style="{ background: `${backgroundColor}` }"
>
<div class="me-n3 absolute top-0 right-3"> <div class="me-n3 absolute top-0 right-3">
<IconBtn> <IconBtn>
<VIcon icon="mdi-dots-vertical" class="text-white" /> <VIcon icon="mdi-dots-vertical" class="text-white" />
<VMenu <VMenu activator="parent" close-on-content-click>
activator="parent"
close-on-content-click
>
<VList> <VList>
<VListItem <VListItem
v-for="(item, i) in dropdownItems" v-for="(item, i) in dropdownItems"
@@ -184,9 +166,7 @@ const dropdownItems = ref([
</VMenu> </VMenu>
</IconBtn> </IconBtn>
</div> </div>
<VAvatar <VAvatar size="8rem">
size="8rem"
>
<VImg <VImg
ref="imageRef" ref="imageRef"
:src="iconPath" :src="iconPath"
@@ -208,11 +188,7 @@ const dropdownItems = ref([
<VCardText class="flex items-center justify-start pb-2"> <VCardText class="flex items-center justify-start pb-2">
<span> <span>
<VIcon icon="mdi-account" class="me-1" /> <VIcon icon="mdi-account" class="me-1" />
<a <a :href="props.plugin?.author_url" target="_blank" @click.stop>
:href="props.plugin?.author_url"
target="_blank"
@click.stop
>
{{ props.plugin?.plugin_author }} {{ props.plugin?.plugin_author }}
</a> </a>
</span> </span>
@@ -223,31 +199,9 @@ const dropdownItems = ref([
</VCardText> </VCardText>
</VCard> </VCard>
<!-- 安装插件进度框 --> <!-- 安装插件进度框 -->
<VDialog <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
v-model="progressDialog"
:scrim="false"
width="25rem"
>
<VCard
color="primary"
>
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear
indeterminate
color="white"
class="mb-0 mt-1"
/>
</VCardText>
</VCard>
</VDialog>
<!-- 更新日志 --> <!-- 更新日志 -->
<VDialog <VDialog v-if="releaseDialog" v-model="releaseDialog" width="600" scrollable>
v-if="releaseDialog"
v-model="releaseDialog"
width="600"
scrollable
>
<VCard> <VCard>
<DialogCloseBtn @click="releaseDialog = false" /> <DialogCloseBtn @click="releaseDialog = false" />
<VCardTitle>{{ props.plugin?.plugin_name }} 更新说明</VCardTitle> <VCardTitle>{{ props.plugin?.plugin_name }} 更新说明</VCardTitle>
@@ -263,7 +217,7 @@ const dropdownItems = ref([
-webkit-backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
background: rgba(29, 39, 59, 48%); background: rgba(29, 39, 59, 48%);
content: ""; content: '';
inset: 0; inset: 0;
} }
</style> </style>
+3 -9
View File
@@ -12,6 +12,7 @@ import noImage from '@images/logos/plugin.png'
import { getDominantColor } from '@/@core/utils/image' import { getDominantColor } from '@/@core/utils/image'
import store from '@/store' import store from '@/store'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import ProgressDialog from '../dialog/ProgressDialog.vue'
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
@@ -474,15 +475,8 @@ watch(
</VCard> </VCard>
</VDialog> </VDialog>
<!-- 更新插件进度框 --> <!-- 进度框 -->
<VDialog v-model="progressDialog" :scrim="false" width="25rem"> <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
<VCard color="primary">
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear indeterminate color="white" class="mb-0 mt-1" />
</VCardText>
</VCard>
</VDialog>
<!-- 更新日志 --> <!-- 更新日志 -->
<VDialog v-if="releaseDialog" v-model="releaseDialog" width="600" scrollable> <VDialog v-if="releaseDialog" v-model="releaseDialog" width="600" scrollable>
+3 -9
View File
@@ -6,9 +6,9 @@ import SiteTorrentTable from '../table/SiteTorrentTable.vue'
import { requiredValidator } from '@/@validators' import { requiredValidator } from '@/@validators'
import api from '@/api' import api from '@/api'
import type { Site, SiteStatistic } from '@/api/types' import type { Site, SiteStatistic } from '@/api/types'
import ExistIcon from '@core/components/ExistIcon.vue'
import { isNullOrEmptyObject } from '@/@core/utils' import { isNullOrEmptyObject } from '@/@core/utils'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import ProgressDialog from '../dialog/ProgressDialog.vue'
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
@@ -313,14 +313,8 @@ onMounted(() => {
</VCardText> </VCardText>
</VCard> </VCard>
</VDialog> </VDialog>
<VDialog v-model="progressDialog" :scrim="false" width="25rem"> <!-- 进度框 -->
<VCard color="primary"> <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear indeterminate color="white" class="mb-0 mt-1" />
</VCardText>
</VCard>
</VDialog>
</template> </template>
<style lang="scss"> <style lang="scss">
+17
View File
@@ -0,0 +1,17 @@
<script setup lang="ts">
const props = defineProps({
value: Number,
text: String,
})
</script>
<template>
<!-- 手动整理进度框 -->
<VDialog :scrim="false" width="25rem">
<VCard color="primary">
<VCardText class="text-center">
{{ props.text }}
<VProgressLinear color="white" class="mb-0 mt-1" :model-value="props.value" indeterminate />
</VCardText>
</VCard>
</VDialog>
</template>
+2 -8
View File
@@ -5,6 +5,7 @@ import store from '@/store'
import api from '@/api' import api from '@/api'
import { numberValidator } from '@/@validators' import { numberValidator } from '@/@validators'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import ProgressDialog from './ProgressDialog.vue'
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
@@ -262,14 +263,7 @@ async function transfer() {
</VCardActions> </VCardActions>
</VCard> </VCard>
<!-- 手动整理进度框 --> <!-- 手动整理进度框 -->
<VDialog v-model="progressDialog" :scrim="false" width="25rem"> <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" :value="progressValue" />
<VCard color="primary">
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear v-if="progressValue" color="white" class="mb-0 mt-1" :model-value="progressValue" />
</VCardText>
</VCard>
</VDialog>
<!-- TMDB ID搜索框 --> <!-- TMDB ID搜索框 -->
<VDialog v-model="tmdbSelectorDialog" width="40rem" scrollable max-height="85vh"> <VDialog v-model="tmdbSelectorDialog" width="40rem" scrollable max-height="85vh">
<TmdbSelector v-model="transferForm.tmdbid" @close="tmdbSelectorDialog = false" /> <TmdbSelector v-model="transferForm.tmdbid" @close="tmdbSelectorDialog = false" />
@@ -3,6 +3,7 @@ import api from '@/api'
import { Subscribe } from '@/api/types' import { Subscribe } from '@/api/types'
import { formatDateDifference } from '@core/utils/formatters' import { formatDateDifference } from '@core/utils/formatters'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import ProgressDialog from './ProgressDialog.vue'
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
@@ -204,13 +205,6 @@ const dropdownItems = ref([
</VList> </VList>
</VCard> </VCard>
<!-- 进度框 --> <!-- 进度框 -->
<VDialog v-model="progressDialog" :scrim="false" width="25rem"> <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
<VCard color="primary">
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear indeterminate color="white" class="mb-0 mt-1" />
</VCardText>
</VCard>
</VDialog>
</VDialog> </VDialog>
</template> </template>
+48 -126
View File
@@ -10,6 +10,7 @@ import type { Context, EndPoints, FileItem } from '@/api/types'
import store from '@/store' import store from '@/store'
import api from '@/api' import api from '@/api'
import MediaInfoCard from '@/components/cards/MediaInfoCard.vue' import MediaInfoCard from '@/components/cards/MediaInfoCard.vue'
import ProgressDialog from '../dialog/ProgressDialog.vue'
// 输入参数 // 输入参数
const inProps = defineProps({ const inProps = defineProps({
@@ -77,14 +78,10 @@ const nameTestDialog = ref(false)
const defer = (_: number) => true const defer = (_: number) => true
// 目录过滤 // 目录过滤
const dirs = computed(() => const dirs = computed(() => items.value.filter(item => item.type === 'dir' && item.basename.includes(filter.value)))
items.value.filter(item => item.type === 'dir' && item.basename.includes(filter.value)),
)
// 文件过滤 // 文件过滤
const files = computed(() => const files = computed(() => items.value.filter(item => item.type === 'file' && item.basename.includes(filter.value)))
items.value.filter(item => item.type === 'file' && item.basename.includes(filter.value)),
)
// 是否目录 // 是否目录
const isDir = computed(() => inProps.path?.endsWith('/')) const isDir = computed(() => inProps.path?.endsWith('/'))
@@ -113,7 +110,7 @@ async function load() {
method: inProps.endpoints?.list.method || 'get', method: inProps.endpoints?.list.method || 'get',
} }
// 加载数据 // 加载数据
items.value = await axiosInstance.value.request(config) ?? [] items.value = (await axiosInstance.value.request(config)) ?? []
emit('loading', false) emit('loading', false)
loading.value = false loading.value = false
} }
@@ -122,9 +119,7 @@ async function load() {
async function deleteItem(item: FileItem) { async function deleteItem(item: FileItem) {
const confirmed = await createConfirm({ const confirmed = await createConfirm({
title: '确认', title: '确认',
content: `是否确认删除${ content: `是否确认删除${item.type === 'dir' ? '目录' : '文件'} ${item.basename}`,
item.type === 'dir' ? '目录' : '文件'
} ${item.basename}`,
confirmationText: '确认', confirmationText: '确认',
cancellationText: '取消', cancellationText: '取消',
dialogProps: { dialogProps: {
@@ -161,8 +156,7 @@ function changePath(_path: string) {
// 新窗口中下载文件 // 新窗口中下载文件
function download(path: string) { function download(path: string) {
if (!path) if (!path) return
return
const token = store.state.auth.token const token = store.state.auth.token
const url_path = inProps.endpoints?.download.url const url_path = inProps.endpoints?.download.url
.replace(/{storage}/g, storage.value) .replace(/{storage}/g, storage.value)
@@ -174,8 +168,7 @@ function download(path: string) {
// 显示图片 // 显示图片
function getImgLink(path: string) { function getImgLink(path: string) {
if (!path) if (!path) return ''
return ''
const token = store.state.auth.token const token = store.state.auth.token
const url_path = inProps.endpoints?.image.url const url_path = inProps.endpoints?.image.url
.replace(/{storage}/g, storage.value) .replace(/{storage}/g, storage.value)
@@ -261,11 +254,9 @@ async function recognize(path: string) {
}) })
// 关闭进度条 // 关闭进度条
progressDialog.value = false progressDialog.value = false
if (!nameTestResult.value) if (!nameTestResult.value) $toast.error(`${path} 识别失败!`)
$toast.error(`${path} 识别失败!`)
nameTestDialog.value = !!nameTestResult.value?.meta_info?.name nameTestDialog.value = !!nameTestResult.value?.meta_info?.name
} } catch (error) {
catch (error) {
console.error(error) console.error(error)
} }
} }
@@ -283,12 +274,9 @@ async function scrape(path: string) {
}) })
// 关闭进度条 // 关闭进度条
progressDialog.value = false progressDialog.value = false
if (!result.success) if (!result.success) $toast.error(result.message)
$toast.error(result.message) else $toast.success(`${path}削刮完成!`)
else } catch (error) {
$toast.success(`${path}削刮完成!`)
}
catch (error) {
console.error(error) console.error(error)
} }
} }
@@ -303,7 +291,8 @@ const dropdownItems = ref([
recognize(_item.path || '') recognize(_item.path || '')
}, },
}, },
}, { },
{
title: '刮削', title: '刮削',
value: 2, value: 2,
props: { props: {
@@ -312,7 +301,8 @@ const dropdownItems = ref([
scrape(_item.path || '') scrape(_item.path || '')
}, },
}, },
}, { },
{
title: '重命名', title: '重命名',
value: 3, value: 3,
props: { props: {
@@ -361,49 +351,26 @@ onMounted(() => {
/> />
<VSpacer v-if="isFile" /> <VSpacer v-if="isFile" />
<IconBtn v-if="isFile" @click="recognize(inProps.path || '')"> <IconBtn v-if="isFile" @click="recognize(inProps.path || '')">
<VIcon color="primary"> <VIcon color="primary"> mdi-text-recognition </VIcon>
mdi-text-recognition
</VIcon>
</IconBtn> </IconBtn>
<IconBtn v-if="isFile" @click="download(inProps.path || '')"> <IconBtn v-if="isFile" @click="download(inProps.path || '')">
<VIcon color="primary"> <VIcon color="primary"> mdi-download </VIcon>
mdi-download
</VIcon>
</IconBtn> </IconBtn>
<IconBtn v-if="!isFile" @click="load"> <IconBtn v-if="!isFile" @click="load">
<VIcon color="primary"> <VIcon color="primary"> mdi-refresh </VIcon>
mdi-refresh
</VIcon>
</IconBtn> </IconBtn>
</VToolbar> </VToolbar>
<VCardText <VCardText v-if="loading" class="text-center flex flex-col items-center">
v-if="loading" <VProgressCircular size="48" indeterminate color="primary" />
class="text-center flex flex-col items-center"
>
<VProgressCircular
size="48"
indeterminate
color="primary"
/>
</VCardText> </VCardText>
<VCardText <VCardText v-if="!path" class="grow d-flex justify-center align-center grey--text"> 选择目录或文件 </VCardText>
v-if="!path" <VCardText v-else-if="isFile && !isImage" class="text-center break-all">
class="grow d-flex justify-center align-center grey--text" <strong>{{ items[0]?.name }}</strong
> ><br />
选择目录或文件 大小{{ formatBytes(items[0]?.size || 0) }}<br />
</VCardText>
<VCardText
v-else-if="isFile && !isImage"
class="text-center break-all"
>
<strong>{{ items[0]?.name }}</strong><br>
大小{{ formatBytes(items[0]?.size || 0) }}<br>
修改时间{{ formatTime(items[0]?.modify_time || 0) }} 修改时间{{ formatTime(items[0]?.modify_time || 0) }}
</VCardText> </VCardText>
<VCardText <VCardText v-else-if="isFile && isImage" class="grow d-flex justify-center align-center">
v-else-if="isFile && isImage"
class="grow d-flex justify-center align-center"
>
<VImg :src="getImgLink(path)" max-width="100%" max-height="100%" /> <VImg :src="getImgLink(path)" max-width="100%" max-height="100%" />
</VCardText> </VCardText>
<VCardText v-else-if="dirs.length || files.length" class="p-0"> <VCardText v-else-if="dirs.length || files.length" class="p-0">
@@ -412,13 +379,12 @@ onMounted(() => {
<template #default="{ item }"> <template #default="{ item }">
<VHover> <VHover>
<template #default="hover"> <template #default="hover">
<VListItem <VListItem v-bind="hover.props" class="px-3 pe-1" @click="changePath(item.path)">
v-bind="hover.props"
class="px-3 pe-1"
@click="changePath(item.path)"
>
<template #prepend> <template #prepend>
<VIcon v-if="inProps.icons && item.extension" :icon="inProps.icons[item.extension.toLowerCase()] || inProps.icons?.other" /> <VIcon
v-if="inProps.icons && item.extension"
:icon="inProps.icons[item.extension.toLowerCase()] || inProps.icons?.other"
/>
<VIcon v-else icon="mdi-folder-outline" /> <VIcon v-else icon="mdi-folder-outline" />
</template> </template>
<VListItemTitle v-text="item.name" /> <VListItemTitle v-text="item.name" />
@@ -427,13 +393,8 @@ onMounted(() => {
</VListItemSubtitle> </VListItemSubtitle>
<template #append> <template #append>
<IconBtn class="d-sm-none"> <IconBtn class="d-sm-none">
<VIcon <VIcon icon="mdi-dots-vertical" />
icon="mdi-dots-vertical" <VMenu activator="parent" close-on-content-click>
/>
<VMenu
activator="parent"
close-on-content-click
>
<VList> <VList>
<VListItem <VListItem
v-for="(menu, i) in dropdownItems" v-for="(menu, i) in dropdownItems"
@@ -495,42 +456,21 @@ onMounted(() => {
</VVirtualScroll> </VVirtualScroll>
</VList> </VList>
</VCardText> </VCardText>
<VCardText <VCardText v-else-if="filter" class="grow d-flex justify-center align-center grey--text py-5">
v-else-if="filter"
class="grow d-flex justify-center align-center grey--text py-5"
>
没有目录或文件 没有目录或文件
</VCardText> </VCardText>
<VCardText <VCardText v-else-if="!loading" class="grow d-flex justify-center align-center grey--text py-5"> 空目录 </VCardText>
v-else-if="!loading"
class="grow d-flex justify-center align-center grey--text py-5"
>
空目录
</VCardText>
</VCard> </VCard>
<!-- 重命名弹窗 --> <!-- 重命名弹窗 -->
<VDialog <VDialog v-if="renamePopper" v-model="renamePopper" max-width="50rem">
v-if="renamePopper"
v-model="renamePopper"
max-width="50rem"
>
<VCard title="重命名"> <VCard title="重命名">
<VCardText> <VCardText>
<VTextField v-model="newName" label="名称" /> <VTextField v-model="newName" label="名称" />
</VCardText> </VCardText>
<VCardActions> <VCardActions>
<VBtn depressed @click="renamePopper = false"> <VBtn depressed @click="renamePopper = false"> 取消 </VBtn>
取消
</VBtn>
<VSpacer /> <VSpacer />
<VBtn <VBtn :disabled="!newName" depressed variant="tonal" @click="rename"> 重命名 </VBtn>
:disabled="!newName"
depressed
variant="tonal"
@click="rename"
>
重命名
</VBtn>
</VCardActions> </VCardActions>
</VCard> </VCard>
</VDialog> </VDialog>
@@ -539,35 +479,18 @@ onMounted(() => {
v-if="transferPopper" v-if="transferPopper"
v-model="transferPopper" v-model="transferPopper"
:path="currentItem?.path" :path="currentItem?.path"
@done="transferPopper = false; load()" @done="
() => {
transferPopper = false
load()
}
"
@close="transferPopper = false" @close="transferPopper = false"
/> />
<!-- 手动整理进度框 --> <!-- 进度框 -->
<VDialog <ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" :value="progressValue" />
v-model="progressDialog"
:scrim="false"
width="25rem"
>
<VCard
color="primary"
>
<VCardText class="text-center">
{{ progressText }}
<VProgressLinear
v-if="progressValue"
color="white"
class="mb-0 mt-1"
:model-value="progressValue"
/>
</VCardText>
</VCard>
</VDialog>
<!-- 识别结果对话框 --> <!-- 识别结果对话框 -->
<VDialog <VDialog v-if="nameTestDialog" v-model="nameTestDialog" width="50rem">
v-if="nameTestDialog"
v-model="nameTestDialog"
width="50rem"
>
<VCard> <VCard>
<DialogCloseBtn @click="nameTestDialog = false" /> <DialogCloseBtn @click="nameTestDialog = false" />
<VCardItem> <VCardItem>
@@ -595,5 +518,4 @@ onMounted(() => {
block-size: calc(100vh - 17rem); block-size: calc(100vh - 17rem);
} }
} }
</style> </style>
+16 -1
View File
@@ -1,7 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { isNullOrEmptyObject } from '@/@core/utils' import { isNullOrEmptyObject } from '@/@core/utils'
import api from '@/api' import api from '@/api'
import { type PropType, ref } from 'vue' import { type PropType } from 'vue'
import ProgressDialog from '../dialog/ProgressDialog.vue'
// 定议外部事件 // 定议外部事件
const emit = defineEmits(['action']) const emit = defineEmits(['action'])
@@ -22,9 +23,17 @@ const elementProps = defineProps({
config: Object as PropType<RenderProps>, config: Object as PropType<RenderProps>,
}) })
// 进度框
const progressDialog = ref(false)
// 进度框文本
const progressText = ref('正在处理...')
// 元素API事件响应 // 元素API事件响应
async function commonAction(api_path: string, method: string, params = {}) { async function commonAction(api_path: string, method: string, params = {}) {
if (!api_path || !method) return if (!api_path || !method) return
progressDialog.value = true
try {
if (method.toUpperCase() === 'GET') { if (method.toUpperCase() === 'GET') {
await api.get(api_path, { await api.get(api_path, {
params: params, params: params,
@@ -33,6 +42,10 @@ async function commonAction(api_path: string, method: string, params = {}) {
await api.post(api_path, params) await api.post(api_path, params)
} }
emit('action') emit('action')
} catch (error) {
console.error(error)
}
progressDialog.value = false
} }
// 组装事件 // 组装事件
@@ -82,4 +95,6 @@ if (!isNullOrEmptyObject(elementProps.config?.events)) {
v-html="elementProps.config?.html" v-html="elementProps.config?.html"
v-on="componentEvents" v-on="componentEvents"
/> />
<!-- 进度框 -->
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
</template> </template>
+14 -68
View File
@@ -5,6 +5,7 @@ import { useToast } from 'vue-toast-notification'
import router from '@/router' import router from '@/router'
import avatar1 from '@images/avatars/avatar-1.png' import avatar1 from '@images/avatars/avatar-1.png'
import api from '@/api' import api from '@/api'
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
// Vuex Store // Vuex Store
const store = useStore() const store = useStore()
@@ -56,8 +57,7 @@ async function restart() {
$toast.error(result.message) $toast.error(result.message)
return return
} }
} } catch (error) {
catch (error) {
console.error(error) console.error(error)
} }
// 注销 // 注销
@@ -72,53 +72,33 @@ const avatar = store.state.auth.avatar
</script> </script>
<template> <template>
<VAvatar <VAvatar class="cursor-pointer" color="primary" variant="tonal">
class="cursor-pointer"
color="primary"
variant="tonal"
>
<VImg :src="avatar ?? avatar1" /> <VImg :src="avatar ?? avatar1" />
<!-- SECTION Menu --> <!-- SECTION Menu -->
<VMenu <VMenu activator="parent" width="230" location="bottom end" offset="14px">
activator="parent"
width="230"
location="bottom end"
offset="14px"
>
<VList> <VList>
<!-- 👉 User Avatar & Name --> <!-- 👉 User Avatar & Name -->
<VListItem> <VListItem>
<template #prepend> <template #prepend>
<VListItemAction start> <VListItemAction start>
<VAvatar <VAvatar color="primary" variant="tonal">
color="primary"
variant="tonal"
>
<VImg :src="avatar ?? avatar1" /> <VImg :src="avatar ?? avatar1" />
</VAvatar> </VAvatar>
</VListItemAction> </VListItemAction>
</template> </template>
<VListItemTitle class="font-weight-semibold"> <VListItemTitle class="font-weight-semibold">
{{ superUser ? "管理员" : "普通用户" }} {{ superUser ? '管理员' : '普通用户' }}
</VListItemTitle> </VListItemTitle>
<VListItemSubtitle>{{ userName }}</VListItemSubtitle> <VListItemSubtitle>{{ userName }}</VListItemSubtitle>
</VListItem> </VListItem>
<VDivider class="my-2" /> <VDivider class="my-2" />
<!-- 👉 Profile --> <!-- 👉 Profile -->
<VListItem <VListItem v-if="superUser" link to="setting">
v-if="superUser"
link
to="setting"
>
<template #prepend> <template #prepend>
<VIcon <VIcon class="me-2" icon="mdi-account-outline" size="22" />
class="me-2"
icon="mdi-account-outline"
size="22"
/>
</template> </template>
<VListItemTitle>设定</VListItemTitle> <VListItemTitle>设定</VListItemTitle>
@@ -128,32 +108,18 @@ const avatar = store.state.auth.avatar
<VDivider class="my-2" /> <VDivider class="my-2" />
<!-- 👉 restart --> <!-- 👉 restart -->
<VListItem <VListItem v-if="superUser" @click="restart">
v-if="superUser"
@click="restart"
>
<template #prepend> <template #prepend>
<VIcon <VIcon class="me-2" icon="mdi-restart" size="22" />
class="me-2"
icon="mdi-restart"
size="22"
/>
</template> </template>
<VListItemTitle>重启</VListItemTitle> <VListItemTitle>重启</VListItemTitle>
</VListItem> </VListItem>
<!-- 👉 FAQ --> <!-- 👉 FAQ -->
<VListItem <VListItem href="https://github.com/jxxghp/MoviePilot/blob/main/README.md" target="_blank">
href="https://github.com/jxxghp/MoviePilot/blob/main/README.md"
target="_blank"
>
<template #prepend> <template #prepend>
<VIcon <VIcon class="me-2" icon="mdi-help-circle-outline" size="22" />
class="me-2"
icon="mdi-help-circle-outline"
size="22"
/>
</template> </template>
<VListItemTitle>帮助</VListItemTitle> <VListItemTitle>帮助</VListItemTitle>
@@ -162,11 +128,7 @@ const avatar = store.state.auth.avatar
<!-- 👉 Logout --> <!-- 👉 Logout -->
<VListItem @click="logout"> <VListItem @click="logout">
<template #prepend> <template #prepend>
<VIcon <VIcon class="me-2" icon="mdi-logout" size="22" />
class="me-2"
icon="mdi-logout"
size="22"
/>
</template> </template>
<VListItemTitle>注销</VListItemTitle> <VListItemTitle>注销</VListItemTitle>
@@ -176,21 +138,5 @@ const avatar = store.state.auth.avatar
<!-- !SECTION --> <!-- !SECTION -->
</VAvatar> </VAvatar>
<!-- 重启进度框 --> <!-- 重启进度框 -->
<VDialog <ProgressDialog v-if="progressDialog" v-model="progressDialog" text="正在重启 ..." />
v-model="progressDialog"
width="25rem"
>
<VCard
color="primary"
>
<VCardText class="text-center">
正在重启 ...
<VProgressLinear
indeterminate
color="white"
class="mb-0 mt-1"
/>
</VCardText>
</VCard>
</VDialog>
</template> </template>
+2 -2
View File
@@ -382,11 +382,11 @@ onMounted(fetchData)
</template> </template>
<template #item.status="{ item }"> <template #item.status="{ item }">
<VChip v-if="item?.status" color="success" size="small"> 成功 </VChip> <VChip v-if="item?.status" color="success" size="small"> 成功 </VChip>
<v-tooltip v-else :text="item?.errmsg"> <VTooltip v-else :text="item?.errmsg">
<template #activator="{ props }"> <template #activator="{ props }">
<VChip v-bind="props" color="error" size="small"> 失败 </VChip> <VChip v-bind="props" color="error" size="small"> 失败 </VChip>
</template> </template>
</v-tooltip> </VTooltip>
</template> </template>
<template #item.date="{ item }"> <template #item.date="{ item }">
<small>{{ item?.date }}</small> <small>{{ item?.date }}</small>