feat: 绿幕视频创建和微课视频创建
This commit is contained in:
@@ -28,7 +28,7 @@ const props = defineProps({
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2.5">
|
||||||
<slot name="action"/>
|
<slot name="action"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ watchEffect(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const onCreateCourseSubmit = async (event: FormSubmitEvent<CreateCourseSchema>) => {
|
const onCreateCourseSubmit = async (event: FormSubmitEvent<CreateCourseSchema>) => {
|
||||||
console.log(event.data)
|
|
||||||
if (!selected_file.value) {
|
if (!selected_file.value) {
|
||||||
toast.add({
|
toast.add({
|
||||||
title: '未选择文件',
|
title: '未选择文件',
|
||||||
@@ -167,6 +166,11 @@ const onCreateCourseSubmit = async (event: FormSubmitEvent<CreateCourseSchema>)
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UFormGroup label="PPT 文件" required>
|
<UFormGroup label="PPT 文件" required>
|
||||||
|
<template #help>
|
||||||
|
<p class="text-xs text-neutral-400">
|
||||||
|
仅支持 .pptx 格式
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
<FileDnD
|
<FileDnD
|
||||||
accept="application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
accept="application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
||||||
@change="file => selected_file = file"
|
@change="file => selected_file = file"
|
||||||
|
|||||||
198
components/SlideCreateCourseGreen.vue
Normal file
198
components/SlideCreateCourseGreen.vue
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { type InferType, number, object, string } from 'yup'
|
||||||
|
import ModalDigitalHumanSelect from '~/components/ModalDigitalHumanSelect.vue'
|
||||||
|
import type { FormSubmitEvent } from '#ui/types'
|
||||||
|
import { useFetchWrapped } from '~/composables/useFetchWrapped'
|
||||||
|
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
|
||||||
|
const slide = useSlideover()
|
||||||
|
const toast = useToast()
|
||||||
|
const loginState = useLoginState()
|
||||||
|
|
||||||
|
const creationForm = ref<HTMLFormElement>()
|
||||||
|
const creationPending = ref(false)
|
||||||
|
const isDigitalSelectorOpen = ref(false)
|
||||||
|
|
||||||
|
const createCourseSchema = object({
|
||||||
|
title: string().trim().min(4, '标题必须大于4个字符').max(20, '标题不能超过20个字符').required('请输入视频标题'),
|
||||||
|
content: string().trim().min(4, '内容必须大于4个字符').max(1000, '内容不能超过1000个字符').required('请输入驱动文本内容'),
|
||||||
|
digital_human_id: number().not([0], '请选择数字人'),
|
||||||
|
speed: number().default(1.0).min(0.5).max(1.5).required(),
|
||||||
|
})
|
||||||
|
|
||||||
|
type CreateCourseSchema = InferType<typeof createCourseSchema>
|
||||||
|
|
||||||
|
const createCourseState = reactive({
|
||||||
|
title: undefined,
|
||||||
|
content: undefined,
|
||||||
|
digital_human_id: 0,
|
||||||
|
speed: 1.0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const selected_digital_human = ref<DigitalHumanItem | null>(null)
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (selected_digital_human.value) {
|
||||||
|
createCourseState.digital_human_id = selected_digital_human.value.model_id || selected_digital_human.value.id!
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const onCreateCourseGreenSubmit = async (event: FormSubmitEvent<CreateCourseSchema>) => {
|
||||||
|
creationPending.value = true
|
||||||
|
useFetchWrapped<req.gen.GBVideoCreate & AuthedRequest, BaseResponse<resp.gen.GBVideoCreate>>('App.Digital_VideoTask.Create', {
|
||||||
|
token: loginState.token!,
|
||||||
|
user_id: loginState.user.id,
|
||||||
|
title: event.data.title,
|
||||||
|
content: event.data.content,
|
||||||
|
digital_human_id: event.data.digital_human_id,
|
||||||
|
speed: 2 - event.data.speed,
|
||||||
|
device_id: 'XSHAssistant Web',
|
||||||
|
}).then(res => {
|
||||||
|
if (!!res.data.task_id) {
|
||||||
|
toast.add({
|
||||||
|
title: '创建成功',
|
||||||
|
description: '视频已加入生成队列',
|
||||||
|
color: 'green',
|
||||||
|
icon: 'i-tabler-check',
|
||||||
|
})
|
||||||
|
emit('success')
|
||||||
|
slide.close()
|
||||||
|
} else {
|
||||||
|
toast.add({
|
||||||
|
title: '创建失败',
|
||||||
|
description: res.msg || '未知错误',
|
||||||
|
color: 'red',
|
||||||
|
icon: 'i-tabler-alert-triangle',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
creationPending.value = false
|
||||||
|
}).catch(e => {
|
||||||
|
creationPending.value = false
|
||||||
|
toast.add({
|
||||||
|
title: '创建失败',
|
||||||
|
description: e.message || '未知错误',
|
||||||
|
color: 'red',
|
||||||
|
icon: 'i-tabler-alert-triangle',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<USlideover prevent-close>
|
||||||
|
<UCard
|
||||||
|
:ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }"
|
||||||
|
class="flex flex-col flex-1"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||||
|
新建绿幕视频
|
||||||
|
</h3>
|
||||||
|
<UButton
|
||||||
|
class="-my-1"
|
||||||
|
color="gray"
|
||||||
|
icon="i-tabler-x"
|
||||||
|
variant="ghost"
|
||||||
|
@click="slide.close()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<UForm
|
||||||
|
ref="creationForm"
|
||||||
|
:schema="createCourseSchema"
|
||||||
|
:state="createCourseState"
|
||||||
|
class="space-y-4"
|
||||||
|
@submit="onCreateCourseGreenSubmit"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between gap-2 *:flex-1">
|
||||||
|
<UFormGroup label="视频标题" name="title" required>
|
||||||
|
<UInput v-model="createCourseState.title" placeholder="请输入视频标题"/>
|
||||||
|
</UFormGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||||
|
<UFormGroup label="数字人" name="digital_human_id" required>
|
||||||
|
<div
|
||||||
|
:class="{'shadow-inner': !!selected_digital_human}"
|
||||||
|
class="flex items-center gap-2 bg-neutral-100 p-2 rounded-md cursor-pointer select-none transition-all"
|
||||||
|
@click="isDigitalSelectorOpen = true"
|
||||||
|
>
|
||||||
|
<div class="w-12 aspect-square border rounded-md flex justify-center items-center overflow-hidden">
|
||||||
|
<UIcon v-if="!selected_digital_human" class="text-2xl opacity-50" name="i-tabler-user-screen"/>
|
||||||
|
<NuxtImg v-else :src="selected_digital_human?.avatar"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col text-neutral-400 text-sm font-medium">
|
||||||
|
<span :class="!!selected_digital_human ? 'text-neutral-600' : ''">{{
|
||||||
|
selected_digital_human?.name || '点击选择数字人'
|
||||||
|
}}</span>
|
||||||
|
<span v-if="selected_digital_human?.description" class="text-2xs">
|
||||||
|
{{ selected_digital_human?.description }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UFormGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UFormGroup label="驱动内容" name="content" required>
|
||||||
|
<!-- <template #help>-->
|
||||||
|
<!-- <p class="text-xs text-neutral-400">-->
|
||||||
|
<!-- 仅支持 .pptx 格式-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<UTextarea v-model="createCourseState.content" :rows="6" autoresize placeholder="请输入驱动文本内容"/>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UAccordion :items="[{label: '高级选项'}]" color="gray" size="lg">
|
||||||
|
<template #item>
|
||||||
|
<div class="border rounded-lg space-y-4 p-4 pb-6">
|
||||||
|
<UFormGroup :label="`视频倍速:${createCourseState.speed}`" name="speed">
|
||||||
|
<URange
|
||||||
|
v-model="createCourseState.speed"
|
||||||
|
:max="1.5"
|
||||||
|
:min="0.5"
|
||||||
|
:step="0.1"
|
||||||
|
class="pt-4"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</UFormGroup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UAccordion>
|
||||||
|
</UForm>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end space-x-4">
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
label="取消"
|
||||||
|
size="lg"
|
||||||
|
variant="ghost"
|
||||||
|
@click="slide.close()"
|
||||||
|
/>
|
||||||
|
<UButton
|
||||||
|
:loading="creationPending"
|
||||||
|
color="primary"
|
||||||
|
label="提交"
|
||||||
|
size="lg"
|
||||||
|
variant="solid"
|
||||||
|
@click="creationForm?.submit()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UCard>
|
||||||
|
<ModalDigitalHumanSelect
|
||||||
|
:is-open="isDigitalSelectorOpen"
|
||||||
|
@close="isDigitalSelectorOpen = false"
|
||||||
|
@select="digitalHumans => {
|
||||||
|
selected_digital_human = (digitalHumans as DigitalHumanItem)
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</USlideover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,7 @@ import type { PropType } from 'vue'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useDownload } from '~/composables/useDownload'
|
import { useDownload } from '~/composables/useDownload'
|
||||||
import gsap from 'gsap'
|
import gsap from 'gsap'
|
||||||
|
import SRTEditor from '~/components/aigc/generation/SRTEditor.vue'
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const { metaSymbol } = useShortcuts()
|
const { metaSymbol } = useShortcuts()
|
||||||
@@ -284,7 +285,7 @@ const copyTaskId = (extraMessage?: string) => {
|
|||||||
/>
|
/>
|
||||||
</UCard>
|
</UCard>
|
||||||
</UModal>
|
</UModal>
|
||||||
<LazyAigcCourseGenerateSRTEditor
|
<SRTEditor
|
||||||
ref="srtEditor"
|
ref="srtEditor"
|
||||||
:course="course"
|
:course="course"
|
||||||
/>
|
/>
|
||||||
188
components/aigc/generation/GBTaskCard.vue
Normal file
188
components/aigc/generation/GBTaskCard.vue
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
video: {
|
||||||
|
type: Object as PropType<GBVideoItem>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits({
|
||||||
|
delete: (video: GBVideoItem) => video,
|
||||||
|
})
|
||||||
|
|
||||||
|
const dayjs = useDayjs()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
|
const isFullContentOpen = ref(false)
|
||||||
|
const downloadingState = reactive({
|
||||||
|
subtitle: 0,
|
||||||
|
video: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const startDownload = (url: string, filename: string) => {
|
||||||
|
if (url.endsWith('.ass')) {
|
||||||
|
downloadingState.subtitle = 0
|
||||||
|
} else {
|
||||||
|
downloadingState.video = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
download,
|
||||||
|
progressEmitter,
|
||||||
|
} = useDownload(url, filename)
|
||||||
|
|
||||||
|
progressEmitter.on('progress', progress => {
|
||||||
|
if (url.endsWith('.ass')) {
|
||||||
|
downloadingState.subtitle = progress
|
||||||
|
} else {
|
||||||
|
downloadingState.video = progress
|
||||||
|
}
|
||||||
|
console.log(downloadingState)
|
||||||
|
})
|
||||||
|
|
||||||
|
progressEmitter.on('done', () => {
|
||||||
|
if (url.endsWith('.ass')) {
|
||||||
|
downloadingState.subtitle = 100
|
||||||
|
} else {
|
||||||
|
downloadingState.video = 100
|
||||||
|
}
|
||||||
|
toast.add({
|
||||||
|
title: '下载完成',
|
||||||
|
description: '资源下载已完成',
|
||||||
|
color: 'green',
|
||||||
|
icon: 'i-tabler-check',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
progressEmitter.on('error', err => {
|
||||||
|
if (url.endsWith('.ass')) {
|
||||||
|
downloadingState.subtitle = 0
|
||||||
|
} else {
|
||||||
|
downloadingState.video = 0
|
||||||
|
}
|
||||||
|
toast.add({
|
||||||
|
title: '下载失败',
|
||||||
|
description: err.message || '下载失败,未知错误',
|
||||||
|
color: 'red',
|
||||||
|
icon: 'i-tabler-alert-triangle',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
download()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
console.log('click delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-full flex gap-2 rounded-xl border border-neutral-200 dark:border-neutral-700 hover:shadow transition overflow-hidden p-3"
|
||||||
|
>
|
||||||
|
<div class="flex-0 h-48 aspect-[10/16] flex flex-col items-center justify-center rounded-lg shadow overflow-hidden">
|
||||||
|
<div v-if="!video.video_cover" class="w-full h-full bg-primary flex flex-col justify-center items-center gap-2">
|
||||||
|
<UIcon class="animate-spin text-4xl text-white" name="tabler:loader"/>
|
||||||
|
<div class="flex flex-col items-center gap-0.5">
|
||||||
|
<span class="text-sm font-bold text-white/90">火速生成中</span>
|
||||||
|
<span class="text-xs font-medium text-white/50">{{ video.progress }}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NuxtImg v-else :src="video.video_cover" class="brightness-90 object-cover"/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 flex flex-col justify-between gap-2">
|
||||||
|
<div class="flex-1 rounded-lg bg-neutral-100 dark:bg-neutral-800 p-2 px-2.5">
|
||||||
|
<ul class="grid grid-cols-2 gap-1.5">
|
||||||
|
<li class="col-span-2">
|
||||||
|
<!-- <h2 class="text-2xs font-medium text-primary-500">标题</h2>-->
|
||||||
|
<p class="text-sm font-bold line-clamp-1">{{ video.title || '无标题' }}</p>
|
||||||
|
</li>
|
||||||
|
<li class="">
|
||||||
|
<h2 class="text-2xs font-medium text-primary-500">完成时间</h2>
|
||||||
|
<p class="text-xs line-clamp-1">{{ dayjs(video.complete_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}</p>
|
||||||
|
</li>
|
||||||
|
<li class="">
|
||||||
|
<h2 class="text-2xs font-medium text-primary-500">生成耗时</h2>
|
||||||
|
<p class="text-xs line-clamp-1">{{ dayjs.duration(video.duration || 0).format('HH:mm:ss') }}</p>
|
||||||
|
</li>
|
||||||
|
<li class="col-span-2 cursor-pointer" @click="isFullContentOpen = true">
|
||||||
|
<h2 class="text-2xs font-medium text-primary-500">驱动文本</h2>
|
||||||
|
<p class="text-xs line-clamp-3 text-justify">{{ video.content }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end sm:justify-between items-center group flex-nowrap whitespace-nowrap">
|
||||||
|
<div
|
||||||
|
class="hidden sm:flex items-center gap-1 transition-all group-hover:opacity-0 group-hover:pointer-events-none">
|
||||||
|
<UIcon class="text-primary text-lg" name="i-tabler-user-square-rounded"/>
|
||||||
|
<p class="text-xs">数字人 {{ video.digital_human_id }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="space-x-2">
|
||||||
|
<UButton
|
||||||
|
class="transition-all sm:opacity-0 sm:translate-x-4 sm:pointer-events-none group-hover:opacity-100 group-hover:translate-x-0 group-hover:pointer-events-auto"
|
||||||
|
color="red"
|
||||||
|
icon="i-tabler-trash"
|
||||||
|
size="xs"
|
||||||
|
variant="soft"
|
||||||
|
@click="emit('delete', video)"
|
||||||
|
/>
|
||||||
|
<UButtonGroup size="xs">
|
||||||
|
<UButton
|
||||||
|
:label="downloadingState.subtitle > 0 && downloadingState.subtitle < 100 ? `${downloadingState.subtitle.toFixed(0)}%` : '字幕'"
|
||||||
|
:loading="downloadingState.subtitle > 0 && downloadingState.subtitle < 100"
|
||||||
|
color="primary"
|
||||||
|
leading-icon="i-tabler-file-download"
|
||||||
|
variant="soft"
|
||||||
|
@click="startDownload(video.subtitle!, (video.title || video.task_id) + '.ass')"
|
||||||
|
/>
|
||||||
|
<UButton
|
||||||
|
:label="downloadingState.video > 0 && downloadingState.video < 100 ? `${downloadingState.video.toFixed(0)}%` : '视频'"
|
||||||
|
:loading="downloadingState.video > 0 && downloadingState.video < 100"
|
||||||
|
color="primary"
|
||||||
|
leading-icon="i-tabler-download"
|
||||||
|
variant="soft"
|
||||||
|
@click="startDownload(video.video_url!, (video.title || video.task_id) + '.mp4')"
|
||||||
|
/>
|
||||||
|
</UButtonGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Full video content -->
|
||||||
|
<UModal v-model="isFullContentOpen">
|
||||||
|
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||||
|
{{ video.title || '无标题' }}
|
||||||
|
<span class="block text-xs text-primary">驱动内容</span>
|
||||||
|
</h3>
|
||||||
|
<UButton
|
||||||
|
color="gray"
|
||||||
|
icon="i-tabler-x"
|
||||||
|
variant="ghost"
|
||||||
|
@click="isFullContentOpen = false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<article class="prose">
|
||||||
|
<p class="text-justify">{{ video.content }}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<UButton color="primary" @click="isFullContentOpen = false">关闭</UButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UCard>
|
||||||
|
</UModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
32
composables/useTourState.ts
Normal file
32
composables/useTourState.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
export const useTourState = defineStore('tour_state', () => {
|
||||||
|
const tourState = ref<{ [key: string]: boolean }>({})
|
||||||
|
|
||||||
|
const isTourDone = (tourId: string) => tourState.value[tourId] || false
|
||||||
|
const setTourDone = (tourId: string) => {
|
||||||
|
tourState.value = {
|
||||||
|
...tourState.value,
|
||||||
|
[tourId]: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const autoDriveTour = (tourId: string, driver: ReturnType<typeof useDriver>) => {
|
||||||
|
if (isTourDone(tourId)) return
|
||||||
|
driver.setConfig({
|
||||||
|
...driver.getConfig(),
|
||||||
|
onDestroyed: () => setTourDone(tourId),
|
||||||
|
})
|
||||||
|
driver.drive()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
tourState,
|
||||||
|
isTourDone,
|
||||||
|
setTourDone,
|
||||||
|
autoDriveTour,
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
persist: {
|
||||||
|
key: 'xsh_assistant_tour_state',
|
||||||
|
storage: persistedState.localStorage,
|
||||||
|
paths: ['tourState'],
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -17,6 +17,8 @@ export default defineNuxtConfig({
|
|||||||
'@vite-pwa/nuxt',
|
'@vite-pwa/nuxt',
|
||||||
'@nuxtjs/google-fonts',
|
'@nuxtjs/google-fonts',
|
||||||
'@nuxt/image',
|
'@nuxt/image',
|
||||||
|
'@vueuse/nuxt',
|
||||||
|
'nuxt-driver.js',
|
||||||
],
|
],
|
||||||
|
|
||||||
icon: {
|
icon: {
|
||||||
@@ -30,7 +32,7 @@ export default defineNuxtConfig({
|
|||||||
|
|
||||||
dayjs: {
|
dayjs: {
|
||||||
locales: ['zh', 'en'],
|
locales: ['zh', 'en'],
|
||||||
plugins: ['relativeTime', 'utc', 'timezone'],
|
plugins: ['relativeTime', 'utc', 'timezone', 'duration'],
|
||||||
defaultLocale: 'zh',
|
defaultLocale: 'zh',
|
||||||
defaultTimezone: 'Asia/Shanghai',
|
defaultTimezone: 'Asia/Shanghai',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"nuxt": "^3.12.4",
|
"nuxt": "^3.12.4",
|
||||||
|
"nuxt-driver.js": "^0.0.11",
|
||||||
"radix-vue": "^1.9.2",
|
"radix-vue": "^1.9.2",
|
||||||
"vue": "^3.4.34",
|
"vue": "^3.4.34",
|
||||||
"vue-router": "^4.4.0",
|
"vue-router": "^4.4.0",
|
||||||
@@ -38,6 +39,8 @@
|
|||||||
"@tailwindcss/typography": "^0.5.13",
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"@types/markdown-it": "^13.0.9",
|
"@types/markdown-it": "^13.0.9",
|
||||||
"@vite-pwa/nuxt": "^0.5.0",
|
"@vite-pwa/nuxt": "^0.5.0",
|
||||||
|
"@vueuse/core": "^10.11.1",
|
||||||
|
"@vueuse/nuxt": "^10.11.1",
|
||||||
"dayjs-nuxt": "^2.1.9",
|
"dayjs-nuxt": "^2.1.9",
|
||||||
"sass": "^1.77.8"
|
"sass": "^1.77.8"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,4 +73,27 @@ onMounted(() => {
|
|||||||
.subpage-leave-to {
|
.subpage-leave-to {
|
||||||
@apply opacity-0 translate-x-4;
|
@apply opacity-0 translate-x-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-screen-leave-active {
|
||||||
|
@apply transition-all duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-screen-leave-to {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-move,
|
||||||
|
.card-enter-active,
|
||||||
|
.card-leave-active {
|
||||||
|
@apply transition-all duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-enter-from,
|
||||||
|
.card-leave-to {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-leave-active {
|
||||||
|
@apply absolute;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import CGTaskCard from '~/components/aigc/course-generate/CGTaskCard.vue'
|
import CGTaskCard from '~/components/aigc/generation/CGTaskCard.vue'
|
||||||
import { useFetchWrapped } from '~/composables/useFetchWrapped'
|
|
||||||
import ModalAuthentication from '~/components/ModalAuthentication.vue'
|
import ModalAuthentication from '~/components/ModalAuthentication.vue'
|
||||||
import SlideCreateCourse from '~/components/SlideCreateCourse.vue'
|
import SlideCreateCourse from '~/components/SlideCreateCourse.vue'
|
||||||
|
import { useFetchWrapped } from '~/composables/useFetchWrapped'
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const modal = useModal()
|
const modal = useModal()
|
||||||
@@ -90,7 +90,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="font-sans h-full">
|
<div>
|
||||||
<div class="p-4 pb-0">
|
<div class="p-4 pb-0">
|
||||||
<BubbleTitle subtitle="VIDEOS" title="我的微课视频">
|
<BubbleTitle subtitle="VIDEOS" title="我的微课视频">
|
||||||
<template #action>
|
<template #action>
|
||||||
@@ -114,8 +114,10 @@ onMounted(() => {
|
|||||||
<GradientDivider/>
|
<GradientDivider/>
|
||||||
</div>
|
</div>
|
||||||
<Transition name="loading-screen">
|
<Transition name="loading-screen">
|
||||||
<div v-if="courseList?.data.items.length === 0"
|
<div
|
||||||
class="w-full h-full flex flex-col justify-center items-center gap-2 bg-neutral-100 dark:bg-neutral-900">
|
v-if="courseList?.data.items.length === 0"
|
||||||
|
class="w-full py-20 flex flex-col justify-center items-center gap-2"
|
||||||
|
>
|
||||||
<Icon class="text-7xl text-neutral-300 dark:text-neutral-700" name="i-tabler-photo-hexagon"/>
|
<Icon class="text-7xl text-neutral-300 dark:text-neutral-700" name="i-tabler-photo-hexagon"/>
|
||||||
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||||
没有记录
|
没有记录
|
||||||
@@ -137,7 +139,7 @@ onMounted(() => {
|
|||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-4">
|
<div class="flex justify-end mt-4">
|
||||||
<UPagination v-model="page" :page-count="16" :total="courseList?.data.total || 0"/>
|
<UPagination v-model="page" :max="9" :page-count="16" :total="courseList?.data.total || 0"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
@@ -145,26 +147,5 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.loading-screen-leave-active {
|
|
||||||
@apply transition-all duration-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-screen-leave-to {
|
|
||||||
@apply opacity-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-move,
|
|
||||||
.card-enter-active,
|
|
||||||
.card-leave-active {
|
|
||||||
@apply transition-all duration-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-enter-from,
|
|
||||||
.card-leave-to {
|
|
||||||
@apply opacity-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-leave-active {
|
|
||||||
@apply absolute;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,10 +1,204 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { useFetchWrapped } from '~/composables/useFetchWrapped'
|
||||||
|
import GBTaskCard from '~/components/aigc/generation/GBTaskCard.vue'
|
||||||
|
import { useTourState } from '~/composables/useTourState'
|
||||||
|
import SlideCreateCourseGreen from '~/components/SlideCreateCourseGreen.vue'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const slide = useSlideover()
|
||||||
|
const toast = useToast()
|
||||||
|
const loginState = useLoginState()
|
||||||
|
const tourState = useTourState()
|
||||||
|
|
||||||
|
const page = ref(1)
|
||||||
|
const pageCount = ref(15)
|
||||||
|
const searchInput = ref('')
|
||||||
|
const debounceSearch = refDebounced(searchInput, 1000)
|
||||||
|
|
||||||
|
watch(debounceSearch, () => page.value = 1)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: videoList,
|
||||||
|
refresh: refreshVideoList,
|
||||||
|
} = useAsyncData(
|
||||||
|
() => useFetchWrapped<
|
||||||
|
req.gen.GBVideoList & AuthedRequest,
|
||||||
|
BaseResponse<PagedData<GBVideoItem>>
|
||||||
|
>('App.Digital_VideoTask.GetList', {
|
||||||
|
token: loginState.token!,
|
||||||
|
user_id: loginState.user.id,
|
||||||
|
to_user_id: loginState.user.id,
|
||||||
|
page: page.value,
|
||||||
|
perpage: pageCount.value,
|
||||||
|
title: debounceSearch.value,
|
||||||
|
}), {
|
||||||
|
watch: [page, pageCount, debounceSearch],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const onCreateCourseGreenClick = () => {
|
||||||
|
slide.open(SlideCreateCourseGreen, {
|
||||||
|
onSuccess: () => {
|
||||||
|
refreshVideoList()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCourseGreenDelete = (task: GBVideoItem) => {
|
||||||
|
if (!task.task_id) return
|
||||||
|
useFetchWrapped<
|
||||||
|
req.gen.GBVideoDelete & AuthedRequest,
|
||||||
|
BaseResponse<resp.gen.GBVideoDelete>
|
||||||
|
>('App.Digital_VideoTask.Delete', {
|
||||||
|
token: loginState.token!,
|
||||||
|
user_id: loginState.user.id,
|
||||||
|
task_id: task.task_id,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.data.code === 1) {
|
||||||
|
refreshVideoList()
|
||||||
|
toast.add({
|
||||||
|
title: '删除成功',
|
||||||
|
description: '已删除任务记录',
|
||||||
|
color: 'green',
|
||||||
|
icon: 'i-tabler-check',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toast.add({
|
||||||
|
title: '删除失败',
|
||||||
|
description: res.msg || '未知错误',
|
||||||
|
color: 'red',
|
||||||
|
icon: 'i-tabler-alert-triangle',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const beforeLeave = (el: any) => {
|
||||||
|
el.style.width = `${ el.offsetWidth }px`
|
||||||
|
el.style.height = `${ el.offsetHeight }px`
|
||||||
|
}
|
||||||
|
|
||||||
|
const leave = (el: any, done: Function) => {
|
||||||
|
el.style.position = 'absolute'
|
||||||
|
el.style.transition = 'none' // 取消过渡动画
|
||||||
|
el.style.opacity = 0 // 立即隐藏元素
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const i = setInterval(refreshVideoList, 1000 * 5)
|
||||||
|
onBeforeUnmount(() => clearInterval(i))
|
||||||
|
|
||||||
|
const driver = useDriver({
|
||||||
|
showProgress: true,
|
||||||
|
animate: true,
|
||||||
|
smoothScroll: true,
|
||||||
|
disableActiveInteraction: true,
|
||||||
|
popoverOffset: 12,
|
||||||
|
progressText: '{{current}} / {{total}}',
|
||||||
|
prevBtnText: '上一步',
|
||||||
|
nextBtnText: '下一步',
|
||||||
|
doneBtnText: '完成',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
element: '#button-create',
|
||||||
|
popover: {
|
||||||
|
title: '新建视频',
|
||||||
|
description: '点击这里开始新建绿幕视频',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: '#input-search',
|
||||||
|
popover: {
|
||||||
|
title: '搜索生成记录',
|
||||||
|
description: '在这里输入视频标题,可以搜索符合条件的生成记录',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
tourState.autoDriveTour(route.fullPath, driver)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="h-full">
|
||||||
绿幕视频生成
|
<div class="p-4 pb-0">
|
||||||
|
<BubbleTitle
|
||||||
|
:subtitle="!debounceSearch ? 'GB VIDEOS' : 'SEARCH...'"
|
||||||
|
:title="!debounceSearch ? '我的绿幕视频' : `标题搜索:${debounceSearch.toLocaleUpperCase()}`"
|
||||||
|
>
|
||||||
|
<template #action>
|
||||||
|
<UButtonGroup size="md">
|
||||||
|
<UInput
|
||||||
|
id="input-search"
|
||||||
|
v-model="searchInput"
|
||||||
|
:autofocus="false"
|
||||||
|
:ui="{ icon: { trailing: { pointer: '' } } }"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="标题搜索"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<template #trailing>
|
||||||
|
<UButton
|
||||||
|
v-show="searchInput !== ''"
|
||||||
|
:padded="false"
|
||||||
|
color="gray"
|
||||||
|
icon="i-tabler-x"
|
||||||
|
variant="link"
|
||||||
|
@click="searchInput = ''"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</UInput>
|
||||||
|
</UButtonGroup>
|
||||||
|
<UButton
|
||||||
|
id="button-create"
|
||||||
|
:trailing="false"
|
||||||
|
color="primary"
|
||||||
|
icon="i-tabler-plus"
|
||||||
|
label="新建"
|
||||||
|
size="md"
|
||||||
|
variant="solid"
|
||||||
|
@click="onCreateCourseGreenClick"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BubbleTitle>
|
||||||
|
<GradientDivider/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Transition name="loading-screen">
|
||||||
|
<div
|
||||||
|
v-if="videoList?.data.items.length === 0"
|
||||||
|
class="w-full py-20 flex flex-col justify-center items-center gap-2"
|
||||||
|
>
|
||||||
|
<Icon class="text-7xl text-neutral-300 dark:text-neutral-700" name="i-tabler-photo-hexagon"/>
|
||||||
|
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||||
|
没有记录
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="relative grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-3 fhd:grid-cols-5 gap-4">
|
||||||
|
<TransitionGroup
|
||||||
|
name="card"
|
||||||
|
@beforeLeave="beforeLeave"
|
||||||
|
@leave="leave"
|
||||||
|
>
|
||||||
|
<GBTaskCard
|
||||||
|
v-for="(v, i) in videoList?.data.items"
|
||||||
|
:key="v.task_id"
|
||||||
|
:video="v"
|
||||||
|
@delete="v => onCourseGreenDelete(v)"
|
||||||
|
/>
|
||||||
|
</TransitionGroup>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end mt-4">
|
||||||
|
<UPagination v-model="page" :max="9" :page-count="pageCount" :total="videoList?.data.total || 0"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
78
pnpm-lock.yaml
generated
78
pnpm-lock.yaml
generated
@@ -53,6 +53,9 @@ importers:
|
|||||||
nuxt:
|
nuxt:
|
||||||
specifier: ^3.12.4
|
specifier: ^3.12.4
|
||||||
version: 3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
|
version: 3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
|
||||||
|
nuxt-driver.js:
|
||||||
|
specifier: ^0.0.11
|
||||||
|
version: 0.0.11(magicast@0.3.4)(rollup@4.19.1)
|
||||||
radix-vue:
|
radix-vue:
|
||||||
specifier: ^1.9.2
|
specifier: ^1.9.2
|
||||||
version: 1.9.2(vue@3.4.34)
|
version: 1.9.2(vue@3.4.34)
|
||||||
@@ -90,6 +93,12 @@ importers:
|
|||||||
'@vite-pwa/nuxt':
|
'@vite-pwa/nuxt':
|
||||||
specifier: ^0.5.0
|
specifier: ^0.5.0
|
||||||
version: 0.5.0(magicast@0.3.4)(rollup@4.19.1)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(workbox-build@7.1.1)(workbox-window@7.1.0)
|
version: 0.5.0(magicast@0.3.4)(rollup@4.19.1)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))(workbox-build@7.1.1)(workbox-window@7.1.0)
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: ^10.11.1
|
||||||
|
version: 10.11.1(vue@3.4.34)
|
||||||
|
'@vueuse/nuxt':
|
||||||
|
specifier: ^10.11.1
|
||||||
|
version: 10.11.1(magicast@0.3.4)(nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)))(rollup@4.19.1)(vue@3.4.34)
|
||||||
dayjs-nuxt:
|
dayjs-nuxt:
|
||||||
specifier: ^2.1.9
|
specifier: ^2.1.9
|
||||||
version: 2.1.9(magicast@0.3.4)(rollup@4.19.1)
|
version: 2.1.9(magicast@0.3.4)(rollup@4.19.1)
|
||||||
@@ -1835,6 +1844,9 @@ packages:
|
|||||||
'@vueuse/core@10.11.0':
|
'@vueuse/core@10.11.0':
|
||||||
resolution: {integrity: sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==}
|
resolution: {integrity: sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==}
|
||||||
|
|
||||||
|
'@vueuse/core@10.11.1':
|
||||||
|
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
|
||||||
|
|
||||||
'@vueuse/integrations@10.11.0':
|
'@vueuse/integrations@10.11.0':
|
||||||
resolution: {integrity: sha512-Pp6MtWEIr+NDOccWd8j59Kpjy5YDXogXI61Kb1JxvSfVBO8NzFQkmrKmSZz47i+ZqHnIzxaT38L358yDHTncZg==}
|
resolution: {integrity: sha512-Pp6MtWEIr+NDOccWd8j59Kpjy5YDXogXI61Kb1JxvSfVBO8NzFQkmrKmSZz47i+ZqHnIzxaT38L358yDHTncZg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1882,9 +1894,20 @@ packages:
|
|||||||
'@vueuse/metadata@10.11.0':
|
'@vueuse/metadata@10.11.0':
|
||||||
resolution: {integrity: sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==}
|
resolution: {integrity: sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==}
|
||||||
|
|
||||||
|
'@vueuse/metadata@10.11.1':
|
||||||
|
resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
|
||||||
|
|
||||||
|
'@vueuse/nuxt@10.11.1':
|
||||||
|
resolution: {integrity: sha512-UiaYSIwOkmUVn8Gl1AqtLWYR12flO+8sEu9X0Y1fNjSR7EWy9jMuiCvOGqwtoeTsqfHrivl0d5HfMzr11GFnMA==}
|
||||||
|
peerDependencies:
|
||||||
|
nuxt: ^3.0.0
|
||||||
|
|
||||||
'@vueuse/shared@10.11.0':
|
'@vueuse/shared@10.11.0':
|
||||||
resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==}
|
resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==}
|
||||||
|
|
||||||
|
'@vueuse/shared@10.11.1':
|
||||||
|
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
|
||||||
|
|
||||||
abbrev@1.1.1:
|
abbrev@1.1.1:
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||||
|
|
||||||
@@ -2547,6 +2570,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
driver.js@1.3.1:
|
||||||
|
resolution: {integrity: sha512-MvUdXbqSgEsgS/H9KyWb5Rxy0aE6BhOVT4cssi2x2XjmXea6qQfgdx32XKVLLSqTaIw7q/uxU5Xl3NV7+cN6FQ==}
|
||||||
|
|
||||||
duplexer@0.1.2:
|
duplexer@0.1.2:
|
||||||
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
||||||
|
|
||||||
@@ -3602,6 +3628,9 @@ packages:
|
|||||||
engines: {node: ^16.10.0 || >=18.0.0}
|
engines: {node: ^16.10.0 || >=18.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nuxt-driver.js@0.0.11:
|
||||||
|
resolution: {integrity: sha512-WzcNjEk7VGyMrt6vKAQGXiaf/sHp7cfGYtZ1O6fxow3DYWJ+a2NHsLE9ejumSSH753JKzmLNpJRrX0YYFCnl9g==}
|
||||||
|
|
||||||
nuxt@3.12.4:
|
nuxt@3.12.4:
|
||||||
resolution: {integrity: sha512-/ddvyc2kgYYIN2UEjP8QIz48O/W3L0lZm7wChIDbOCj0vF/yLLeZHBaTb3aNvS9Hwp269nfjrm8j/mVxQK4RhA==}
|
resolution: {integrity: sha512-/ddvyc2kgYYIN2UEjP8QIz48O/W3L0lZm7wChIDbOCj0vF/yLLeZHBaTb3aNvS9Hwp269nfjrm8j/mVxQK4RhA==}
|
||||||
engines: {node: ^14.18.0 || >=16.10.0}
|
engines: {node: ^14.18.0 || >=16.10.0}
|
||||||
@@ -6493,7 +6522,7 @@ snapshots:
|
|||||||
'@tailwindcss/container-queries': 0.1.1(tailwindcss@3.4.7)
|
'@tailwindcss/container-queries': 0.1.1(tailwindcss@3.4.7)
|
||||||
'@tailwindcss/forms': 0.5.7(tailwindcss@3.4.7)
|
'@tailwindcss/forms': 0.5.7(tailwindcss@3.4.7)
|
||||||
'@tailwindcss/typography': 0.5.13(tailwindcss@3.4.7)
|
'@tailwindcss/typography': 0.5.13(tailwindcss@3.4.7)
|
||||||
'@vueuse/core': 10.11.0(vue@3.4.34)
|
'@vueuse/core': 10.11.1(vue@3.4.34)
|
||||||
'@vueuse/integrations': 10.11.0(fuse.js@6.6.2)(idb-keyval@6.2.1)(vue@3.4.34)
|
'@vueuse/integrations': 10.11.0(fuse.js@6.6.2)(idb-keyval@6.2.1)(vue@3.4.34)
|
||||||
'@vueuse/math': 10.11.0(vue@3.4.34)
|
'@vueuse/math': 10.11.0(vue@3.4.34)
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
@@ -7165,6 +7194,16 @@ snapshots:
|
|||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
'@vueuse/core@10.11.1(vue@3.4.34)':
|
||||||
|
dependencies:
|
||||||
|
'@types/web-bluetooth': 0.0.20
|
||||||
|
'@vueuse/metadata': 10.11.1
|
||||||
|
'@vueuse/shared': 10.11.1(vue@3.4.34)
|
||||||
|
vue-demi: 0.14.10(vue@3.4.34)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@vue/composition-api'
|
||||||
|
- vue
|
||||||
|
|
||||||
'@vueuse/integrations@10.11.0(fuse.js@6.6.2)(idb-keyval@6.2.1)(vue@3.4.34)':
|
'@vueuse/integrations@10.11.0(fuse.js@6.6.2)(idb-keyval@6.2.1)(vue@3.4.34)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vueuse/core': 10.11.0(vue@3.4.34)
|
'@vueuse/core': 10.11.0(vue@3.4.34)
|
||||||
@@ -7187,6 +7226,23 @@ snapshots:
|
|||||||
|
|
||||||
'@vueuse/metadata@10.11.0': {}
|
'@vueuse/metadata@10.11.0': {}
|
||||||
|
|
||||||
|
'@vueuse/metadata@10.11.1': {}
|
||||||
|
|
||||||
|
'@vueuse/nuxt@10.11.1(magicast@0.3.4)(nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)))(rollup@4.19.1)(vue@3.4.34)':
|
||||||
|
dependencies:
|
||||||
|
'@nuxt/kit': 3.12.4(magicast@0.3.4)(rollup@4.19.1)
|
||||||
|
'@vueuse/core': 10.11.1(vue@3.4.34)
|
||||||
|
'@vueuse/metadata': 10.11.1
|
||||||
|
local-pkg: 0.5.0
|
||||||
|
nuxt: 3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3))
|
||||||
|
vue-demi: 0.14.10(vue@3.4.34)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@vue/composition-api'
|
||||||
|
- magicast
|
||||||
|
- rollup
|
||||||
|
- supports-color
|
||||||
|
- vue
|
||||||
|
|
||||||
'@vueuse/shared@10.11.0(vue@3.4.34)':
|
'@vueuse/shared@10.11.0(vue@3.4.34)':
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi: 0.14.10(vue@3.4.34)
|
vue-demi: 0.14.10(vue@3.4.34)
|
||||||
@@ -7194,6 +7250,13 @@ snapshots:
|
|||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
'@vueuse/shared@10.11.1(vue@3.4.34)':
|
||||||
|
dependencies:
|
||||||
|
vue-demi: 0.14.10(vue@3.4.34)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@vue/composition-api'
|
||||||
|
- vue
|
||||||
|
|
||||||
abbrev@1.1.1: {}
|
abbrev@1.1.1: {}
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
@@ -7866,6 +7929,8 @@ snapshots:
|
|||||||
|
|
||||||
dotenv@16.4.5: {}
|
dotenv@16.4.5: {}
|
||||||
|
|
||||||
|
driver.js@1.3.1: {}
|
||||||
|
|
||||||
duplexer@0.1.2: {}
|
duplexer@0.1.2: {}
|
||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
@@ -9126,6 +9191,15 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
nuxt-driver.js@0.0.11(magicast@0.3.4)(rollup@4.19.1):
|
||||||
|
dependencies:
|
||||||
|
'@nuxt/kit': 3.12.4(magicast@0.3.4)(rollup@4.19.1)
|
||||||
|
driver.js: 1.3.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- magicast
|
||||||
|
- rollup
|
||||||
|
- supports-color
|
||||||
|
|
||||||
nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)):
|
nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.14.12)(idb-keyval@6.2.1)(ioredis@5.4.1)(magicast@0.3.4)(rollup@4.19.1)(sass@1.77.8)(terser@5.31.3)(vite@5.3.5(@types/node@20.14.12)(sass@1.77.8)(terser@5.31.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/devalue': 2.0.2
|
'@nuxt/devalue': 2.0.2
|
||||||
@@ -9645,7 +9719,7 @@ snapshots:
|
|||||||
'@internationalized/date': 3.5.5
|
'@internationalized/date': 3.5.5
|
||||||
'@internationalized/number': 3.5.3
|
'@internationalized/number': 3.5.3
|
||||||
'@tanstack/vue-virtual': 3.8.3(vue@3.4.34)
|
'@tanstack/vue-virtual': 3.8.3(vue@3.4.34)
|
||||||
'@vueuse/core': 10.11.0(vue@3.4.34)
|
'@vueuse/core': 10.11.1(vue@3.4.34)
|
||||||
'@vueuse/shared': 10.11.0(vue@3.4.34)
|
'@vueuse/shared': 10.11.0(vue@3.4.34)
|
||||||
aria-hidden: 1.2.4
|
aria-hidden: 1.2.4
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
|
|||||||
56
typings/types.d.ts
vendored
56
typings/types.d.ts
vendored
@@ -40,6 +40,24 @@ interface DigitalHumanItem {
|
|||||||
digital_human_id: number
|
digital_human_id: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GBVideoItem {
|
||||||
|
id: number
|
||||||
|
user_id: number
|
||||||
|
task_id: string
|
||||||
|
create_time: number
|
||||||
|
complete_time: number
|
||||||
|
progress: number
|
||||||
|
duration?: number
|
||||||
|
digital_human_id: number
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
bg_img: string
|
||||||
|
video_url?: string
|
||||||
|
video_cover?: string
|
||||||
|
subtitle?: string
|
||||||
|
speed: number
|
||||||
|
}
|
||||||
|
|
||||||
// Common request and response schemas
|
// Common request and response schemas
|
||||||
namespace req {
|
namespace req {
|
||||||
namespace user {
|
namespace user {
|
||||||
@@ -115,6 +133,29 @@ namespace req {
|
|||||||
page?: number
|
page?: number
|
||||||
perpage?: number
|
perpage?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param title 任务标题筛选
|
||||||
|
*/
|
||||||
|
interface GBVideoList {
|
||||||
|
to_user_id: number
|
||||||
|
page?: number
|
||||||
|
perpage?: number
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GBVideoCreate {
|
||||||
|
device_id: string
|
||||||
|
digital_human_id: number
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
bg_img?: string
|
||||||
|
speed?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GBVideoDelete {
|
||||||
|
task_id: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AssistantTemplateList {
|
interface AssistantTemplateList {
|
||||||
@@ -191,6 +232,21 @@ namespace resp {
|
|||||||
video_sub_id: number
|
video_sub_id: number
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request_id 任务 ID,同 task_id
|
||||||
|
*/
|
||||||
|
interface GBVideoCreate {
|
||||||
|
data_id: string
|
||||||
|
task_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param code 1: 删除成功, 0: 删除失败
|
||||||
|
*/
|
||||||
|
interface GBVideoDelete {
|
||||||
|
code: 0 | 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user