add subscribe share cards

This commit is contained in:
jxxghp
2024-10-09 19:47:31 +08:00
parent 936be9928d
commit f307327af3
6 changed files with 456 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import { useToast } from 'vue-toast-notification'
import { useConfirm } from 'vuetify-use-dialog'
import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
import SubscribeFilesDialog from '../dialog/SubscribeFilesDialog.vue'
import SubscribeShareDialog from '../dialog/SubscribeShareDialog.vue'
import { formatDateDifference, formatSeason } from '@/@core/utils/formatters'
import api from '@/api'
import type { Subscribe } from '@/api/types'
@@ -34,6 +35,9 @@ const subscribeEditDialog = ref(false)
// 订阅文件信息弹窗
const subscribeFilesDialog = ref(false)
// 分享订阅弹窗
const subscribeShareDialog = ref(false)
// 上一次更新时间
const lastUpdateText = ref(props.media && props.media.last_update ? formatDateDifference(props.media.last_update) : '')
@@ -98,6 +102,11 @@ async function resetSubscribe() {
}
}
// 分享订阅
async function shareSubscribe() {
subscribeShareDialog.value = true
}
// 编辑订阅响应
async function editSubscribeDialog() {
subscribeEditDialog.value = true
@@ -164,8 +173,18 @@ const dropdownItems = ref([
show: props.media?.type === '电视剧',
},
{
title: '取消订阅',
title: '分享',
value: 6,
props: {
prependIcon: 'mdi-share',
click: shareSubscribe,
color: 'success',
},
show: props.media?.type === '电视剧',
},
{
title: '取消订阅',
value: 7,
props: {
prependIcon: 'mdi-trash-can-outline',
color: 'error',
@@ -330,6 +349,13 @@ function onSubscribeEditRemove() {
:subid="props.media?.id"
@close="subscribeFilesDialog = false"
/>
<!-- 分享订阅弹窗 -->
<SubscribeShareDialog
v-if="subscribeShareDialog"
v-model="subscribeShareDialog"
:sub="props.media"
@close="subscribeShareDialog = false"
/>
</template>
<style lang="scss">
.subscribe-card-background {

View File

@@ -0,0 +1,146 @@
<script lang="ts" setup>
import api from '@/api'
import { doneNProgress, startNProgress } from '@/api/nprogress'
import type { SubscribeShare } from '@/api/types'
import router from '@/router'
import { useToast } from 'vue-toast-notification'
import { useConfirm } from 'vuetify-use-dialog'
// 输入参数
const props = defineProps({
media: Object as PropType<SubscribeShare>,
})
// 提示框
const $toast = useToast()
// 确认框
const createConfirm = useConfirm()
// 从 provide 中获取全局设置
const globalSettings: any = inject('globalSettings')
// 图片是否加载完成
const imageLoaded = ref(false)
// 图片加载完成响应
function imageLoadHandler() {
imageLoaded.value = true
}
// 计算backdrop图片地址
const backdropUrl = computed(() => {
const url = props.media?.backdrop || props.media?.poster
// 使用图片缓存
if (globalSettings.GLOBAL_IMAGE_CACHE && url)
return `${import.meta.env.VITE_API_BASE_URL}system/cache/image?url=${encodeURIComponent(url)}`
return url
})
// 计算海报图片地址
const posterUrl = computed(() => {
const url = props.media?.poster
// 使用图片缓存
if (globalSettings.GLOBAL_IMAGE_CACHE && url)
return `${import.meta.env.VITE_API_BASE_URL}system/cache/image?url=${encodeURIComponent(url)}`
return url
})
// 查看媒体详情
async function viewMediaDetail() {
router.push({
path: '/media',
query: {
mediaid: `${props.media?.tmdbid ? `tmdb:${props.media?.tmdbid}` : `douban:${props.media?.doubanid}`}`,
type: props.media?.type,
},
})
}
// 复用订阅
async function forkSubscribe() {
// 开始处理
startNProgress()
try {
// 确认
const isConfirmed = await createConfirm({
title: '确认',
content: `是否确认添加来自 ${props.media?.share_user} 分享的订阅:${props.media?.share_title}`,
})
if (!isConfirmed) return
// 请求API
const result: { [key: string]: any } = await api.post('subscribe/fork', props.media)
// 订阅状态
if (result.success) {
$toast.success(`${props.media?.share_title} 添加订阅成功!`)
} else {
$toast.error(`${props.media?.share_title} 添加订阅失败:${result.message}`)
}
} catch (error) {
console.error(error)
} finally {
doneNProgress()
}
}
</script>
<template>
<VHover>
<template #default="hover">
<VCard
v-bind="hover.props"
:key="props.media?.id"
class="flex flex-col rounded-lg"
:class="{
'transition transform-cpu duration-300 scale-105 shadow-lg': hover.isHovering,
}"
min-height="170"
@click="forkSubscribe"
>
<template #image>
<VImg :src="backdropUrl || posterUrl" aspect-ratio="3/2" cover @load="imageLoadHandler" position="top">
<template #placeholder>
<div class="w-full h-full">
<VSkeletonLoader class="object-cover aspect-w-3 aspect-h-2" />
</div>
</template>
<div class="absolute inset-0 subscribe-card-background"></div>
</VImg>
</template>
<div>
<VCardText class="flex items-center">
<div class="h-auto w-12 flex-shrink-0 overflow-hidden rounded-md shadow-lg" v-if="imageLoaded">
<VImg :src="posterUrl" aspect-ratio="2/3" cover @click.stop="viewMediaDetail">
<template #placeholder>
<div class="w-full h-full">
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
</div>
</template>
</VImg>
</div>
<div class="flex flex-col justify-center overflow-hidden pl-2 xl:pl-4">
<div class="text-sm font-medium text-white sm:pt-1">{{ props.media?.year }}</div>
<div class="mr-2 min-w-0 text-lg font-bold text-white">
{{ props.media?.share_title }}
</div>
</div>
</VCardText>
<VCardText class="flex justify-space-between align-center flex-wrap">
{{ props.media?.share_comment }}
</VCardText>
<VCardText class="absolute right-0 bottom-0 d-flex align-center p-2 text-gray-300">
<VIcon icon="mdi-account" class="me-1" />
{{ props.media?.share_user }}
</VCardText>
</div>
</VCard>
</template>
</VHover>
</template>
<style lang="scss">
.subscribe-card-background {
background-image: linear-gradient(90deg, rgba(31, 41, 55, 47%) 0%, rgb(31, 41, 55) 100%);
}
</style>

View File

@@ -0,0 +1,92 @@
<script lang="ts" setup>
import { useToast } from 'vue-toast-notification'
import { requiredValidator } from '@/@validators'
import api from '@/api'
import type { Subscribe, SubscribeShare } from '@/api/types'
import { useDisplay } from 'vuetify'
// 显示器宽度
const display = useDisplay()
// 输入参数
const props = defineProps({
sub: Object as PropType<Subscribe>,
})
// 定义触发的自定义事件
const emit = defineEmits(['close'])
// 订阅编辑表单
const shareForm = ref<SubscribeShare>({
subscribe_id: props.sub?.id ?? 0,
})
// 分享订阅
async function doShare() {
if (!shareForm.value.share_title || !shareForm.value.share_comment || !shareForm.value.share_user) return
try {
const result: { [key: string]: any } = await api.post('subscribe/share', shareForm.value)
// 提示
if (result.success) {
$toast.success(`${props.sub?.name} 分享成功!`)
// 通知父组件刷新
emit('close')
} else {
$toast.error(`${props.sub?.name} 分享失败:${result.message}`)
}
} catch (e) {
console.log(e)
}
}
// 提示框
const $toast = useToast()
</script>
<template>
<VDialog scrollable max-width="50rem" :fullscreen="!display.mdAndUp.value">
<VCard
:title="`分享订阅 - ${props.sub?.name} ${props.sub?.season ? `第 ${props.sub?.season} 季` : ''}`"
class="rounded-t"
>
<VCardText>
<DialogCloseBtn @click="emit('close')" />
<VForm @submit.prevent="() => {}" class="pt-2">
<VRow>
<VCol cols="12">
<VTextField
v-model="shareForm.share_title"
label="标题"
hint="给分享取一个便于识别的名称"
:rules="[requiredValidator]"
persistent-hint
/>
</VCol>
<VCol cols="12">
<VTextarea
v-model="shareForm.share_comment"
label="说明"
:rules="[requiredValidator]"
hint="关于该订阅的说明"
persistent-hint
/>
</VCol>
<VCol cols="12">
<VTextField
v-model="shareForm.share_user"
label="分享用户"
:rules="[requiredValidator]"
hint="分享人的昵称"
persistent-hint
/>
</VCol>
</VRow>
</VForm>
</VCardText>
<VCardActions class="pt-3">
<VSpacer />
<VBtn variant="elevated" @click="doShare" prepend-icon="mdi-share" class="px-5"> 确认分享 </VBtn>
</VCardActions>
</VCard>
</VDialog>
</template>