diff --git a/.oxlintrc.json b/.oxlintrc.json
index ed1ef5b..8676ed9 100644
--- a/.oxlintrc.json
+++ b/.oxlintrc.json
@@ -10,7 +10,9 @@
"vitest"
],
"categories": {},
- "rules": {},
+ "rules": {
+ "no-unused-vars": "error"
+ },
"settings": {
"jsdoc": {
"ignorePrivate": false,
diff --git a/.vscode/settings.json b/.vscode/settings.json
index f563e1a..762595d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,9 +1,9 @@
{
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true,
- // "editor.codeActionsOnSave": {
- // "source.fixAll.oxc": "always"
- // },
+ "editor.codeActionsOnSave": {
+ "source.fixAll.oxc": "always"
+ },
"typescript.tsdk": "node_modules\\typescript\\lib",
"[typescript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
diff --git a/app/app.config.ts b/app/app.config.ts
index 32aa854..323d793 100644
--- a/app/app.config.ts
+++ b/app/app.config.ts
@@ -1,14 +1,28 @@
export default defineAppConfig({
ui: {
- primary: 'indigo',
- gray: 'neutral',
strategy: 'merge',
+ colors: {
+ primary: 'indigo',
+ neutral: 'neutral',
+ success: 'emerald',
+ warning: 'amber',
+ },
+ icons: {
+ loading: 'svg-spinners-180-ring',
+ },
button: {
- icon: {
- loading: 'animate-none',
+ slots: {
+ leadingIcon: 'animate-none',
},
- default: {
- loadingIcon: 'i-svg-spinners-180-ring-with-bg',
+ },
+ input: {
+ slots: {
+ root: 'w-full',
+ },
+ },
+ textarea: {
+ slots: {
+ root: 'w-full',
},
},
notifications: {
diff --git a/app/app.vue b/app/app.vue
index 1186dc7..8f3c52f 100644
--- a/app/app.vue
+++ b/app/app.vue
@@ -4,7 +4,7 @@ import ModalAuthentication from '~/components/ModalAuthentication.vue'
const toast = useToast()
const route = useRoute()
const router = useRouter()
-const modal = useModal()
+const overlay = useOverlay()
const loginState = useLoginState()
useHead({
@@ -24,10 +24,11 @@ onMounted(() => {
toast.add({
title: '登录失效',
description: '登录已过期,请重新登录',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
- modal.open(ModalAuthentication)
+ const modal = overlay.create(ModalAuthentication)
+ modal.open()
} else if (!loggedIn && !loginState.token) {
// Prevents redirect from register page
if (route.path === '/user/register') return
@@ -41,12 +42,10 @@ onMounted(() => {
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/app/assets/css/tailwind.css b/app/assets/css/main.css
similarity index 79%
rename from app/assets/css/tailwind.css
rename to app/assets/css/main.css
index caa50b4..d450cb7 100644
--- a/app/assets/css/tailwind.css
+++ b/app/assets/css/main.css
@@ -1,7 +1,10 @@
@import 'tailwindcss';
+@import '@nuxt/ui';
@config '../../../tailwind.config.ts';
+@source inline("{hover:,}{bg,text,border,from,to}-{primary,neutral,amber}{-{50,{100..900..100},950},}{/{0..100..5},}");
+
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
@@ -25,3 +28,6 @@
box-sizing: border-box;
}
}
+
+@layer theme {
+}
diff --git a/app/components/BubbleTitle.vue b/app/components/BubbleTitle.vue
index e855c34..d6286ae 100644
--- a/app/components/BubbleTitle.vue
+++ b/app/components/BubbleTitle.vue
@@ -14,7 +14,7 @@ const props = defineProps({
},
bubbleColor: {
type: String,
- default: 'primary-500',
+ default: 'primary',
},
})
diff --git a/app/components/DatePicker.vue b/app/components/DatePicker.vue
index 6675b50..814816b 100644
--- a/app/components/DatePicker.vue
+++ b/app/components/DatePicker.vue
@@ -1,11 +1,10 @@
@@ -30,10 +31,10 @@ const modal = useModal()
请登录后使用
登录
diff --git a/app/components/ModalAuthentication.vue b/app/components/ModalAuthentication.vue
index ae3352e..2092f6a 100644
--- a/app/components/ModalAuthentication.vue
+++ b/app/components/ModalAuthentication.vue
@@ -4,8 +4,9 @@ import { object, string, type InferType } from 'yup'
import type { FormSubmitEvent } from '#ui/types'
import { useFetchWrapped } from '~/composables/useFetchWrapped'
+const emit = defineEmits(['close'])
const toast = useToast()
-const modal = useModal()
+const overlay = useOverlay()
const loginState = useLoginState()
const sms_triggered = ref(false)
@@ -55,7 +56,7 @@ function onSubmit(form: req.user.Login) {
toast.add({
title: '登录失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -64,7 +65,7 @@ function onSubmit(form: req.user.Login) {
toast.add({
title: '登录失败',
description: res.msg || '账号或密码错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -73,7 +74,7 @@ function onSubmit(form: req.user.Login) {
toast.add({
title: '登录失败',
description: res.msg || '无法获取登录状态',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -84,7 +85,8 @@ function onSubmit(form: req.user.Login) {
.updateProfile()
.then(() => {
loginState.checkSession()
- modal.close()
+ // TODO: only close the specific modal
+ overlay.closeAll()
toast.add({
title: '登录成功',
description: `${loginState.user.username}, 欢迎回来`,
@@ -96,7 +98,7 @@ function onSubmit(form: req.user.Login) {
toast.add({
title: '登录失败',
description: err.msg || '网络错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -108,7 +110,7 @@ function onSubmit(form: req.user.Login) {
toast.add({
title: '登录失败',
description: err.msg || '网络错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -130,7 +132,7 @@ const obtainSmsCode = () => {
toast.add({
title: '验证码发送失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -140,7 +142,7 @@ const obtainSmsCode = () => {
sms_counting_down.value = 60 // TODO: save timestamp to localstorage
toast.add({
title: '短信验证码已发送',
- color: 'indigo',
+ color: 'primary',
icon: 'i-tabler-circle-check',
})
const interval = setInterval(() => {
@@ -154,7 +156,7 @@ const obtainSmsCode = () => {
toast.add({
title: '验证码发送失败',
description: err.msg || '网络错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -175,7 +177,7 @@ const handle_sms_verify = (e: string[]) => {
toast.add({
title: '登录失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -185,7 +187,7 @@ const handle_sms_verify = (e: string[]) => {
toast.add({
title: '登录失败',
description: res.msg || '无法获取登录状态',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -196,7 +198,7 @@ const handle_sms_verify = (e: string[]) => {
.updateProfile()
.then(() => {
loginState.checkSession()
- modal.close()
+ emit('close')
toast.add({
title: '登录成功',
description: `${loginState.user.username}, 欢迎回来`,
@@ -208,7 +210,7 @@ const handle_sms_verify = (e: string[]) => {
toast.add({
title: '登录失败',
description: err.msg || '网络错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -251,7 +253,7 @@ const obtainForgetSmsCode = () => {
toast.add({
title: '验证码发送失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -261,7 +263,7 @@ const obtainForgetSmsCode = () => {
sms_counting_down.value = 60 // TODO: save timestamp to localstorage
toast.add({
title: '短信验证码已发送',
- color: 'indigo',
+ color: 'primary',
icon: 'i-tabler-circle-check',
})
const interval = setInterval(() => {
@@ -275,7 +277,7 @@ const obtainForgetSmsCode = () => {
toast.add({
title: '验证码发送失败',
description: err.msg || '网络错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -299,7 +301,7 @@ const onForgetPasswordSubmit = (
toast.add({
title: '重置密码失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -307,7 +309,7 @@ const onForgetPasswordSubmit = (
toast.add({
title: '重置密码成功',
description: '请您继续登录',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-circle-check',
})
currentTab.value = 1
@@ -316,7 +318,7 @@ const onForgetPasswordSubmit = (
toast.add({
title: '重置密码失败',
description: err.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
})
@@ -324,173 +326,101 @@ const onForgetPasswordSubmit = (
-
-
-
-
-
- 登录眩生花 AI 助手
-
-
-
-
-
-
-
-
-
{{ item.label }}
-
+
+
+
+
+
+ 登录眩生花 AI 助手
+
+
-
- onSubmit(accountForm)">
-
-
- {{ item.label }}
-
-
- {{ item.description }}
-
-
-
-
-
-
-
-
-
+
+
+
+ onSubmit(accountForm)">
+
+
+ {{ item.label }}
+
+
+ {{ item.description }}
+
+
-
-
-
-
-
-
- +86
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+86
@@ -501,78 +431,156 @@ const onForgetPasswordSubmit = (
? `${sms_counting_down}秒后重发`
: '获取验证码'
"
- @click="obtainForgetSmsCode"
+ @click="obtainSmsCode"
:loading="sms_sending"
- :disabled="!!sms_counting_down"
+ :disabled="!!sms_counting_down || final_loading"
class="text-xs font-bold"
- color="gray"
+ color="neutral"
/>
-
-
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+ +86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 重置密码
+
+
+
+
+
+
+
- 重置密码
+ 登录
+
+
+ 忘记密码
-
-
-
-
-
-
- 登录
-
-
- 忘记密码
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/app/components/ModalDigitalHumanSelect.vue b/app/components/ModalDigitalHumanSelect.vue
index db277af..fad5122 100644
--- a/app/components/ModalDigitalHumanSelect.vue
+++ b/app/components/ModalDigitalHumanSelect.vue
@@ -27,16 +27,17 @@ const emit = defineEmits({
})
const loginState = useLoginState()
-const modal = useModal()
const toast = useToast()
const page = ref(1)
+const isRealOpen = computed(() => props.isOpen)
+
const sourceTypeList = [
- { label: 'xsh_wm', value: 1, color: 'blue' }, // 万木(腾讯)
- { label: 'xsh_zy', value: 2, color: 'green' }, // XSH 自有
- { label: 'xsh_fh', value: 3, color: 'purple' }, // 硅基(泛化数字人)
- { label: 'xsh_bb', value: 4, color: 'indigo' }, // 百度小冰
+ { label: 'xsh_wm', value: 1, color: 'info' }, // 万木(腾讯)
+ { label: 'xsh_zy', value: 2, color: 'success' }, // XSH 自有
+ { label: 'xsh_fh', value: 3, color: 'warning' }, // 硅基(泛化数字人)
+ { label: 'xsh_bb', value: 4, color: 'primary' }, // 百度小冰
]
// const sourceType = ref(sourceTypeList[0])
@@ -59,7 +60,7 @@ const handleClose = () => {
if (props.isOpen) {
emit('close')
} else {
- modal.close()
+ emit('close')
}
}
@@ -68,7 +69,7 @@ const handleSubmit = () => {
toast.add({
title: '请选择数字人',
description: '请至少选择一个数字人',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -77,7 +78,7 @@ const handleSubmit = () => {
'select',
props.multiple
? selectedDigitalHumans.value
- : selectedDigitalHumans.value[0]
+ : selectedDigitalHumans.value[0]!
)
handleClose()
setTimeout(() => {
@@ -153,113 +154,111 @@ onMounted(() => {
-
-
-
-
- 数字人选择器
-
-
-
-
-
-
-
-
-
+
+
+
+
+ 数字人选择器
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
+
+
- {{ d.name }}
-
-
- ID:{{ d.digital_human_id || d.id }}
-
+
+
+
+
+
+
+ {{ d.name }}
+
+
+ ID:{{ d.digital_human_id || d.id }}
+
+
-
-
+
+
+
+
+
+
+
+ 如果没有出现您的数字人,请联系管理员开通
+
+
+
+
+
-
-
-
-
-
-
-
- 如果没有出现您的数字人,请联系管理员开通
-
-
-
-
-
-
-
-
-
+
+
diff --git a/app/components/ModalVideoTitleSelect.vue b/app/components/ModalVideoTitleSelect.vue
index 01e3e4f..ed00eb2 100644
--- a/app/components/ModalVideoTitleSelect.vue
+++ b/app/components/ModalVideoTitleSelect.vue
@@ -12,8 +12,8 @@ const emit = defineEmits({
})
const toast = useToast()
-const modal = useModal()
const loginState = useLoginState()
+const isRealOpen = computed(() => props.isOpen)
const pagination = reactive({
page: 1,
@@ -48,7 +48,7 @@ const handleClose = () => {
if (props.isOpen) {
emit('close')
} else {
- modal.close()
+ emit('close')
}
}
@@ -57,7 +57,7 @@ const handleSubmit = () => {
toast.add({
title: '请选择片头',
description: '请选择一个片头',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-circle-x',
})
return
@@ -69,118 +69,115 @@ const handleSubmit = () => {
-
-
-
-
- 视频片头选择器
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
- {{ titles.title }}
-
-
- ID:{{ titles.id }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 如果此处没有您的片头,请在
-
- 片头模版库
-
- 页面确认已经制作完毕
-
-
-
+ 视频片头选择器
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ titles.title }}
+
+
+ ID:{{ titles.id }}
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+ 如果此处没有您的片头,请在
+
+ 片头模版库
+
+ 页面确认已经制作完毕
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/SlideCreateCourse.vue b/app/components/SlideCreateCourse.vue
index 3cfa446..7a94617 100644
--- a/app/components/SlideCreateCourse.vue
+++ b/app/components/SlideCreateCourse.vue
@@ -5,9 +5,8 @@ import ModalDigitalHumanSelect from '~/components/ModalDigitalHumanSelect.vue'
import type { FormSubmitEvent } from '#ui/types'
import { useFetchWrapped } from '~/composables/useFetchWrapped'
-const emit = defineEmits(['success'])
+const emit = defineEmits(['success', 'close'])
-const slide = useSlideover()
const toast = useToast()
const loginState = useLoginState()
@@ -65,14 +64,14 @@ const onCreateCourseSubmit = async (
toast.add({
title: '未选择文件',
description: '请先选择 PPTX 文件',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
return
}
creationPending.value = true
// upload PPTX file
- useFileGo(selected_file.value[0], 'ppt').then((url) => {
+ useFileGo(selected_file.value[0]!, 'ppt').then((url) => {
useFetchWrapped<
req.gen.CourseGenCreate & AuthedRequest,
BaseResponse
@@ -93,16 +92,16 @@ const onCreateCourseSubmit = async (
toast.add({
title: '创建成功',
description: '已加入生成队列',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
emit('success')
- slide.close()
+ emit('close')
} else {
toast.add({
title: '创建失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
}
@@ -113,7 +112,7 @@ const onCreateCourseSubmit = async (
toast.add({
title: '创建失败',
description: e.message || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
})
@@ -122,239 +121,229 @@ const onCreateCourseSubmit = async (
-
-
-
-
-
- 新建微课视频
-
-
-
-
-
-
+
+
-
-
-
+
+
+ 新建微课视频
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ selected_digital_human?.name || '点击选择数字人' }}
+
+
+ {{ selected_digital_human?.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ selected_titles?.title || '点击选择片头' }}
+
+
+ {{ selected_titles?.description }}
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- {{ selected_digital_human?.name || '点击选择数字人' }}
-
-
- {{ selected_digital_human?.description }}
-
-
-
-
-
+ 仅支持 .pptx 格式
+
+ (selected_file = file)"
+ />
+
+
+
-
+
-
-
-
-
-
- {{ selected_titles?.title || '点击选择片头' }}
-
-
- {{ selected_titles?.description }}
-
+
+
+
+
+
-
-
-
-
+
+
+
-
-
- 仅支持 .pptx 格式
-
- (selected_file = file)"
- />
-
+ {
+ selected_digital_human = digitalHumans as DigitalHumanItem
+ }
+ "
+ />
+ {
+ selected_titles = titles as TitlesTemplate
+ }
+ "
+ />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {
- selected_digital_human = digitalHumans as DigitalHumanItem
- }
- "
- />
- {
- selected_titles = titles as TitlesTemplate
- }
- "
- />
+
+
+
+
+
+
+
+
diff --git a/app/components/SlideCreateCourseGreen.vue b/app/components/SlideCreateCourseGreen.vue
index d03dced..050a583 100644
--- a/app/components/SlideCreateCourseGreen.vue
+++ b/app/components/SlideCreateCourseGreen.vue
@@ -4,9 +4,7 @@ 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 emit = defineEmits(['success', 'close'])
const toast = useToast()
const loginState = useLoginState()
@@ -100,16 +98,16 @@ const onCreateCourseGreenSubmit = async (
toast.add({
title: '创建成功',
description: '视频已加入生成队列',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
emit('success')
- slide.close()
+ emit('close')
} else {
toast.add({
title: '创建失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
}
@@ -120,7 +118,7 @@ const onCreateCourseGreenSubmit = async (
toast.add({
title: '创建失败',
description: e.message || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
})
@@ -128,174 +126,174 @@ const onCreateCourseGreenSubmit = async (
-
-
-
-
-
- 新建绿幕视频
-
-
-
-
-
-
+
+
-
-
-
+
+
+ 新建绿幕视频
+
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
- {{ selected_digital_human?.name || '点击选择数字人' }}
-
-
- {{ selected_digital_human?.description }}
-
+
+
+
+
+
+ {{ selected_digital_human?.name || '点击选择数字人' }}
+
+
+ {{ selected_digital_human?.description }}
+
+
-
-
-
+
+
-
+ -->
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{
- selected_digital_human = digitalHumans as DigitalHumanItem
- }
- "
- />
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ selected_digital_human = digitalHumans as DigitalHumanItem
+ }
+ "
+ />
+
diff --git a/app/components/aigc/RatioSelector.vue b/app/components/aigc/RatioSelector.vue
index 0fd2b5b..ff079a9 100644
--- a/app/components/aigc/RatioSelector.vue
+++ b/app/components/aigc/RatioSelector.vue
@@ -68,7 +68,7 @@ const getShapeSize = (r: { w: number; h: number }, size: number) => {
:class="[ratio.value === selected && 'bg-sky-200/50 dark:bg-sky-700/50']"
>
-import type { PropType } from 'vue'
-import type { ChatSession } from '~/typings/llm'
-
-const props = defineProps({
- active: {
- type: Boolean,
- default: false,
- },
- chatSession: {
- type: Object as PropType
,
- required: true,
- },
-})
-const emit = defineEmits<{
- (e: 'remove', session: ChatSession): void
-}>()
-
-const dayjs = useDayjs()
-
-
-
-
-
-
-
- {{
- !!chatSession.assistant
- ? chatSession.assistant.tpl_name
- : chatSession.subject
- }}
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/aigc/chat/Message.vue b/app/components/aigc/chat/Message.vue
deleted file mode 100644
index 07f086d..0000000
--- a/app/components/aigc/chat/Message.vue
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/components/aigc/chat/NewSessionScreen.vue b/app/components/aigc/chat/NewSessionScreen.vue
deleted file mode 100644
index 64cffc2..0000000
--- a/app/components/aigc/chat/NewSessionScreen.vue
+++ /dev/null
@@ -1,208 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 返回
-
-
-
-
-
- 选择智能助手
-
-
- 直接开始
-
-
-
-
-
-
-
-
-
-
-
-
{{ assistant.tpl_name }}
-
- {{ assistant.des }}
-
-
-
-
-
-
-
-
-
diff --git a/app/components/aigc/drawing/OptionBlock.vue b/app/components/aigc/drawing/OptionBlock.vue
deleted file mode 100644
index 20d05a9..0000000
--- a/app/components/aigc/drawing/OptionBlock.vue
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
- {{ label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/aigc/drawing/ResultBlock.vue b/app/components/aigc/drawing/ResultBlock.vue
deleted file mode 100644
index d54d11e..0000000
--- a/app/components/aigc/drawing/ResultBlock.vue
+++ /dev/null
@@ -1,303 +0,0 @@
-
-
-
-
-
-
-
- {{ meta.type || 'AI 智能绘图' }}
-
-
-
-
-
-
-
-
-
-
![AI Generated]()
-
-
-
-
-
-
-
-
-
- {{ meta.modal }}
-
-
-
- {{ meta.style }}
-
-
-
- {{ meta.cost }}
-
-
-
- {{ meta.ratio }}
-
-
-
- {{ meta.id }}
-
-
-
- {{ dayjs(meta.datetime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
-
-
-
-
-
-
-
diff --git a/app/components/aigc/drawing/index.d.ts b/app/components/aigc/drawing/index.d.ts
deleted file mode 100644
index 206eda9..0000000
--- a/app/components/aigc/drawing/index.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export declare interface ResultBlockMeta {
- modal?: string
- cost?: string
- ratio?: string
- id?: string
- style?: string
- datetime?: number
- type?: string
-}
diff --git a/app/components/aigc/generation/CGTaskCard.client.vue b/app/components/aigc/generation/CGTaskCard.client.vue
index a651704..130469c 100644
--- a/app/components/aigc/generation/CGTaskCard.client.vue
+++ b/app/components/aigc/generation/CGTaskCard.client.vue
@@ -6,7 +6,6 @@ import gsap from 'gsap'
const toast = useToast()
const loginState = useLoginState()
-const { metaSymbol } = useShortcuts()
const srtEditor = ref()
@@ -59,17 +58,17 @@ const isPreviewModalOpen = ref(false)
const stateDisplay = computed(() => {
if (props.course.progress === -1)
return {
- color: 'red',
+ color: 'error' as const,
text: '失败',
}
if (props.course.progress === 100)
return {
- color: 'green',
+ color: 'success' as const,
text: '完成',
}
return {
- color: 'blue',
- text: !!props.course.progress
+ color: 'info' as const,
+ text: props.course.progress
? `${tweenedGenerateProgress.value.toFixed(0)}%`
: '队列中',
}
@@ -108,7 +107,7 @@ const startDownload = async (url: string, filename: string) => {
toast.add({
title: '下载完成',
description: '资源下载已完成',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
})
@@ -122,7 +121,7 @@ const startDownload = async (url: string, filename: string) => {
toast.add({
title: '下载失败',
description: err.message || '下载失败,未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
})
@@ -137,7 +136,7 @@ const copyTaskId = (extraMessage?: string) => {
toast.add({
title: '复制成功',
description: '已复制任务 ID',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
}
@@ -155,7 +154,7 @@ const onCombination = async () => {
toast.add({
title: '获取字幕失败',
description: '无法获取字幕文件,请稍后重试',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
return
@@ -174,7 +173,7 @@ const onCombination = async () => {
toast.add({
title: '嵌入字幕失败',
description: err.message || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
combinationState.value = 0
@@ -208,7 +207,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
toast.add({
title: '重试已提交',
description: '已加入生成队列',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
// delete
@@ -217,7 +216,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
toast.add({
title: '提交重试失败',
description: res.msg || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
}
@@ -226,7 +225,7 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
toast.add({
title: '提交重试失败',
description: err.message || '未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
}
@@ -236,11 +235,11 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
-
+
{
/>
-
+
{{ stateDisplay.text }}
@@ -283,24 +282,24 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
-
+
{
/>
{{ course.title }}
-
+
{{ dayjs(course.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}
@@ -327,32 +326,15 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
-
+
-
- {
if (isFailed) {
@@ -364,15 +346,18 @@ const onRetryClick = (course: resp.gen.CourseGenItem) => {
"
/>
-
-
+
-
-
-
-
-
-
微课视频预览
-
- {{ course.title }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
微课视频预览
+
+ {{ course.title }}
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
嵌入视频字幕
-
+
+
+
+
+
- {{ course.title }}
-
+
嵌入视频字幕
+
+ {{ course.title }}
+
+
+
-
-
-
-
-
-
-
- {{ step }}
-
-
-
-
- {{ step }}
-
-
-
-
+
+
+
+
+ {{ step }}
+
+
+
+
+
+
+ {{ step }}
+
+
+
+
+
{
toast.add({
title: '文件类型错误',
description: '请选择一个图片文件',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
return
@@ -82,7 +82,7 @@ const composeBackgroundVideo = async () => {
toast.add({
title: '未选择图片',
description: '请先选择一个背景图片',
- color: 'orange',
+ color: 'warning',
icon: 'i-tabler-alert-circle',
})
return
@@ -110,7 +110,7 @@ const composeBackgroundVideo = async () => {
toast.add({
title: '合成成功',
description: '背景已成功合成,可预览或下载',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
} catch (err: any) {
@@ -118,7 +118,7 @@ const composeBackgroundVideo = async () => {
toast.add({
title: '合成失败',
description: combinatorError.value,
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
} finally {
@@ -172,7 +172,7 @@ const startDownload = (url: string, filename: string) => {
toast.add({
title: '下载完成',
description: '资源下载已完成',
- color: 'green',
+ color: 'success',
icon: 'i-tabler-check',
})
})
@@ -186,7 +186,7 @@ const startDownload = (url: string, filename: string) => {
toast.add({
title: '下载失败',
description: err.message || '下载失败,未知错误',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
})
@@ -197,14 +197,14 @@ const startDownload = (url: string, filename: string) => {
-
+
-
-
+
{{ video.title || '无标题' }}
-
-
完成时间
-
+
完成时间
+
{{
video.complete_time
? dayjs(video.complete_time * 1000).format(
@@ -272,8 +272,8 @@ const startDownload = (url: string, filename: string) => {
-
-
生成耗时
-
+
生成耗时
+
{{
video.duration
? dayjs.duration(video.duration || 0).format('HH:mm:ss')
@@ -285,13 +285,13 @@ const startDownload = (url: string, filename: string) => {
class="col-span-2 cursor-pointer"
@click="isFullContentOpen = true"
>
-
驱动文本
- {{ video.content }}
+ 驱动文本
+ {{ video.content }}
@@ -299,7 +299,7 @@ const startDownload = (url: string, filename: string) => {
{{ video.digital_human_id }}
@@ -307,8 +307,8 @@ const startDownload = (url: string, filename: string) => {
{
)
"
/>
-
-
+
-
-
-
-
-
- {{ video.title || '无标题' }}
- 驱动内容
-
-
-
-
-
-
-
- {{ video.content }}
-
-
-
-
-
-
- 关闭
-
-
-
-
-
-
-
-
-
-
-
绿幕视频预览
-
+
+
+
+
+
- {{ video.title }}
-
+ {{ video.title || '无标题' }}
+ 驱动内容
+
+
-
-
-
+
-
-
-
-
-
-
-
-
-
视频背景合成
-
+
+ {{ video.content }}
+
+
+
+
+
+
- {{ video.title }}
-
+ 关闭
+
-
-
-
+
+
+
+
-
-
-
-
-
- 选择背景图片
+
+
+
+
+
+
+
绿幕视频预览
+
+ {{ video.title }}
+
+
+
+
-
-
+
+
+
+ 选择背景图片
+
+
+
+
-
-
+
+
-
-
+
+
-
-
- 已选择: {{ selectedBackgroundFile.name }}
+
+
+ 已选择: {{ selectedBackgroundFile.name }}
+
-
-
-
+
+
-
-
-
-
- {{ phaseText }}
-
-
- {{ compositingProgress }}%
-
+
+
+
+
+ {{ phaseText }}
+
+
+ {{ compositingProgress }}%
+
+
+
-
-
-
-
-
-
-
- {
- selectedBackgroundFile = null
- selectedBackgroundPreview = ''
- compositedVideoBlob = null
- combinatorError = ''
- isCombinatorLoading = false
- }
- "
- />
-
-
-
-
-
+
+
+
+ {
+ selectedBackgroundFile = null
+ selectedBackgroundPreview = ''
+ compositedVideoBlob = null
+ combinatorError = ''
+ isCombinatorLoading = false
+ }
+ "
+ />
+
+
+
+
+
+
diff --git a/app/components/aigc/generation/SRTEditor.vue b/app/components/aigc/generation/SRTEditor.vue
index 4265725..ac42281 100644
--- a/app/components/aigc/generation/SRTEditor.vue
+++ b/app/components/aigc/generation/SRTEditor.vue
@@ -41,7 +41,7 @@ type subtitleStyleSchema = InferType
const subtitleStyleState = reactive({
color: '#fff',
- effect: 'shadow-sm',
+ effect: 'shadow-xs',
fontSize: 24,
bottomOffset: 12,
})
@@ -58,7 +58,7 @@ const loadSrt = async () => {
toast.add({
title: '加载字幕失败',
description: `${err}` || '未知错误',
- color: 'red',
+ color: 'error',
})
} finally {
isLoading.value = false
@@ -79,8 +79,8 @@ const parseSrt = (srt: string) => {
subtitles.value.push(subtitle)
}
subtitle = {
- start: match[1],
- end: match[2],
+ start: match[1] || '',
+ end: match[2] || '',
text: '',
}
} else if (subtitle) {
@@ -105,23 +105,23 @@ const generateSrt = () => {
const formatTime = (time: string) => {
const parts = time.split(',')
- const timeParts = parts[0].split(':')
+ const timeParts = parts[0]?.split(':') || []
return {
- hours: parseInt(timeParts[0]),
- minutes: parseInt(timeParts[1]),
- seconds: parseInt(timeParts[2]),
- milliseconds: parseInt(parts[1]),
+ hours: parseInt(timeParts[0] || '0'),
+ minutes: parseInt(timeParts[1] || '0'),
+ seconds: parseInt(timeParts[2] || '0'),
+ milliseconds: parseInt(parts[1] || '0'),
}
}
const formatTimeToDayjs = (time: string) => {
const parts = time.split(',')
- const timeParts = parts[0].split(':')
+ const timeParts = parts[0]?.split(':') || []
return dayjs()
- .hour(parseInt(timeParts[0]))
- .minute(parseInt(timeParts[1]))
- .second(parseInt(timeParts[2]))
- .millisecond(parseInt(parts[1]))
+ .hour(parseInt(timeParts[0] || '0'))
+ .minute(parseInt(timeParts[1] || '0'))
+ .second(parseInt(timeParts[2] || '0'))
+ .millisecond(parseInt(parts[1] || '0'))
}
const syncSubtitles = () => {
@@ -183,7 +183,7 @@ const saveNewSubtitle = () => {
.then((_) => {
modified.value = false
toast.add({
- color: 'green',
+ color: 'success',
title: '字幕已保存',
description: '修改后的字幕文件已保存',
})
@@ -202,7 +202,7 @@ const exportVideo = async () => {
toast.add({
title: '获取字幕失败',
description: '无法获取字幕文件,请稍后重试',
- color: 'red',
+ color: 'error',
icon: 'i-tabler-alert-triangle',
})
return
@@ -213,7 +213,7 @@ const exportVideo = async () => {
color: subtitleStyleState.color,
fontSize: subtitleStyleState.fontSize,
textShadow:
- subtitleStyleState.effect === 'shadow-sm'
+ subtitleStyleState.effect === 'shadow-xs'
? {
offsetX: 2,
offsetY: 2,
@@ -258,346 +258,349 @@ defineExpose({
-
-
-
-
-
- 字幕编辑器
-
-
- {{ course.title }}
-
-
-
-
-
+
-
-
-