mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
feat:进度条公共组件
This commit is contained in:
@@ -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: {
|
||||||
{
|
repo_url: props.plugin?.repo_url,
|
||||||
params: {
|
force: props.plugin?.has_update,
|
||||||
repo_url: props.plugin?.repo_url,
|
|
||||||
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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -579,10 +502,10 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.v-card {
|
.v-card {
|
||||||
block-size: 100%;
|
block-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-toolbar{
|
.v-toolbar {
|
||||||
background: rgb(var(--v-table-header-background));
|
background: rgb(var(--v-table-header-background));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,5 +518,4 @@ onMounted(() => {
|
|||||||
block-size: calc(100vh - 17rem);
|
block-size: calc(100vh - 17rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -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,17 +23,29 @@ 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
|
||||||
if (method.toUpperCase() === 'GET') {
|
progressDialog.value = true
|
||||||
await api.get(api_path, {
|
try {
|
||||||
params: params,
|
if (method.toUpperCase() === 'GET') {
|
||||||
})
|
await api.get(api_path, {
|
||||||
} else {
|
params: params,
|
||||||
await api.post(api_path, params)
|
})
|
||||||
|
} else {
|
||||||
|
await api.post(api_path, params)
|
||||||
|
}
|
||||||
|
emit('action')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
}
|
}
|
||||||
emit('action')
|
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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user