mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-25 01:59:35 +08:00
feat:订阅和插件支持手动排序
This commit is contained in:
@@ -115,7 +115,7 @@ function changeTheme(theme: string) {
|
|||||||
// 保存主题到服务端
|
// 保存主题到服务端
|
||||||
try {
|
try {
|
||||||
api.post('/user/config/Layout', {
|
api.post('/user/config/Layout', {
|
||||||
theme: nextTheme
|
theme: nextTheme,
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('保存主题到服务端失败')
|
console.error('保存主题到服务端失败')
|
||||||
@@ -176,7 +176,7 @@ async function saveCustomCSS() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.success) $toast.success('自定义CSS保存成功!')
|
if (result.success) $toast.success('自定义CSS保存成功,请刷新页面生效!')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('保存自定义 CSS 到服务端失败')
|
console.error('保存自定义 CSS 到服务端失败')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,28 +149,8 @@ const dropdownItems = ref([
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VCard :width="props.width" :height="props.height" @click="installPlugin" class="flex flex-col">
|
<div>
|
||||||
<div class="me-n3 absolute bottom-0 right-3">
|
<VCard :width="props.width" :height="props.height" @click="installPlugin" class="flex flex-col h-full">
|
||||||
<IconBtn>
|
|
||||||
<VIcon icon="mdi-dots-vertical" />
|
|
||||||
<VMenu activator="parent" close-on-content-click>
|
|
||||||
<VList>
|
|
||||||
<VListItem
|
|
||||||
v-for="(item, i) in dropdownItems"
|
|
||||||
v-show="item.show"
|
|
||||||
:key="i"
|
|
||||||
variant="plain"
|
|
||||||
@click="item.props.click"
|
|
||||||
>
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon :icon="item.props.prependIcon" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle v-text="item.title" />
|
|
||||||
</VListItem>
|
|
||||||
</VList>
|
|
||||||
</VMenu>
|
|
||||||
</IconBtn>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-row items-start pa-3 justify-between grow"
|
class="relative flex flex-row items-start pa-3 justify-between grow"
|
||||||
:style="{ background: `${backgroundColor}` }"
|
:style="{ background: `${backgroundColor}` }"
|
||||||
@@ -213,6 +193,27 @@ const dropdownItems = ref([
|
|||||||
<VIcon icon="mdi-download" />
|
<VIcon icon="mdi-download" />
|
||||||
<span class="text-sm ms-1 mt-1">{{ props.count?.toLocaleString() }}</span>
|
<span class="text-sm ms-1 mt-1">{{ props.count?.toLocaleString() }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
<div class="me-n3 absolute bottom-1 right-3">
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon icon="mdi-dots-vertical" />
|
||||||
|
<VMenu activator="parent" close-on-content-click>
|
||||||
|
<VList>
|
||||||
|
<VListItem
|
||||||
|
v-for="(item, i) in dropdownItems"
|
||||||
|
v-show="item.show"
|
||||||
|
:key="i"
|
||||||
|
variant="plain"
|
||||||
|
@click="item.props.click"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon :icon="item.props.prependIcon" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle v-text="item.title" />
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<!-- 安装插件进度框 -->
|
<!-- 安装插件进度框 -->
|
||||||
@@ -225,4 +226,5 @@ const dropdownItems = ref([
|
|||||||
<VersionHistory :history="props.plugin?.history" />
|
<VersionHistory :history="props.plugin?.history" />
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -390,30 +390,18 @@ watch(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<!-- 插件卡片 -->
|
<!-- 插件卡片 -->
|
||||||
<VCard v-if="isVisible" :width="props.width" :height="props.height" @click="openPluginDetail" class="flex flex-col">
|
<VHover>
|
||||||
<div class="me-n3 absolute bottom-0 right-3">
|
<template #default="hover">
|
||||||
<IconBtn>
|
<VCard
|
||||||
<VIcon icon="mdi-dots-vertical" />
|
v-if="isVisible"
|
||||||
<VMenu activator="parent" close-on-content-click>
|
v-bind="hover.props"
|
||||||
<VList>
|
:width="props.width"
|
||||||
<VListItem
|
:height="props.height"
|
||||||
v-for="(item, i) in dropdownItems"
|
@click="openPluginDetail"
|
||||||
v-show="item.show"
|
class="flex flex-col h-full"
|
||||||
:key="i"
|
|
||||||
variant="plain"
|
|
||||||
:base-color="item.props.color"
|
|
||||||
@click="item.props.click"
|
|
||||||
>
|
>
|
||||||
<template #prepend>
|
|
||||||
<VIcon :icon="item.props.prependIcon" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle v-text="item.title" />
|
|
||||||
</VListItem>
|
|
||||||
</VList>
|
|
||||||
</VMenu>
|
|
||||||
</IconBtn>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-row items-start pa-3 justify-between grow"
|
class="relative flex flex-row items-start pa-3 justify-between grow"
|
||||||
:style="{ background: `${backgroundColor}` }"
|
:style="{ background: `${backgroundColor}` }"
|
||||||
@@ -459,11 +447,38 @@ watch(
|
|||||||
<VIcon icon="mdi-download" />
|
<VIcon icon="mdi-download" />
|
||||||
<span class="text-sm ms-1 mt-1">{{ props.count?.toLocaleString() }}</span>
|
<span class="text-sm ms-1 mt-1">{{ props.count?.toLocaleString() }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
<div class="me-n3 absolute bottom-1 right-3">
|
||||||
|
<IconBtn>
|
||||||
|
<VIcon icon="mdi-dots-vertical" />
|
||||||
|
<VMenu activator="parent" close-on-content-click>
|
||||||
|
<VList>
|
||||||
|
<VListItem
|
||||||
|
v-for="(item, i) in dropdownItems"
|
||||||
|
v-show="item.show"
|
||||||
|
:key="i"
|
||||||
|
variant="plain"
|
||||||
|
:base-color="item.props.color"
|
||||||
|
@click="item.props.click"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon :icon="item.props.prependIcon" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle v-text="item.title" />
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VMenu>
|
||||||
|
</IconBtn>
|
||||||
|
</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<div v-if="props.plugin?.has_update" class="me-n3 absolute top-0 right-5">
|
<div v-if="hover.isHovering" class="me-n3 absolute top-0 right-5">
|
||||||
|
<VIcon class="cursor-move text-white">mdi-drag</VIcon>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="props.plugin?.has_update" class="me-n3 absolute top-0 right-5">
|
||||||
<VIcon icon="mdi-new-box" class="text-white" />
|
<VIcon icon="mdi-new-box" class="text-white" />
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
</template>
|
||||||
|
</VHover>
|
||||||
|
|
||||||
<!-- 插件配置页面 -->
|
<!-- 插件配置页面 -->
|
||||||
<VDialog v-model="pluginConfigDialog" scrollable max-width="60rem" :fullscreen="!display.mdAndUp.value">
|
<VDialog v-model="pluginConfigDialog" scrollable max-width="60rem" :fullscreen="!display.mdAndUp.value">
|
||||||
@@ -514,6 +529,7 @@ watch(
|
|||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -271,12 +271,13 @@ function onSubscribeEditRemove() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<VHover>
|
<VHover>
|
||||||
<template #default="hover">
|
<template #default="hover">
|
||||||
<VCard
|
<VCard
|
||||||
v-bind="hover.props"
|
v-bind="hover.props"
|
||||||
:key="props.media?.id"
|
:key="props.media?.id"
|
||||||
class="flex flex-col rounded-lg"
|
class="flex flex-col rounded-lg h-full"
|
||||||
:class="{
|
:class="{
|
||||||
'outline-dashed outline-1': props.media?.best_version && imageLoaded,
|
'outline-dashed outline-1': props.media?.best_version && imageLoaded,
|
||||||
'transition transform-cpu duration-300 scale-105 shadow-lg': hover.isHovering,
|
'transition transform-cpu duration-300 scale-105 shadow-lg': hover.isHovering,
|
||||||
@@ -316,10 +317,7 @@ function onSubscribeEditRemove() {
|
|||||||
</template>
|
</template>
|
||||||
<div class="absolute inset-0 subscribe-card-background"></div>
|
<div class="absolute inset-0 subscribe-card-background"></div>
|
||||||
</VImg>
|
</VImg>
|
||||||
<div
|
<div v-if="subscribeState === 'P'" class="absolute inset-0 bg-yellow-900 opacity-80 pointer-events-none" />
|
||||||
v-if="subscribeState === 'P'"
|
|
||||||
class="absolute inset-0 bg-yellow-900 opacity-40 pointer-events-none"
|
|
||||||
></div>
|
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<VCardText class="flex items-center">
|
<VCardText class="flex items-center">
|
||||||
@@ -371,6 +369,9 @@ function onSubscribeEditRemove() {
|
|||||||
color="success"
|
color="success"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="hover.isHovering" class="me-n3 absolute top-1 right-10">
|
||||||
|
<IconBtn><VIcon class="cursor-move text-white">mdi-drag</VIcon></IconBtn>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
</template>
|
</template>
|
||||||
@@ -399,6 +400,7 @@ function onSubscribeEditRemove() {
|
|||||||
:sub="props.media"
|
:sub="props.media"
|
||||||
@close="subscribeShareDialog = false"
|
@close="subscribeShareDialog = false"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.subscribe-card-background {
|
.subscribe-card-background {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Plugin } from '@/api/types'
|
import type { Plugin } from '@/api/types'
|
||||||
@@ -28,6 +29,9 @@ const pluginId = ref(route.query.id)
|
|||||||
// 当前排序字段
|
// 当前排序字段
|
||||||
const activeSort = ref(null)
|
const activeSort = ref(null)
|
||||||
|
|
||||||
|
// 插件顺序配置
|
||||||
|
const orderConfig = ref<{ id: string }[]>([])
|
||||||
|
|
||||||
// 排序选项
|
// 排序选项
|
||||||
const sortOptions = [
|
const sortOptions = [
|
||||||
{ title: '热门', value: 'count' },
|
{ title: '热门', value: 'count' },
|
||||||
@@ -104,6 +108,49 @@ const labelFilterOptions = ref<string[]>([])
|
|||||||
// 插件库过滤项
|
// 插件库过滤项
|
||||||
const repoFilterOptions = ref<string[]>([])
|
const repoFilterOptions = ref<string[]>([])
|
||||||
|
|
||||||
|
// 加载插件顺序
|
||||||
|
async function loadPluginOrderConfig() {
|
||||||
|
// 顺序配置
|
||||||
|
const local_order = localStorage.getItem('MP_PLUGIN_ORDER')
|
||||||
|
if (local_order) {
|
||||||
|
orderConfig.value = JSON.parse(local_order)
|
||||||
|
} else {
|
||||||
|
const response2 = await api.get('/user/config/PluginOrder')
|
||||||
|
if (response2 && response2.data && response2.data.value) {
|
||||||
|
orderConfig.value = response2.data.value
|
||||||
|
localStorage.setItem('MP_PLUGIN_ORDER', JSON.stringify(orderConfig.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 排序
|
||||||
|
if (orderConfig.value) {
|
||||||
|
sortPluginOrder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按order的顺序对插件进行排序
|
||||||
|
function sortPluginOrder() {
|
||||||
|
dataList.value.sort((a, b) => {
|
||||||
|
const aIndex = orderConfig.value.findIndex((item: { id: string }) => item.id === a.id)
|
||||||
|
const bIndex = orderConfig.value.findIndex((item: { id: string }) => item.id === b.id)
|
||||||
|
return (aIndex === -1 ? 999 : aIndex) - (bIndex === -1 ? 999 : bIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存顺序设置
|
||||||
|
async function savePluginOrder() {
|
||||||
|
// 顺序配置
|
||||||
|
const orderObj = dataList.value.map(item => ({ id: item.id }))
|
||||||
|
const orderString = JSON.stringify(orderObj)
|
||||||
|
localStorage.setItem('MP_PLUGIN_ORDER', orderString)
|
||||||
|
|
||||||
|
// 保存到服务端
|
||||||
|
try {
|
||||||
|
await api.post('/user/config/PluginOrder', orderObj)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化过滤选项
|
// 初始化过滤选项
|
||||||
function initOptions(item: Plugin) {
|
function initOptions(item: Plugin) {
|
||||||
const optionValue = (options: Array<string>, value: string | undefined) => {
|
const optionValue = (options: Array<string>, value: string | undefined) => {
|
||||||
@@ -329,8 +376,9 @@ function handleRepoUrl(url: string | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 加载时获取数据
|
// 加载时获取数据
|
||||||
onBeforeMount(async () => {
|
onMounted(async () => {
|
||||||
await refreshData()
|
await refreshData()
|
||||||
|
await loadPluginOrderConfig()
|
||||||
getPluginStatistics()
|
getPluginStatistics()
|
||||||
if (activeTab.value != 'market' && pluginId.value) {
|
if (activeTab.value != 'market' && pluginId.value) {
|
||||||
// 找到这个插件
|
// 找到这个插件
|
||||||
@@ -356,18 +404,26 @@ onBeforeMount(async () => {
|
|||||||
<transition name="fade-slide" appear>
|
<transition name="fade-slide" appear>
|
||||||
<div>
|
<div>
|
||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
<div v-if="dataList.length > 0" class="grid gap-4 grid-plugin-card">
|
<draggable
|
||||||
<template v-for="(data, index) in dataList" :key="`${data.id}_v${data.plugin_version}`">
|
v-if="dataList.length > 0"
|
||||||
|
v-model="dataList"
|
||||||
|
@end="savePluginOrder"
|
||||||
|
handle=".cursor-move"
|
||||||
|
item-key="id"
|
||||||
|
tag="div"
|
||||||
|
:component-data="{ class: 'grid gap-4 grid-plugin-card' }"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
<PluginCard
|
<PluginCard
|
||||||
:count="PluginStatistics[data.id || '0']"
|
:count="PluginStatistics[element.id || '0']"
|
||||||
:plugin="data"
|
:plugin="element"
|
||||||
:action="pluginActions[data.id || '0']"
|
:action="pluginActions[element.id || '0']"
|
||||||
@remove="refreshData"
|
@remove="refreshData"
|
||||||
@save="refreshData"
|
@save="refreshData"
|
||||||
@action-done="pluginActions[data.id || '0'] = false"
|
@action-done="pluginActions[element.id || '0'] = false"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</draggable>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="dataList.length === 0 && isRefreshed"
|
v-if="dataList.length === 0 && isRefreshed"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
import { VPullToRefresh } from 'vuetify/labs/VPullToRefresh'
|
import { VPullToRefresh } from 'vuetify/labs/VPullToRefresh'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Subscribe } from '@/api/types'
|
import type { Subscribe } from '@/api/types'
|
||||||
@@ -31,6 +32,52 @@ const subscribeEditDialog = ref(false)
|
|||||||
// 历史记录弹窗
|
// 历史记录弹窗
|
||||||
const historyDialog = ref(false)
|
const historyDialog = ref(false)
|
||||||
|
|
||||||
|
// 订阅顺序配置
|
||||||
|
const orderConfig = ref<{ id: number }[]>([])
|
||||||
|
|
||||||
|
// 加载顺序
|
||||||
|
async function loadSubscribeOrderConfig() {
|
||||||
|
// 顺序配置
|
||||||
|
const local_order = localStorage.getItem('MP_SUBSCRIBE_ORDER')
|
||||||
|
if (local_order) {
|
||||||
|
orderConfig.value = JSON.parse(local_order)
|
||||||
|
} else {
|
||||||
|
const response2 = await api.get('/user/config/SubscribeOrder')
|
||||||
|
if (response2 && response2.data && response2.data.value) {
|
||||||
|
orderConfig.value = response2.data.value
|
||||||
|
localStorage.setItem('MP_SUBSCRIBE_ORDER', JSON.stringify(orderConfig.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 排序
|
||||||
|
if (orderConfig.value) {
|
||||||
|
sortSubscribeOrder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按order的顺序排序
|
||||||
|
function sortSubscribeOrder() {
|
||||||
|
displayList.value.sort((a, b) => {
|
||||||
|
const aIndex = orderConfig.value.findIndex((item: { id: number }) => item.id === a.id)
|
||||||
|
const bIndex = orderConfig.value.findIndex((item: { id: number }) => item.id === b.id)
|
||||||
|
return (aIndex === -1 ? 999 : aIndex) - (bIndex === -1 ? 999 : bIndex)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存顺序设置
|
||||||
|
async function saveSubscribeOrder() {
|
||||||
|
// 顺序配置
|
||||||
|
const orderObj = displayList.value.map(item => ({ id: item.id }))
|
||||||
|
const orderString = JSON.stringify(orderObj)
|
||||||
|
localStorage.setItem('MP_SUBSCRIBE_ORDER', orderString)
|
||||||
|
|
||||||
|
// 保存到服务端
|
||||||
|
try {
|
||||||
|
await api.post('/user/config/SubscribeOrder', orderObj)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取订阅列表数据
|
// 获取订阅列表数据
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
try {
|
try {
|
||||||
@@ -49,20 +96,28 @@ const loading = ref(false)
|
|||||||
// 下拉刷新
|
// 下拉刷新
|
||||||
async function onRefresh({ done }: { done: any }) {
|
async function onRefresh({ done }: { done: any }) {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
|
await loadSubscribeOrderConfig()
|
||||||
done('ok')
|
done('ok')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过滤数据,管理员用户显示全部,非管理员只显示自己的订阅
|
// 显示的订阅列表
|
||||||
const filteredDataList = computed(() => {
|
const displayList = ref<Subscribe[]>([])
|
||||||
|
|
||||||
|
// 监听dataList变化,同步更新displayList
|
||||||
|
watch(dataList, () => {
|
||||||
// 从Vuex Store中获取用户信息
|
// 从Vuex Store中获取用户信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = store.state.auth.superUser
|
||||||
const userName = store.state.auth.userName
|
const userName = store.state.auth.userName
|
||||||
if (superUser) return dataList.value.filter(data => data.type === props.type)
|
if (superUser) displayList.value = dataList.value.filter(data => data.type === props.type)
|
||||||
else return dataList.value.filter(data => data.type === props.type && data.username === userName)
|
else displayList.value = dataList.value.filter(data => data.type === props.type && data.username === userName)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 过滤数据,管理员用户显示全部,非管理员只显示自己的订阅
|
||||||
|
const filteredDataList = computed(() => {})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
|
await loadSubscribeOrderConfig()
|
||||||
if (props.subid) {
|
if (props.subid) {
|
||||||
// 找到这个订阅
|
// 找到这个订阅
|
||||||
const sub = dataList.value.find(sub => sub.id.toString() == props.subid?.toString())
|
const sub = dataList.value.find(sub => sub.id.toString() == props.subid?.toString())
|
||||||
@@ -75,7 +130,8 @@ onMounted(async () => {
|
|||||||
|
|
||||||
onActivated(async () => {
|
onActivated(async () => {
|
||||||
if (!loading.value) {
|
if (!loading.value) {
|
||||||
fetchData()
|
await fetchData()
|
||||||
|
await loadSubscribeOrderConfig()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -83,17 +139,21 @@ onActivated(async () => {
|
|||||||
<template>
|
<template>
|
||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
<VPullToRefresh v-model="loading" @load="onRefresh">
|
<VPullToRefresh v-model="loading" @load="onRefresh">
|
||||||
<div v-if="filteredDataList.length > 0" class="mx-3 grid gap-4 grid-subscribe-card p-1">
|
<draggable
|
||||||
<SubscribeCard
|
v-if="displayList.length > 0"
|
||||||
v-for="data in filteredDataList"
|
v-model="displayList"
|
||||||
:key="data.id"
|
@end="saveSubscribeOrder"
|
||||||
:media="data"
|
handle=".cursor-move"
|
||||||
@remove="fetchData"
|
item-key="id"
|
||||||
@save="fetchData"
|
tag="div"
|
||||||
/>
|
:component-data="{ class: 'mx-3 grid gap-4 grid-subscribe-card p-1' }"
|
||||||
</div>
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<SubscribeCard :key="element.id" :media="element" @remove="fetchData" @save="fetchData" />
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="filteredDataList.length === 0 && isRefreshed"
|
v-if="displayList.length === 0 && isRefreshed"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
error-title="没有订阅"
|
error-title="没有订阅"
|
||||||
error-description="请通过搜索添加电影、电视剧订阅。"
|
error-description="请通过搜索添加电影、电视剧订阅。"
|
||||||
|
|||||||
Reference in New Issue
Block a user