feat(ppt-templates): 添加PPT模板库页面

This commit is contained in:
2025-01-20 00:58:23 +08:00
parent 70d23ba7a2
commit a8c689d325
5 changed files with 173 additions and 3 deletions

View File

@@ -18,10 +18,15 @@ export default defineAppConfig({
container: 'gap-2',
base: 'px-3 py-4',
after: 'after:hidden',
active: 'before:bg-neutral-600 hover:before:bg-neutral-600 dark:before:bg-neutral-800 dark:hover:before:bg-neutral-800 text-neutral-50 dark:text-neutral-300',
active:
'before:bg-neutral-600 hover:before:bg-neutral-600 dark:before:bg-neutral-800 dark:hover:before:bg-neutral-800 text-neutral-50 dark:text-neutral-300',
icon: {
active: 'text-neutral-50 dark:text-neutral-300',
},
},
formGroup: {
hint: 'text-xs',
help: 'text-xs',
},
},
})

View File

@@ -5,6 +5,7 @@ const colorMode = useColorMode()
const dayjs = useDayjs()
const modal = useModal()
const toast = useToast()
const router = useRouter()
const loginState = useLoginState()
const isDark = computed({
@@ -42,6 +43,7 @@ const items = [
}], [{
label: '账号资料',
icon: 'i-tabler-user-circle',
to: '/profile'
}], [{
label: '注销登录',
icon: 'i-tabler-logout',
@@ -63,8 +65,8 @@ const open_login_modal = () => {
<div class="relative grid w-full min-h-screen">
<header>
<h1 class="inline-flex flex-col">
<span class="text-lg text-neutral-600 dark:text-neutral-300 font-bold">眩生花 AI 助手</span>
<span class="text-xs text-neutral-600 dark:text-neutral-300">XSH AI Assistant</span>
<span class="text-lg text-neutral-600 dark:text-neutral-300 font-bold">AIGC 微课视频研创平台</span>
<!-- <span class="text-xs text-neutral-600 dark:text-neutral-300">眩生花科技</span> -->
</h1>
<div class="hidden md:block">
<UHorizontalNavigation :links="links" class="select-none"/>

View File

@@ -33,6 +33,11 @@ const navList = ref<
icon: 'tabler:keyframes',
to: '/generation/materials',
},
{
label: 'PPT 模板库',
icon: 'tabler:file-type-ppt',
to: '/generation/ppt-templates',
},
{
label: '用户管理',
icon: 'tabler:users',

View File

@@ -0,0 +1,125 @@
<script lang="ts" setup>
const loginState = useLoginState()
const { data: pptCategories } = useAsyncData('pptCategories', () =>
useFetchWrapped<
PagedDataRequest & AuthedRequest,
BaseResponse<PagedData<PPTCategory>>
>('App.Digital_PowerPointCat.GetList', {
token: loginState.token!,
user_id: loginState.user.id,
page: 1,
perpage: 20,
})
)
const selectedCat = ref<number>(0)
const pagination = reactive({
page: 1,
perpage: 18,
})
const { data: pptTemplates } = useAsyncData(
'pptTemplates',
() =>
useFetchWrapped<
PagedDataRequest & { type: string | number } & AuthedRequest,
BaseResponse<PagedData<PPTTemplate>>
>('App.Digital_PowerPoint.GetList', {
token: loginState.token!,
user_id: loginState.user.id,
page: pagination.page,
perpage: pagination.perpage,
type: selectedCat.value === 0 ? '' : selectedCat.value,
}),
{
watch: [selectedCat, pagination],
}
)
const onDownloadClick = (ppt: PPTTemplate) => {
const { download } = useDownload(ppt.file_url, `${ppt.title}.pptx`)
download()
}
</script>
<template>
<div>
<div class="p-4 pb-0">
<BubbleTitle
title="PPT 模板库"
subtitle="Slide Templates"
/>
<GradientDivider />
</div>
<div class="p-4 pt-0">
<!-- cat selector -->
<div class="flex flex-wrap gap-2">
<div
v-for="cat in [
{ id: 0, type: '全部' },
...(pptCategories?.data.items || []),
]"
@click="selectedCat = cat.id"
:key="cat.id"
:class="{
'bg-primary text-white': selectedCat === cat.id,
'bg-gray-100 text-gray-500': selectedCat !== cat.id,
}"
class="rounded-lg px-4 py-2 text-sm cursor-pointer"
>
{{ cat.type }}
</div>
</div>
<div class="space-y-4">
<div
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-4 mt-4"
>
<div
v-for="ppt in pptTemplates?.data.items"
:key="ppt.id"
class="relative bg-white rounded-lg shadow-md overflow-hidden"
>
<NuxtImg
:src="ppt.preview_url"
:alt="ppt.title"
class="w-full aspect-video object-cover"
/>
<div
class="absolute inset-x-0 bottom-0 p-3 pt-6 flex justify-between items-end bg-gradient-to-t from-black/50 to-transparent"
>
<div class="space-y-0.5">
<h3 class="text-base font-bold text-white">{{ ppt.title }}</h3>
<p class="text-xs font-medium text-neutral-400">
{{ ppt.description }}
</p>
</div>
<div>
<UButton
label="下载"
size="sm"
color="primary"
icon="tabler:download"
@click="onDownloadClick(ppt)"
/>
</div>
</div>
</div>
</div>
<div class="w-full flex justify-end">
<UPagination
v-if="pptTemplates?.data.total > pagination.perpage"
:total="pptTemplates?.data.total"
:page-count="pagination.perpage"
:max="9"
v-model="pagination.page"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped></style>

33
typings/types.d.ts vendored
View File

@@ -32,6 +32,7 @@ interface UserSchema {
email: string
mobile: string
auth_code: 0 | 1 | 2 // 0: Banned, 1: User, 2: Operator
company?: string
}
interface DigitalHumanItem {
@@ -76,6 +77,22 @@ interface TitlesTemplate {
description: string
}
interface PPTCategory {
id: number
type: string
create_time: number
}
interface PPTTemplate {
id: number
create_time: number
file_url: string
preview_url: string
title: string
description: string
type: string
}
// Common request and response schemas
namespace req {
namespace user {
@@ -103,6 +120,22 @@ namespace req {
perpage?: number
is_verify: boolean
}
interface ChangePassword {
username: string
old_password: string
new_password: string
}
interface SmsChangePasswordVerify {
mobile: string
}
interface SmsChangePassword {
mobile: string
sms_code: string
new_password: string
}
}
namespace file {