Commit 3cd05182 authored by shirlyn.guo's avatar shirlyn.guo 🤡

Merge branch 'master' of https://gitlab.gsstcloud.com/digitalperson/digitalperson-fe into shirlyn

parents 5c798291 37546bd0
...@@ -14,7 +14,7 @@ pipeline { ...@@ -14,7 +14,7 @@ pipeline {
node -v node -v
pnpm -v pnpm -v
pnpm install pnpm install
pnpm run build pnpm run build:sit
cp -r ./dist ./build cp -r ./dist ./build
''' '''
} }
......
pipeline {
agent {
docker {
image 'cimg/node:18.18.2'
args '-v /root/jenkins/data/jobs/${JOB_NAME}/data/node_modules:${WORKSPACE}/node_modules -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker'
}
}
stages {
stage('BUILD PROJECT') {
steps {
sh '''
npm set registry https://registry.npmmirror.com/
npm install -g pnpm
node -v
pnpm -v
pnpm install
pnpm run build:uat
cp -r ./dist ./build
'''
}
}
stage('BUILD IMAGE') {
steps {
sh '''
cd build
docker build -t $registry_address/$image_name:latest .'''
}
}
stage('PUSH IMAGE') {
steps {
sh '''docker login --username=rcsadmin@gsst -p 9HRpm_hk registry.cn-shenzhen.aliyuncs.com
docker push $registry_address/$image_name:latest'''
}
}
stage('REMOVE LOCAL IMAGE') {
steps {
sh '''docker rmi -f $registry_address/$image_name:latest'''
}
}
stage('Cleanup') {
steps {
cleanWs(deleteDirs: true)
}
}
}
environment {
registry_address = 'registry.cn-shenzhen.aliyuncs.com/gsst'
image_name = 'digitalperson-fe'
}
}
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- <title>DIGITAL_PERSON-FE</title> --> <title>萃想智能雲創</title>
<title>DIGITAL_PERSON_FE</title>
</head> </head>
<body> <body>
......
export const BASE_URLS: Record<'DEV' | 'PROD', string> = { export const BASE_URLS: Record<'DEV' | 'PROD', string> = {
DEV: 'https://digitalperson-sit.gsstcloud.com', DEV: 'https://digitalperson-sit.gsstcloud.com',
PROD: 'https://digitalperson-sit.gsstcloud.com', PROD: 'https://digitalperson.gsstcloud.com',
} }
export const AI_INDEX_URLS: Record<'DEV' | 'PROD', string> = { export const AI_INDEX_URLS: Record<'DEV' | 'PROD', string> = {
......
...@@ -29,8 +29,14 @@ export function createRouterGuards(router: Router) { ...@@ -29,8 +29,14 @@ export function createRouterGuards(router: Router) {
next() next()
}) })
router.afterEach(() => { router.afterEach((to) => {
document.title = import.meta.env.VITE_APP_NAME let title = import.meta.env.VITE_APP_NAME
if (to.meta.title) {
title += ` - ${to.meta.title}`
}
document.title = title
window.$loadingBar.finish() window.$loadingBar.finish()
}) })
......
import { AudioConfig, LangType, VoiceType } from '@/store/types/creation' import { AudioConfig, VoiceType } from '@/store/types/creation'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
function defaultAudioSetting(): AudioConfig { function defaultAudioSetting(): AudioConfig {
return { return {
langType: LangType.CANTONESE,
voiceType: VoiceType.CANTONESE_FEMALE, voiceType: VoiceType.CANTONESE_FEMALE,
consumption: 0, consumption: 0,
} }
...@@ -17,10 +16,6 @@ export const useAudioSettingStore = defineStore('audio-setting-store', { ...@@ -17,10 +16,6 @@ export const useAudioSettingStore = defineStore('audio-setting-store', {
state: (): AudioConfig => getLocalState(), state: (): AudioConfig => getLocalState(),
actions: { actions: {
setLanType(langType: LangType) {
this.langType = langType
},
setVoiceType(voiceType: VoiceType) { setVoiceType(voiceType: VoiceType) {
this.voiceType = voiceType this.voiceType = voiceType
}, },
......
import { DraftConfig, LangType } from '@/store/types/creation' import { DraftConfig, LangType, ScreenType } from '@/store/types/creation'
import { DriveType, TaskType } from '@/store/types/template' import { DriveType, TaskType } from '@/store/types/template'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
...@@ -7,6 +7,7 @@ function defaultDigitalCreation(): DraftConfig { ...@@ -7,6 +7,7 @@ function defaultDigitalCreation(): DraftConfig {
id: null, id: null,
coverUrl: null, coverUrl: null,
draftName: '', draftName: '',
pronunciationLanguage: LangType.CANTONESE,
taskType: TaskType.BASE_VIDEO, taskType: TaskType.BASE_VIDEO,
inputImageUrl: null, inputImageUrl: null,
driveType: DriveType.TEXT, driveType: DriveType.TEXT,
...@@ -17,6 +18,7 @@ function defaultDigitalCreation(): DraftConfig { ...@@ -17,6 +18,7 @@ function defaultDigitalCreation(): DraftConfig {
pitch: '5', pitch: '5',
inputAudioUrl: null, inputAudioUrl: null,
figureId: null, figureId: null,
pageLayout: ScreenType.PORTRAIT,
width: 720, width: 720,
height: 1280, height: 1280,
cameraId: null, cameraId: null,
...@@ -34,7 +36,6 @@ function defaultDigitalCreation(): DraftConfig { ...@@ -34,7 +36,6 @@ function defaultDigitalCreation(): DraftConfig {
logoUrl: null, logoUrl: null,
bgmUrl: null, bgmUrl: null,
materialUrl: null, materialUrl: null,
pronunciationLanguage: LangType.CANTONESE,
} }
} }
...@@ -114,7 +115,11 @@ export const useDigitalCreationStore = defineStore('digital-creation-store', { ...@@ -114,7 +115,11 @@ export const useDigitalCreationStore = defineStore('digital-creation-store', {
this.enabled = subtitleEnabled this.enabled = subtitleEnabled
}, },
updateDigitalCreation(digitalCreation: DraftConfig) { setPronunciationLanguage(pronunciationLanguage: LangType) {
this.pronunciationLanguage = pronunciationLanguage
},
updateDigitalCreation(digitalCreation: Partial<DraftConfig>) {
this.$state = { ...this.$state, ...digitalCreation } this.$state = { ...this.$state, ...digitalCreation }
}, },
......
...@@ -14,7 +14,7 @@ export function defaultDigitalHumanDialogue(): DigitalHumanDialogueConfig { ...@@ -14,7 +14,7 @@ export function defaultDigitalHumanDialogue(): DigitalHumanDialogueConfig {
figureId: 'A2A_V2-xiaomeng2', figureId: 'A2A_V2-xiaomeng2',
speed: 5, speed: 5,
intonation: 5, intonation: 5,
timebreId: '5132', timebreId: '101019',
}, },
backgroundInfo: { backgroundInfo: {
backgroundUrl: 'https://digitalpeople-sit.gz.bcebos.com/share/backgroud/%E5%8C%BB%E5%AD%A61.jpg', backgroundUrl: 'https://digitalpeople-sit.gz.bcebos.com/share/backgroud/%E5%8C%BB%E5%AD%A61.jpg',
......
...@@ -28,7 +28,6 @@ export enum VoiceType { ...@@ -28,7 +28,6 @@ export enum VoiceType {
} }
export interface AudioConfig { export interface AudioConfig {
langType: LangType
voiceType: VoiceType voiceType: VoiceType
consumption: number consumption: number
} }
...@@ -73,6 +72,7 @@ export interface DraftConfig { ...@@ -73,6 +72,7 @@ export interface DraftConfig {
id: number | null id: number | null
coverUrl: string | null coverUrl: string | null
draftName: string draftName: string
pronunciationLanguage: LangType
taskType: TaskType taskType: TaskType
inputImageUrl: string | null inputImageUrl: string | null
driveType: DriveType driveType: DriveType
...@@ -83,6 +83,7 @@ export interface DraftConfig { ...@@ -83,6 +83,7 @@ export interface DraftConfig {
pitch: string pitch: string
inputAudioUrl: string | null inputAudioUrl: string | null
figureId: string | null figureId: string | null
pageLayout: ScreenType
width: number width: number
height: number height: number
cameraId: number | null cameraId: number | null
...@@ -100,7 +101,6 @@ export interface DraftConfig { ...@@ -100,7 +101,6 @@ export interface DraftConfig {
logoUrl: string | null logoUrl: string | null
bgmUrl: string | null bgmUrl: string | null
materialUrl: string | null materialUrl: string | null
pronunciationLanguage: LangType
memberId?: number memberId?: number
modifiedTime?: string modifiedTime?: string
} }
......
...@@ -168,11 +168,16 @@ function onImageLoaded(index: number) { ...@@ -168,11 +168,16 @@ function onImageLoaded(index: number) {
@click="handleClickImage(image)" @click="handleClickImage(image)"
> >
<img class="h-full w-full object-contain" :src="image.imageUrl" @load="onImageLoaded(index)" /> <img class="h-full w-full object-contain" :src="image.imageUrl" @load="onImageLoaded(index)" />
<n-popover trigger="hover" placement="bottom">
<template #trigger>
<div <div
class="absolute bottom-0 h-5 w-full truncate bg-gradient-to-t from-gray-600 px-1 text-xs leading-5 text-white" class="absolute bottom-0 line-clamp-1 h-5 w-full break-all bg-gradient-to-t from-gray-600 px-1 text-xs leading-5 text-white"
> >
{{ image.imageName }} {{ image.imageName }}
</div> </div>
</template>
<span class="text-xs">{{ image.imageName }}</span>
</n-popover>
<div <div
v-if="currentBackgroundImageType === BackgroundImageType.PERSON" v-if="currentBackgroundImageType === BackgroundImageType.PERSON"
class="absolute right-1 top-1 hidden h-7 w-7 cursor-pointer items-center justify-center rounded-md bg-black/40 p-1 group-hover:flex" class="absolute right-1 top-1 hidden h-7 w-7 cursor-pointer items-center justify-center rounded-md bg-black/40 p-1 group-hover:flex"
...@@ -180,6 +185,11 @@ function onImageLoaded(index: number) { ...@@ -180,6 +185,11 @@ function onImageLoaded(index: number) {
> >
<CustomIcon icon="mi:delete" class="text-lg text-white" /> <CustomIcon icon="mi:delete" class="text-lg text-white" />
</div> </div>
<CustomIcon
v-if="digitalCreationStore.backgroundImageUrl === image.imageUrl"
icon="si-glyph:checked"
class="text-blue absolute left-0 top-0 text-xs"
/>
</div> </div>
</n-spin> </n-spin>
</n-gi> </n-gi>
......
...@@ -4,7 +4,7 @@ import CustomModal from '@/components/custom-modal/custom-modal.vue' ...@@ -4,7 +4,7 @@ import CustomModal from '@/components/custom-modal/custom-modal.vue'
import { ScreenType } from '@/store/types/creation' import { ScreenType } from '@/store/types/creation'
import { formatDateTime } from '@/utils/date-formatter' import { formatDateTime } from '@/utils/date-formatter'
import { FormInst } from 'naive-ui' import { FormInst } from 'naive-ui'
import { computed, reactive, ref } from 'vue' import { computed, reactive, ref, watch } from 'vue'
interface Props { interface Props {
isShowModal: boolean isShowModal: boolean
...@@ -51,6 +51,16 @@ const showModal = computed({ ...@@ -51,6 +51,16 @@ const showModal = computed({
}, },
}) })
watch(
() => showModal.value,
(newValue) => {
if (newValue) {
digitalHumanVideoFormData.title = '新建數字人視頻' + formatDateTime(new Date())
digitalHumanVideoFormData.pageLayout = ScreenType.PORTRAIT
}
},
)
function handleUpdatePageLayout(pageLayout: ScreenType) { function handleUpdatePageLayout(pageLayout: ScreenType) {
digitalHumanVideoFormData.pageLayout = pageLayout digitalHumanVideoFormData.pageLayout = pageLayout
} }
......
<script setup lang="ts"> <script setup lang="ts">
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { TimbreItem } from '@/store/types/creation' import { TimbreItem } from '@/store/types/creation'
import { computed, ref } from 'vue' import { computed } from 'vue'
interface Props { interface Props {
value?: TimbreItem value?: TimbreItem
...@@ -11,19 +11,15 @@ interface Props { ...@@ -11,19 +11,15 @@ interface Props {
interface Emits { interface Emits {
(e: 'click', value: TimbreItem): void (e: 'click', value: TimbreItem): void
(e: 'toggle', value: boolean): void (e: 'toggle', value: boolean): void
(e: 'play', value: string): void
} }
defineProps<Props>() defineProps<Props>()
const emit = defineEmits<Emits>() const emit = defineEmits<Emits>()
const digitalCreationStore = useDigitalCreationStore() const digitalCreationStore = useDigitalCreationStore()
const digitalAudio = ref<HTMLAudioElement>()
const person = computed(() => digitalCreationStore.person) const person = computed(() => digitalCreationStore.person)
function playAudio() {
digitalAudio.value?.play()
}
</script> </script>
<template> <template>
...@@ -39,7 +35,11 @@ function playAudio() { ...@@ -39,7 +35,11 @@ function playAudio() {
<div class="flex-1 overflow-hidden"> <div class="flex-1 overflow-hidden">
<div class="mb-2 flex items-center gap-2"> <div class="mb-2 flex items-center gap-2">
<div class="max-w-32 truncate">{{ value?.name }}</div> <div class="max-w-32 truncate">{{ value?.name }}</div>
<CustomIcon class="cursor-pointer text-lg" icon="mingcute:volume-line" @click.stop.prevent="playAudio" /> <CustomIcon
class="cursor-pointer text-lg"
icon="mingcute:volume-line"
@click.stop.prevent="emit('play', value!.audioUrl)"
/>
</div> </div>
<div class="flex gap-1"> <div class="flex gap-1">
<n-tag v-for="(style, index) in value?.style" :key="index" type="warning" size="tiny" round>{{ style }}</n-tag> <n-tag v-for="(style, index) in value?.style" :key="index" type="warning" size="tiny" round>{{ style }}</n-tag>
...@@ -49,6 +49,4 @@ function playAudio() { ...@@ -49,6 +49,4 @@ function playAudio() {
<CustomIcon class="cursor-pointer text-lg" icon="ant-design:swap-outlined" @click="emit('toggle', true)" /> <CustomIcon class="cursor-pointer text-lg" icon="ant-design:swap-outlined" @click="emit('toggle', true)" />
</div> </div>
</div> </div>
<audio ref="digitalAudio" :src="value?.audioUrl"></audio>
</template> </template>
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
import { fetchDigitalHumanTimbreList, fetchTimbreByExample } from '@/apis/digital-creation' import { fetchDigitalHumanTimbreList, fetchTimbreByExample } from '@/apis/digital-creation'
import { useAudioSettingStore } from '@/store/modules/audio-setting' import { useAudioSettingStore } from '@/store/modules/audio-setting'
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { LangType, TimbreItem, VoiceType } from '@/store/types/creation' import { LangType, TimbreItem, VoiceType } from '@/store/types/creation'
import { computed, onMounted, ref, watch } from 'vue' import { computed, nextTick, onMounted, ref, watch } from 'vue'
import DigitalAudioCard from './digital-audio-card.vue' import DigitalAudioCard from './digital-audio-card.vue'
const audioSettingStore = useAudioSettingStore() const audioSettingStore = useAudioSettingStore()
...@@ -36,15 +35,17 @@ const digitalTimbreValue = ref<TimbreItem>() ...@@ -36,15 +35,17 @@ const digitalTimbreValue = ref<TimbreItem>()
const digitalTimbreList = ref<TimbreItem[]>([]) const digitalTimbreList = ref<TimbreItem[]>([])
const digitalTimbreFemaleList = ref<TimbreItem[]>([]) const digitalTimbreFemaleList = ref<TimbreItem[]>([])
const digitalTimbreMaleList = ref<TimbreItem[]>([]) const digitalTimbreMaleList = ref<TimbreItem[]>([])
const showAll = ref(false) const digitalAudio = ref<HTMLAudioElement>()
const audioSrc = ref('')
const searchName = ref('') const searchName = ref('')
const showAll = ref(false)
const langType = computed({ const langType = computed({
get() { get() {
return audioSettingStore.langType return digitalCreationStore.pronunciationLanguage
}, },
set(value) { set(value) {
audioSettingStore.setLanType(value) digitalCreationStore.setPronunciationLanguage(value)
}, },
}) })
...@@ -84,6 +85,7 @@ watch( ...@@ -84,6 +85,7 @@ watch(
langType.value = LangType.MANDARIN langType.value = LangType.MANDARIN
} else { } else {
digitalTimbreValue.value = digitalTimbreList.value[0] digitalTimbreValue.value = digitalTimbreList.value[0]
langType.value = LangType.CANTONESE
} }
} }
}, },
...@@ -92,14 +94,15 @@ watch( ...@@ -92,14 +94,15 @@ watch(
watch( watch(
() => langType.value, () => langType.value,
(newVal) => { (newVal) => {
digitalCreationStore.setInputAudioUrl('')
if (newVal === LangType.CANTONESE) { if (newVal === LangType.CANTONESE) {
digitalCreationStore.setPerson('')
audioSettingStore.setVoiceType(VoiceType.CANTONESE_FEMALE) audioSettingStore.setVoiceType(VoiceType.CANTONESE_FEMALE)
} else { } else {
if (digitalTimbreValue.value?.sex === '男') { digitalCreationStore.setPerson(digitalTimbreValue.value?.timebreId || '')
audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE) audioSettingStore.setVoiceType(
} else { digitalTimbreValue.value?.sex === '男' ? VoiceType.MANDARIN_MALE : VoiceType.MANDARIN_FEMALE,
audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE) )
}
} }
}, },
) )
...@@ -133,6 +136,14 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -133,6 +136,14 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
? audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE) ? audioSettingStore.setVoiceType(VoiceType.MANDARIN_MALE)
: audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE) : audioSettingStore.setVoiceType(VoiceType.MANDARIN_FEMALE)
} }
function playAudio(audioUrl: string) {
audioSrc.value && digitalAudio.value?.pause()
audioSrc.value = audioUrl
nextTick(() => {
digitalAudio.value?.play()
})
}
</script> </script>
<template> <template>
...@@ -153,6 +164,7 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -153,6 +164,7 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
:value="digitalTimbreValue" :value="digitalTimbreValue"
show-toggle show-toggle
@toggle="showAll = true" @toggle="showAll = true"
@play="playAudio"
/> />
<div class="mt-4 text-lg">聲音</div> <div class="mt-4 text-lg">聲音</div>
...@@ -198,8 +210,11 @@ function handleClickAudioCard(timbreItem: TimbreItem) { ...@@ -198,8 +210,11 @@ function handleClickAudioCard(timbreItem: TimbreItem) {
:key="index" :key="index"
:value="timbre" :value="timbre"
@click="handleClickAudioCard" @click="handleClickAudioCard"
@play="playAudio"
/> />
</div> </div>
</div> </div>
<audio ref="digitalAudio" :src="audioSrc"></audio>
</div> </div>
</template> </template>
...@@ -57,15 +57,15 @@ const digitalImagePositionH = computed({ ...@@ -57,15 +57,15 @@ const digitalImagePositionH = computed({
</n-input-number> </n-input-number>
</div> </div>
<div class="mt-4 flex"> <div class="mt-4 flex">
<n-input-number v-model:value="digitalImagePositionW" class="flex-1"> <n-input v-model:value="digitalImagePositionW" readonly class="flex-1">
<template #prefix><div class="text-gray w-4 text-center text-xs">W</div></template> <template #prefix><div class="text-gray w-4 text-center text-xs">W</div></template>
</n-input-number> </n-input>
<div class="flex w-4 items-center justify-center"> <div class="flex w-4 items-center justify-center">
<CustomIcon class="text-gray text-xs" icon="fa6-solid:lock" /> <CustomIcon class="text-gray text-xs" icon="fa6-solid:lock" />
</div> </div>
<n-input-number v-model:value="digitalImagePositionH" class="flex-1"> <n-input v-model:value="digitalImagePositionH" readonly class="flex-1">
<template #prefix><div class="text-gray w-4 text-center text-xs">H</div></template> <template #prefix><div class="text-gray w-4 text-center text-xs">H</div></template>
</n-input-number> </n-input>
</div> </div>
</div> </div>
</template> </template>
...@@ -15,6 +15,7 @@ const audioPlaying = ref(false) ...@@ -15,6 +15,7 @@ const audioPlaying = ref(false)
const previewContentWidth = ref(0) const previewContentWidth = ref(0)
const previewContentHeight = ref(0) const previewContentHeight = ref(0)
const previewContent = ref<HTMLElement>() const previewContent = ref<HTMLElement>()
const digitalHumanImage = ref<HTMLImageElement>()
const digitalAudio = ref<HTMLAudioElement>() const digitalAudio = ref<HTMLAudioElement>()
const audioSetting = ref<AudioSetting>({ const audioSetting = ref<AudioSetting>({
codec: 'mp3', codec: 'mp3',
...@@ -31,7 +32,7 @@ const ttsSpeedMarks: { [speed: string]: number } = { ...@@ -31,7 +32,7 @@ const ttsSpeedMarks: { [speed: string]: number } = {
'4': -0.8, '4': -0.8,
'5': -0.5, '5': -0.5,
'6': 0, '6': 0,
'7': 1, '7': 0.8,
} }
const resizeObserver = new ResizeObserver((entries) => { const resizeObserver = new ResizeObserver((entries) => {
...@@ -42,12 +43,6 @@ const resizeObserver = new ResizeObserver((entries) => { ...@@ -42,12 +43,6 @@ const resizeObserver = new ResizeObserver((entries) => {
const isLandscape = computed(() => digitalCreationStore.width > digitalCreationStore.height) const isLandscape = computed(() => digitalCreationStore.width > digitalCreationStore.height)
// const digitalHumanWidth = computed(
// () => (digitalCreationStore.w * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080),
// )
const digitalHumanHeight = computed(
() => (digitalCreationStore.h * previewContentHeight.value) / (isLandscape.value ? 1080 : 1920),
)
const digitalHumanLeft = computed( const digitalHumanLeft = computed(
() => (digitalCreationStore.x * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080), () => (digitalCreationStore.x * previewContentWidth.value) / (isLandscape.value ? 1920 : 1080),
) )
...@@ -128,7 +123,7 @@ function controlAudio() { ...@@ -128,7 +123,7 @@ function controlAudio() {
audioSetting.value.voiceType !== audioSettingStore.voiceType || audioSetting.value.voiceType !== audioSettingStore.voiceType ||
audioSetting.value.speed !== ttsSpeedMarks[digitalCreationStore.speed] || audioSetting.value.speed !== ttsSpeedMarks[digitalCreationStore.speed] ||
audioSetting.value.volume !== Number(digitalCreationStore.volume) || audioSetting.value.volume !== Number(digitalCreationStore.volume) ||
(audioSettingStore.langType === LangType.MANDARIN && (digitalCreationStore.pronunciationLanguage === LangType.MANDARIN &&
audioSetting.value.pitch !== Number(digitalCreationStore.pitch)) audioSetting.value.pitch !== Number(digitalCreationStore.pitch))
) { ) {
audioData.value = '' audioData.value = ''
...@@ -156,12 +151,11 @@ function controlAudio() { ...@@ -156,12 +151,11 @@ function controlAudio() {
/> />
<img <img
v-if="digitalCreationStore.inputImageUrl" v-if="digitalCreationStore.inputImageUrl"
ref="digitalHumanImage"
:src="digitalCreationStore.inputImageUrl" :src="digitalCreationStore.inputImageUrl"
class="absolute max-w-none object-cover" class="absolute h-full max-w-none -translate-x-1/2 object-cover"
:style="{ :style="{
// width: `${digitalHumanWidth}px`, left: `calc(50% + ${digitalHumanLeft}px)`,
height: `${digitalHumanHeight}px`,
left: `${digitalHumanLeft}px`,
top: `${digitalHumanTop}px`, top: `${digitalHumanTop}px`,
}" }"
/> />
......
...@@ -26,3 +26,10 @@ const text = computed({ ...@@ -26,3 +26,10 @@ const text = computed({
/> />
</div> </div>
</template> </template>
<style lang="scss" scoped>
:deep(.n-input.n-input--textarea .n-input-word-count) {
right: 0;
bottom: -20px;
}
</style>
...@@ -106,7 +106,7 @@ async function saveDraft(autoSave: boolean = true) { ...@@ -106,7 +106,7 @@ async function saveDraft(autoSave: boolean = true) {
const res = await saveDraftConfig<DraftConfig>(payload) const res = await saveDraftConfig<DraftConfig>(payload)
if (res.code === 0) { if (res.code === 0) {
autoSave ? (autoSaveSuccess.value = true) : window.$message.success('保存成功') autoSave ? (autoSaveSuccess.value = true) : window.$message.success('保存成功')
digitalCreationStore.updateDigitalCreation(res.data) digitalCreationStore.updateDigitalCreation({ id: res.data.id })
const temp: DraftConfig = { ...res.data, modifiedTime: '' } const temp: DraftConfig = { ...res.data, modifiedTime: '' }
savedConfig.value = temp savedConfig.value = temp
} }
...@@ -125,7 +125,7 @@ function confirmExport() { ...@@ -125,7 +125,7 @@ function confirmExport() {
window.$message.error('請輸入視頻名稱') window.$message.error('請輸入視頻名稱')
return false return false
} }
if (!userCurrency.value) { if (userCurrency.value < consumption.value) {
window.$message.error('餘額不足') window.$message.error('餘額不足')
return false return false
} }
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
import { fetchDraftConfigById } from '@/apis/digital-creation' import { fetchDraftConfigById } from '@/apis/digital-creation'
import { fetchGetTaskConfig } from '@/apis/opus' import { fetchGetTaskConfig } from '@/apis/opus'
import { fetchDigitalHumanTemplateStatus } from '@/apis/template' import { fetchDigitalHumanTemplateStatus } from '@/apis/template'
import { useAudioSettingStore } from '@/store/modules/audio-setting'
import { useDigitalCreationStore } from '@/store/modules/creation' import { useDigitalCreationStore } from '@/store/modules/creation'
import { DraftConfig, ScreenType } from '@/store/types/creation' import { DraftConfig, LangType, ScreenType, VoiceType } from '@/store/types/creation'
import { DigitalTemplate } from '@/store/types/template' import { DigitalTemplate } from '@/store/types/template'
import { formatDateTime } from '@/utils/date-formatter' import { formatDateTime } from '@/utils/date-formatter'
import { onMounted } from 'vue' import { onMounted } from 'vue'
...@@ -19,6 +20,7 @@ interface Props { ...@@ -19,6 +20,7 @@ interface Props {
const props = defineProps<Props>() const props = defineProps<Props>()
const audioSettingStore = useAudioSettingStore()
const digitalCreationStore = useDigitalCreationStore() const digitalCreationStore = useDigitalCreationStore()
onMounted(() => { onMounted(() => {
...@@ -39,6 +41,7 @@ async function getDigitalTemplate(id: string) { ...@@ -39,6 +41,7 @@ async function getDigitalTemplate(id: string) {
id: null, id: null,
coverUrl: digitalTemplate.coverUrl, coverUrl: digitalTemplate.coverUrl,
draftName: '新建數字人視頻' + formatDateTime(new Date()), draftName: '新建數字人視頻' + formatDateTime(new Date()),
pronunciationLanguage: digitalTemplate.ttsParams?.person ? LangType.MANDARIN : LangType.CANTONESE,
taskType: digitalTemplate.taskType, taskType: digitalTemplate.taskType,
inputImageUrl: digitalTemplate.digitalHumanImageUrl, inputImageUrl: digitalTemplate.digitalHumanImageUrl,
driveType: digitalTemplate.driveType, driveType: digitalTemplate.driveType,
...@@ -49,8 +52,13 @@ async function getDigitalTemplate(id: string) { ...@@ -49,8 +52,13 @@ async function getDigitalTemplate(id: string) {
pitch: digitalTemplate.ttsParams?.pitch || digitalCreationStore.pitch, pitch: digitalTemplate.ttsParams?.pitch || digitalCreationStore.pitch,
inputAudioUrl: digitalTemplate.inputAudioUrl, inputAudioUrl: digitalTemplate.inputAudioUrl,
figureId: digitalTemplate.figureId, figureId: digitalTemplate.figureId,
width: digitalTemplate.videoParams?.width || digitalCreationStore.width, pageLayout: digitalTemplate.videoParams?.pageLayout || digitalCreationStore.pageLayout,
height: digitalTemplate.videoParams?.height || digitalCreationStore.height, width:
digitalTemplate.videoParams?.width ||
(digitalTemplate.videoParams?.pageLayout === ScreenType.LANDSCAPE ? 1280 : 720),
height:
digitalTemplate.videoParams?.height ||
(digitalTemplate.videoParams?.pageLayout === ScreenType.LANDSCAPE ? 720 : 1280),
cameraId: digitalTemplate.dhParams?.cameraId || null, cameraId: digitalTemplate.dhParams?.cameraId || null,
x: digitalTemplate.dhParams?.position.x || digitalCreationStore.x, x: digitalTemplate.dhParams?.position.x || digitalCreationStore.x,
w: w:
...@@ -70,9 +78,9 @@ async function getDigitalTemplate(id: string) { ...@@ -70,9 +78,9 @@ async function getDigitalTemplate(id: string) {
logoUrl: digitalTemplate.logoParams?.logoUrl || null, logoUrl: digitalTemplate.logoParams?.logoUrl || null,
bgmUrl: digitalTemplate.bgmParams?.bgmUrl || null, bgmUrl: digitalTemplate.bgmParams?.bgmUrl || null,
materialUrl: digitalTemplate.materialUrl, materialUrl: digitalTemplate.materialUrl,
pronunciationLanguage: digitalCreationStore.pronunciationLanguage,
} }
digitalCreationStore.updateDigitalCreation(draftConfig) digitalCreationStore.updateDigitalCreation(draftConfig)
audioSettingStore.setVoiceType(draftConfig.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
...@@ -80,16 +88,49 @@ async function getDraft(id: string) { ...@@ -80,16 +88,49 @@ async function getDraft(id: string) {
const res = await fetchDraftConfigById<DraftConfig>(id) const res = await fetchDraftConfigById<DraftConfig>(id)
if (res.code === 0) { if (res.code === 0) {
digitalCreationStore.updateDigitalCreation(res.data) digitalCreationStore.updateDigitalCreation(res.data)
audioSettingStore.setVoiceType(res.data.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
async function getTaskConfig(id: string) { async function getTaskConfig(id: string) {
const res = await fetchGetTaskConfig<DraftConfig>(id) const res = await fetchGetTaskConfig<DraftConfig>(id)
if (res.code === 0) { if (res.code === 0) {
digitalCreationStore.updateDigitalCreation({ const draftConfig: DraftConfig = {
...res.data, id: null,
draftName: '新建數字人視頻' + formatDateTime(new Date()), draftName: '新建數字人視頻' + formatDateTime(new Date()),
}) pronunciationLanguage: res.data.person ? LangType.MANDARIN : LangType.CANTONESE,
pageLayout: res.data.pageLayout || digitalCreationStore.pageLayout,
width: res.data.width || (res.data.pageLayout === ScreenType.LANDSCAPE ? 1280 : 720),
height: res.data.height || (res.data.pageLayout === ScreenType.LANDSCAPE ? 720 : 1280),
w: res.data.w || (res.data.pageLayout === ScreenType.LANDSCAPE ? 607 : 1080),
h: res.data.h || (res.data.pageLayout === ScreenType.LANDSCAPE ? 1080 : 1920),
coverUrl: res.data.coverUrl || digitalCreationStore.coverUrl,
taskType: res.data.taskType || digitalCreationStore.taskType,
inputImageUrl: res.data.inputImageUrl || digitalCreationStore.inputImageUrl,
driveType: res.data.driveType || digitalCreationStore.driveType,
text: res.data.text || digitalCreationStore.text,
person: res.data.person || digitalCreationStore.person,
speed: res.data.speed || digitalCreationStore.speed,
volume: res.data.volume || digitalCreationStore.volume,
pitch: res.data.pitch || digitalCreationStore.pitch,
inputAudioUrl: res.data.inputAudioUrl || digitalCreationStore.inputAudioUrl,
figureId: res.data.figureId || digitalCreationStore.figureId,
cameraId: res.data.cameraId || digitalCreationStore.cameraId,
x: res.data.x || digitalCreationStore.x,
y: res.data.y || digitalCreationStore.y,
subtitlePolicy: res.data.subtitlePolicy || digitalCreationStore.subtitlePolicy,
enabled: res.data.enabled || digitalCreationStore.enabled,
backgroundImageUrl: res.data.backgroundImageUrl || digitalCreationStore.backgroundImageUrl,
autoAnimoji: res.data.autoAnimoji || digitalCreationStore.autoAnimoji,
enablePalindrome: res.data.enablePalindrome || digitalCreationStore.enablePalindrome,
templateId: res.data.templateId || digitalCreationStore.templateId,
title: res.data.title || digitalCreationStore.title,
logoUrl: res.data.logoUrl || digitalCreationStore.logoUrl,
bgmUrl: res.data.bgmUrl || digitalCreationStore.bgmUrl,
materialUrl: res.data.materialUrl || digitalCreationStore.materialUrl,
}
digitalCreationStore.updateDigitalCreation(draftConfig)
audioSettingStore.setVoiceType(draftConfig.person ? VoiceType.MANDARIN_FEMALE : VoiceType.CANTONESE_FEMALE)
} }
} }
</script> </script>
......
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, ref } from 'vue' import { computed, reactive, ref, watch } from 'vue'
import { FormInst } from 'naive-ui' import { FormInst } from 'naive-ui'
import CustomModal from '@/components/custom-modal/custom-modal.vue' import CustomModal from '@/components/custom-modal/custom-modal.vue'
import CustomIcon from '@/components/custom-icon/custom-icon.vue' import CustomIcon from '@/components/custom-icon/custom-icon.vue'
...@@ -50,6 +50,16 @@ const showModal = computed({ ...@@ -50,6 +50,16 @@ const showModal = computed({
}, },
}) })
watch(
() => showModal.value,
(newValue) => {
if (newValue) {
digitalHumanDialogueFormData.title = '新建對話' + formatDateTime(new Date())
digitalHumanDialogueFormData.pageLayout = 'vertical'
}
},
)
function handleUpdatePageLayout(pageLayout: 'vertical' | 'horizontal') { function handleUpdatePageLayout(pageLayout: 'vertical' | 'horizontal') {
digitalHumanDialogueFormData.pageLayout = pageLayout digitalHumanDialogueFormData.pageLayout = pageLayout
} }
......
...@@ -21,7 +21,7 @@ const speedMarks: { [speed: number]: string } = { ...@@ -21,7 +21,7 @@ const speedMarks: { [speed: number]: string } = {
7: '1.5x', 7: '1.5x',
} }
const currentSelectedAudioType = ref('mandarin') const currentSelectedAudioType = ref('cantonese')
const audioTypeList = [ const audioTypeList = [
{ label: '語言:普通話', value: 'mandarin', style: { fontSize: '12px' } }, { label: '語言:普通話', value: 'mandarin', style: { fontSize: '12px' } },
......
...@@ -31,7 +31,7 @@ const figureId = computed(() => { ...@@ -31,7 +31,7 @@ const figureId = computed(() => {
:class="figureId === imageItem.figureId ? 'border-blue' : 'border-transparent'" :class="figureId === imageItem.figureId ? 'border-blue' : 'border-transparent'"
@click="emit('click', imageItem.figureId as string)" @click="emit('click', imageItem.figureId as string)"
> >
<img :src="imageItem.imageUrl" class="h-full w-full" @load="imageLoading = false" /> <img :src="imageItem.imageUrl" class="h-full w-full object-cover" @load="imageLoading = false" />
<div class="absolute bottom-0 h-5 w-full bg-gradient-to-t from-gray-600 px-1 text-xs leading-5 text-white"> <div class="absolute bottom-0 h-5 w-full bg-gradient-to-t from-gray-600 px-1 text-xs leading-5 text-white">
{{ imageItem.imageName }} {{ imageItem.imageName }}
</div> </div>
......
...@@ -37,7 +37,9 @@ async function handleGetInfoByFigureId(figureId: string) { ...@@ -37,7 +37,9 @@ async function handleGetInfoByFigureId(figureId: string) {
</script> </script>
<template> <template>
<div class="relative h-[calc(100%-190px)] w-[calc(100%-32px)] overflow-hidden rounded-2xl bg-white"> <div
class="relative mx-4 my-[45px] aspect-[16/9] h-full max-w-full overflow-hidden rounded-2xl bg-white xl:my-[60px] 2xl:my-[85px]"
>
<div <div
v-if="isEmptyPreview" v-if="isEmptyPreview"
class="flex h-full w-full select-none items-center justify-center text-xs text-[#84868c]" class="flex h-full w-full select-none items-center justify-center text-xs text-[#84868c]"
...@@ -52,8 +54,11 @@ async function handleGetInfoByFigureId(figureId: string) { ...@@ -52,8 +54,11 @@ async function handleGetInfoByFigureId(figureId: string) {
class="absolute left-0 top-0 h-full w-full object-cover" class="absolute left-0 top-0 h-full w-full object-cover"
/> />
<div class="absolute bottom-0 right-[5%] w-[320px]"> <img
<img v-show="figureImageUrl" :src="figureImageUrl" alt="數字人" class="h-full w-full" /> v-show="figureImageUrl"
</div> :src="figureImageUrl"
alt="數字人"
class="absolute bottom-0 right-[10%] aspect-[9/16] h-[80%] object-cover"
/>
</div> </div>
</template> </template>
...@@ -21,7 +21,9 @@ const props = defineProps<Props>() ...@@ -21,7 +21,9 @@ const props = defineProps<Props>()
const emit = defineEmits<Emits>() const emit = defineEmits<Emits>()
const shareLink = computed(() => { const shareLink = computed(() => {
return `${AI_INDEX_URLS[window.ENV || 'DEV']}digital-work-preview/${props.configId}` const ENV = import.meta.env.VITE_APP_ENV
return `${AI_INDEX_URLS[ENV]}digital-work-preview/${props.configId}`
}) })
const showModal = computed({ const showModal = computed({
......
...@@ -11,14 +11,6 @@ const figureId = computed(() => { ...@@ -11,14 +11,6 @@ const figureId = computed(() => {
return digitalHumanDialogueStore.humanInfo.figureId return digitalHumanDialogueStore.humanInfo.figureId
}) })
watch(
() => figureId.value,
(newValue) => {
newValue && handleGetInfoByFigureId(newValue)
},
{ immediate: true },
)
const backgroundImageUrl = computed(() => { const backgroundImageUrl = computed(() => {
return digitalHumanDialogueStore.backgroundInfo.backgroundUrl return digitalHumanDialogueStore.backgroundInfo.backgroundUrl
}) })
...@@ -27,6 +19,14 @@ const isEmptyPreview = computed(() => { ...@@ -27,6 +19,14 @@ const isEmptyPreview = computed(() => {
return !figureImageUrl.value && !backgroundImageUrl.value return !figureImageUrl.value && !backgroundImageUrl.value
}) })
watch(
() => figureId.value,
(newValue) => {
newValue && handleGetInfoByFigureId(newValue)
},
{ immediate: true },
)
async function handleGetInfoByFigureId(figureId: string) { async function handleGetInfoByFigureId(figureId: string) {
const res = await fetchGetInfoByFigureId<{ imageUrl: string }>(figureId) const res = await fetchGetInfoByFigureId<{ imageUrl: string }>(figureId)
...@@ -37,7 +37,7 @@ async function handleGetInfoByFigureId(figureId: string) { ...@@ -37,7 +37,7 @@ async function handleGetInfoByFigureId(figureId: string) {
</script> </script>
<template> <template>
<div class="relative h-[667px] w-[375px] overflow-hidden rounded-2xl bg-white"> <div class="relative aspect-[9/16] h-full overflow-hidden rounded-2xl bg-white xl:my-[50px] 2xl:my-[100px]">
<div <div
v-if="isEmptyPreview" v-if="isEmptyPreview"
class="flex h-full w-full select-none items-center justify-center text-xs text-[#84868c]" class="flex h-full w-full select-none items-center justify-center text-xs text-[#84868c]"
...@@ -56,7 +56,7 @@ async function handleGetInfoByFigureId(figureId: string) { ...@@ -56,7 +56,7 @@ async function handleGetInfoByFigureId(figureId: string) {
v-show="figureImageUrl" v-show="figureImageUrl"
:src="figureImageUrl" :src="figureImageUrl"
alt="數字人" alt="數字人"
class="absolute bottom-0 left-[25px] h-[574px] w-[324px] object-cover" class="absolute bottom-0 left-[10%] aspect-[9/16] h-[80%] object-cover"
/> />
</div> </div>
</template> </template>
...@@ -34,9 +34,9 @@ watch( ...@@ -34,9 +34,9 @@ watch(
(newValue) => { (newValue) => {
isUnSavedDigitalHumanDialogueConfig.value = true isUnSavedDigitalHumanDialogueConfig.value = true
saveDialoguePayload.value = JSON.parse(JSON.stringify(newValue)) saveDialoguePayload.value = JSON.parse(JSON.stringify(newValue))
saveDialoguePayload.value.systemInfo.chitchatStatus = newValue?.systemInfo.chitchat ? 'Y' : 'N' !newValue?.systemInfo.chitchat && (saveDialoguePayload.value.systemInfo.chitchatStatus = 'N')
saveDialoguePayload.value.systemInfo.perambleStatus = newValue?.systemInfo.preamble ? 'Y' : 'N' !newValue?.systemInfo.preamble && (saveDialoguePayload.value.systemInfo.perambleStatus = 'N')
saveDialoguePayload.value.systemInfo.refuseAnswerStatus = newValue?.systemInfo.refuseAnswer ? 'Y' : 'N' !newValue?.systemInfo.refuseAnswer && (saveDialoguePayload.value.systemInfo.refuseAnswerStatus = 'N')
}, },
{ deep: true }, { deep: true },
) )
...@@ -106,7 +106,7 @@ async function handleSaveDigitalHumanDialogueTitle() { ...@@ -106,7 +106,7 @@ async function handleSaveDigitalHumanDialogueTitle() {
return return
} }
digitalHumanDialogueConfig.value.baseInfo.title = digitalHumanDialogueTitle.value saveDialoguePayload.value.baseInfo.title = digitalHumanDialogueTitle.value
const res = await fetchSaveDigitalHumanDialogueConfig<DigitalHumanDialogueConfig>(saveDialoguePayload.value) const res = await fetchSaveDigitalHumanDialogueConfig<DigitalHumanDialogueConfig>(saveDialoguePayload.value)
......
...@@ -39,9 +39,9 @@ const showModal = computed({ ...@@ -39,9 +39,9 @@ const showModal = computed({
}) })
watch( watch(
() => props.configTitle, () => showModal.value,
(newValue) => { () => {
digitalHumanDialogueFormData.title = (newValue + '副本').slice(0, 30) digitalHumanDialogueFormData.title = (props.configTitle + '副本').slice(0, 30)
}, },
) )
......
...@@ -36,8 +36,11 @@ export function createDarftTableColumns({ ...@@ -36,8 +36,11 @@ export function createDarftTableColumns({
src: row.coverUrl, src: row.coverUrl,
alt: '作品圖', alt: '作品圖',
class: 'h-full object-cover', class: 'h-full object-cover',
style: {
width: row.width > row.height ? '64px' : '20px',
},
}) })
: h('div', { class: 'border w-full h-full text-xs flex items-center justify-center' }, '暫無圖片'), : h('div', { class: 'w-full h-full text-xs flex items-center justify-center' }, '暫無圖片'),
], ],
), ),
h(NEllipsis, {}, { default: () => row.draftName || '--' }), h(NEllipsis, {}, { default: () => row.draftName || '--' }),
......
...@@ -39,9 +39,9 @@ const showModal = computed({ ...@@ -39,9 +39,9 @@ const showModal = computed({
}) })
watch( watch(
() => props.draftName, () => showModal.value,
(newValue) => { () => {
digitalHumanDraftFormData.draftName = (newValue + '副本').slice(0, 30) digitalHumanDraftFormData.draftName = (props.draftName + '副本').slice(0, 30)
}, },
) )
......
...@@ -18,7 +18,7 @@ const taskTypeList = [ ...@@ -18,7 +18,7 @@ const taskTypeList = [
{ value: '', label: '全部' }, { value: '', label: '全部' },
{ {
value: 'IMAGE_VIDEO', value: 'IMAGE_VIDEO',
label: '照片數人', label: '照片數人',
}, },
{ {
value: 'BASE_VIDEO', value: 'BASE_VIDEO',
......
...@@ -16,7 +16,7 @@ const exchangeInfoForm = ref({ ...@@ -16,7 +16,7 @@ const exchangeInfoForm = ref({
const exchangeInfoFormRules = shallowReadonly({ const exchangeInfoFormRules = shallowReadonly({
redemptionCode: { redemptionCode: {
required: true, required: true,
message: '請填禮包碼', message: '請填禮包碼',
trigger: 'blur', trigger: 'blur',
}, },
}) })
...@@ -51,7 +51,7 @@ function handleExchangeSubmit() { ...@@ -51,7 +51,7 @@ function handleExchangeSubmit() {
setTimeout(() => { setTimeout(() => {
window.$dialog.error({ window.$dialog.error({
title: '禮包兌換失敗', title: '禮包兌換失敗',
content: '請重新兌換或聯客服', content: '請重新兌換或聯客服',
contentStyle: { fontSize: '14px', marginTop: '20px' }, contentStyle: { fontSize: '14px', marginTop: '20px' },
closable: false, closable: false,
positiveText: '知道了', positiveText: '知道了',
...@@ -100,14 +100,16 @@ function onModalAfterLeave() { ...@@ -100,14 +100,16 @@ function onModalAfterLeave() {
</n-form> </n-form>
<div class="mb-[20px] mt-[16px]"> <div class="mb-[20px] mt-[16px]">
<h2>兌換明:</h2> <h2>兌換明:</h2>
<div class="mt-[6px] pl-[8px] leading-7"> <div class="mt-[6px] pl-[8px] leading-7">
<div>1、每個禮包碼僅限使用一次;</div> <div>1、每個禮包碼僅限使用一次;</div>
<div>2、禮包內容和適用條件以活動説明爲準;</div> <div>2、禮包內容和適用條件以活動說明為准;</div>
<div>3、兌換時,請準確無誤地輸入禮包碼,包括字母大小冩、數字位數;</div> <div>3、兌換時,請準確無誤地輸入禮包碼,包括字母大小寫、數位位數;</div>
<div>4、禮包碼一旦兌換成功,獎勵將直接髮放至您的賬戶中,不可轉移給其他賬戶;</div> <div>4、禮包碼一旦兌換成功,獎勵將直接發放至您的帳戶中,不可轉移給其他帳戶;</div>
<div>5、本活動最終解釋權歸萃想智能雲創所有,如有任何爭議,萃想保留決定權;</div> <div>5、本活動最終解釋權歸萃想智慧雲創所有,如有任何爭議,萃想保留決定權;</div>
<div>6、如遇無法正常兌換或其他問題,請尋求客服幫助。客服聯繫方式:蒐索微信公衆號:萃想AI工坊,後颱留言。</div> <div>
6、如遇無法正常兌換或其他問題,請尋求客服幫助。 客服聯繫方式:蒐索微信公眾號:萃想AI工坊,後臺留言。
</div>
</div> </div>
</div> </div>
......
...@@ -13,7 +13,7 @@ const userStore = useUserStore() ...@@ -13,7 +13,7 @@ const userStore = useUserStore()
const dropdownOptions = shallowRef([ const dropdownOptions = shallowRef([
{ {
label: '退出登', label: '退出登',
key: 'logout', key: 'logout',
icon: () => h(Logout, { theme: 'outline', size: 12, strokeWidth: 3 }), icon: () => h(Logout, { theme: 'outline', size: 12, strokeWidth: 3 }),
}, },
......
...@@ -18,7 +18,7 @@ const menuOptions = shallowReadonly<MenuOption[]>([ ...@@ -18,7 +18,7 @@ const menuOptions = shallowReadonly<MenuOption[]>([
key: 'Videos', key: 'Videos',
children: [ children: [
{ {
label: '工作', label: '工作',
key: 'Workbench', key: 'Workbench',
icon: () => h(Workbench, { ...iconConfigFactory() }), icon: () => h(Workbench, { ...iconConfigFactory() }),
}, },
......
...@@ -17,7 +17,7 @@ const taskTypeList = [ ...@@ -17,7 +17,7 @@ const taskTypeList = [
{ value: '', label: '全部' }, { value: '', label: '全部' },
{ {
value: 'IMAGE_VIDEO', value: 'IMAGE_VIDEO',
label: '照片數人', label: '照片數人',
}, },
{ {
value: 'BASE_VIDEO', value: 'BASE_VIDEO',
...@@ -179,11 +179,13 @@ async function handleGetDigitalVideoWorkList() { ...@@ -179,11 +179,13 @@ async function handleGetDigitalVideoWorkList() {
function handleGetTaskListUpdatePageNo(pageNo: number) { function handleGetTaskListUpdatePageNo(pageNo: number) {
pagingInfo.value.pageNo = pageNo pagingInfo.value.pageNo = pageNo
handleGetDigitalVideoWorkList()
} }
function handleGetTaskListUpdatePageSize(pageSize: number) { function handleGetTaskListUpdatePageSize(pageSize: number) {
pagingInfo.value.pageNo = 1 pagingInfo.value.pageNo = 1
pagingInfo.value.pageSize = pageSize pagingInfo.value.pageSize = pageSize
handleGetDigitalVideoWorkList()
} }
</script> </script>
......
...@@ -21,17 +21,17 @@ const userStore = useUserStore() ...@@ -21,17 +21,17 @@ const userStore = useUserStore()
const digitalCreationStore = useDigitalCreationStore() const digitalCreationStore = useDigitalCreationStore()
const digitalHumanDialogueStore = useDigitalHumanDialogueStore() const digitalHumanDialogueStore = useDigitalHumanDialogueStore()
const ishowCreateDigitalHumanDialogueModal = ref(false) const isShowCreateDigitalHumanDialogueModal = ref(false)
const ishowCreateDigitalHumanVideoModal = ref(false) const isShowCreateDigitalHumanVideoModal = ref(false)
const userInfo = computed(() => userStore.userInfo) const userInfo = computed(() => userStore.userInfo)
function handleShowCreateDigitalHumanDialogueModal() { function handleShowCreateDigitalHumanDialogueModal() {
ishowCreateDigitalHumanDialogueModal.value = true isShowCreateDigitalHumanDialogueModal.value = true
} }
function handleShowCreateDigitalHumanVideoModal() { function handleShowCreateDigitalHumanVideoModal() {
ishowCreateDigitalHumanVideoModal.value = true isShowCreateDigitalHumanVideoModal.value = true
} }
async function handleCreateDigitalHumanDialogue(digitalHumanDialogueForm: DigitalHumanDialogueForm) { async function handleCreateDigitalHumanDialogue(digitalHumanDialogueForm: DigitalHumanDialogueForm) {
...@@ -48,7 +48,7 @@ async function handleCreateDigitalHumanDialogue(digitalHumanDialogueForm: Digita ...@@ -48,7 +48,7 @@ async function handleCreateDigitalHumanDialogue(digitalHumanDialogueForm: Digita
if (res.code === 0) { if (res.code === 0) {
router.push({ name: 'DialogueDetail', params: { configId: res.data.baseInfo.configId } }) router.push({ name: 'DialogueDetail', params: { configId: res.data.baseInfo.configId } })
ishowCreateDigitalHumanDialogueModal.value = false isShowCreateDigitalHumanDialogueModal.value = false
} }
} }
...@@ -58,6 +58,7 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman ...@@ -58,6 +58,7 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman
payload.draftName = digitalHumanVideoForm.title payload.draftName = digitalHumanVideoForm.title
payload.width = digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT ? 1080 : 1920 payload.width = digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT ? 1080 : 1920
payload.height = digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT ? 1920 : 1080 payload.height = digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT ? 1920 : 1080
payload.figureId = digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT ? 'A2A_V2-gaoming' : 'A2A_V2-3to2_xinyi'
payload.inputImageUrl = payload.inputImageUrl =
digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT digitalHumanVideoForm.pageLayout === ScreenType.PORTRAIT
? 'https://demand-ai-sit.gz.bcebos.com/data/20240913/1726223058345.png' ? 'https://demand-ai-sit.gz.bcebos.com/data/20240913/1726223058345.png'
...@@ -71,7 +72,7 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman ...@@ -71,7 +72,7 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman
if (res.code === 0) { if (res.code === 0) {
router.push({ name: 'Creation', query: { draftId: res.data.id } }) router.push({ name: 'Creation', query: { draftId: res.data.id } })
ishowCreateDigitalHumanDialogueModal.value = false isShowCreateDigitalHumanVideoModal.value = false
} }
} }
</script> </script>
...@@ -154,21 +155,21 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman ...@@ -154,21 +155,21 @@ async function handleCreateDigitalHumanVideo(digitalHumanVideoForm: DigitalHuman
<span v-else>-</span> <span v-else>-</span>
</div> </div>
<div></div> <div></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<CreateDigitalHumanDialogueModal <CreateDigitalHumanDialogueModal
v-model:is-show-modal="ishowCreateDigitalHumanDialogueModal" v-model:is-show-modal="isShowCreateDigitalHumanDialogueModal"
modal-title="新建對話" modal-title="新建對話"
:btn-loading="false" :btn-loading="false"
@confirm="handleCreateDigitalHumanDialogue" @confirm="handleCreateDigitalHumanDialogue"
/> />
<CreateDigitalHumanVideoModal <CreateDigitalHumanVideoModal
v-model:is-show-modal="ishowCreateDigitalHumanVideoModal" v-model:is-show-modal="isShowCreateDigitalHumanVideoModal"
modal-title="新建視頻" modal-title="新建視頻"
:btn-loading="false" :btn-loading="false"
@confirm="handleCreateDigitalHumanVideo" @confirm="handleCreateDigitalHumanVideo"
......
<script setup lang="ts"> <script setup lang="ts">
import { fetchDraftsList } from '@/apis/drafts' import { fetchDraftsList } from '@/apis/drafts'
import { ScreenType } from '@/store/types/creation'
import { TaskType } from '@/store/types/template' import { TaskType } from '@/store/types/template'
import { formatDateTime } from '@/utils/date-formatter' import { formatDateTime } from '@/utils/date-formatter'
import { Right } from '@icon-park/vue-next' import { Right } from '@icon-park/vue-next'
...@@ -12,6 +13,9 @@ interface CreationTemplateInfoItem { ...@@ -12,6 +13,9 @@ interface CreationTemplateInfoItem {
coverUrl: string coverUrl: string
modifiedTime: string modifiedTime: string
draftName: string draftName: string
pageLayout: ScreenType
width: number
height: number
} }
const router = useRouter() const router = useRouter()
...@@ -42,6 +46,9 @@ function getRecentCreationList() { ...@@ -42,6 +46,9 @@ function getRecentCreationList() {
modifiedTime: item.modifiedTime, modifiedTime: item.modifiedTime,
coverUrl: item.coverUrl, coverUrl: item.coverUrl,
taskType: item.taskType, taskType: item.taskType,
pageLayout: item.pageLayout,
width: item.width,
height: item.height,
})) }))
fetchCreationTemplateInfoListLoading.value = false fetchCreationTemplateInfoListLoading.value = false
...@@ -94,11 +101,17 @@ function handleToCreation(draftId: number) { ...@@ -94,11 +101,17 @@ function handleToCreation(draftId: number) {
class="mr-[10px] inline-block pb-[16px]" class="mr-[10px] inline-block pb-[16px]"
> >
<div <div
class="relative mb-[12px] h-[145px] w-[145px] cursor-pointer overflow-hidden rounded-[12px] bg-[#f3f4fb]" class="relative mb-[12px] flex h-[145px] w-[145px] cursor-pointer items-center justify-center overflow-hidden rounded-[12px] bg-[#f3f4fb]"
@click="handleToCreation(templateInfoItem.id)" @click="handleToCreation(templateInfoItem.id)"
> >
<img <img
class="z-1 relative h-full w-full object-contain transition-[scale] duration-300 ease-in-out hover:scale-110" class="z-1 relative object-cover transition-[scale] duration-300 ease-in-out hover:scale-110"
:class="
templateInfoItem.pageLayout === ScreenType.LANDSCAPE ||
templateInfoItem.width > templateInfoItem.height
? 'aspect-[16/9]'
: 'aspect-[9/16] h-full'
"
:src="templateInfoItem.coverUrl" :src="templateInfoItem.coverUrl"
alt="cover" alt="cover"
/> />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment