feat: 优化

This commit is contained in:
2026-02-25 22:06:13 +08:00
parent c8518a381f
commit b29e00950c

View File

@@ -37,6 +37,9 @@
<div v-if="column.key === 'name'" class="voice-name"> <div v-if="column.key === 'name'" class="voice-name">
{{ record.name || '未命名' }} {{ record.name || '未命名' }}
</div> </div>
<a-tooltip v-else-if="column.key === 'note'" :title="record.note" placement="topLeft">
<span class="note-text">{{ record.note || '-' }}</span>
</a-tooltip>
<span v-else-if="column.key === 'createTime'"> <span v-else-if="column.key === 'createTime'">
{{ formatDateTime(record.createTime) }} {{ formatDateTime(record.createTime) }}
</span> </span>
@@ -56,16 +59,18 @@
<a-modal <a-modal
v-model:open="modalVisible" v-model:open="modalVisible"
:title="isCreateMode ? '新建配音' : '编辑配音'" :title="isCreateMode ? '新建配音' : '编辑配音'"
:width="600" :width="480"
ok-text="确定" ok-text="保存"
cancel-text="取消" cancel-text="取消"
:confirm-loading="submitting" :confirm-loading="submitting"
:mask-closable="false"
centered
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
> >
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical"> <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
<a-form-item label="配音名称" name="name"> <a-form-item label="配音名称" name="name">
<a-input v-model:value="formData.name" placeholder="请输入配音名称" /> <a-input v-model:value="formData.name" placeholder="请输入配音名称" allow-clear />
</a-form-item> </a-form-item>
<a-form-item <a-form-item
@@ -74,28 +79,50 @@
name="fileId" name="fileId"
:rules="[{ required: true, message: '请上传音频文件' }]" :rules="[{ required: true, message: '请上传音频文件' }]"
> >
<a-upload <div class="upload-area" :class="{ 'has-file': fileList.length > 0 }">
v-model:file-list="fileList" <a-upload-dragger
:custom-request="handleCustomUpload" v-model:file-list="fileList"
:before-upload="handleBeforeUpload" :custom-request="handleCustomUpload"
:max-count="1" :before-upload="handleBeforeUpload"
accept="audio/*,.mp3,.wav,.aac,.m4a,.flac,.ogg" :max-count="1"
@remove="handleRemoveFile" :show-upload-list="false"
@change="handleFileListChange" accept="audio/*,.mp3,.wav,.aac,.m4a,.flac,.ogg"
> @remove="handleRemoveFile"
<a-button type="primary" :loading="uploadState.uploading"> >
<UploadOutlined v-if="!uploadState.uploading" /> <template v-if="!uploadState.uploading && fileList.length === 0">
{{ uploadState.uploading ? '上传中...' : (fileList.length > 0 ? '重新上传' : '上传音频文件') }} <div class="upload-icon">
</a-button> <CloudUploadOutlined />
</a-upload> </div>
<div class="upload-hint"> <p class="upload-text">点击或拖拽音频文件到此区域</p>
支持格式MP3WAVAACM4AFLACOGG单个文件不超过 5MB<br> <p class="upload-hint-inline">支持 MP3WAVAAC 等格式最大 5MB</p>
<span class="hint-text">🎤 配音建议使用 5-20 秒的短配音效果更佳</span> </template>
<template v-else-if="uploadState.uploading">
<a-progress type="circle" :percent="50" :width="60" status="active" />
<p class="upload-text" style="margin-top: 12px">正在上传...</p>
</template>
<template v-else>
<div class="file-preview">
<SoundOutlined class="file-icon" />
<div class="file-info">
<span class="file-name">{{ fileList[0]?.name || '音频文件' }}</span>
<a-button type="link" size="small" danger @click.stop="handleRemoveFile">
<DeleteOutlined /> 移除
</a-button>
</div>
</div>
</template>
</a-upload-dragger>
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label="备注" name="note"> <a-form-item label="备注" name="note">
<a-textarea v-model="formData.note" :rows="3" placeholder="请输入备注信息" /> <a-textarea
v-model:value="formData.note"
:rows="2"
placeholder="备注信息(选填)"
:auto-size="{ minRows: 2, maxRows: 4 }"
allow-clear
/>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
@@ -107,7 +134,7 @@
<script setup> <script setup>
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, onMounted } from 'vue'
import { message, Modal } from 'ant-design-vue' import { message, Modal } from 'ant-design-vue'
import { PlusOutlined, SearchOutlined, UploadOutlined, PlayCircleOutlined } from '@ant-design/icons-vue' import { PlusOutlined, SearchOutlined, PlayCircleOutlined, CloudUploadOutlined, SoundOutlined, DeleteOutlined } from '@ant-design/icons-vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import BasicLayout from '@/layouts/components/BasicLayout.vue' import BasicLayout from '@/layouts/components/BasicLayout.vue'
import { MaterialService } from '@/api/material' import { MaterialService } from '@/api/material'
@@ -170,9 +197,10 @@ const isCreateMode = computed(() => formMode.value === 'create')
// ========== 表格配置 ========== // ========== 表格配置 ==========
const columns = [ const columns = [
{ title: '配音名称', key: 'name', dataIndex: 'name', width: 200 }, { title: '配音名称', key: 'name', dataIndex: 'name', width: 160 },
{ title: '备注', key: 'note', dataIndex: 'note', ellipsis: true },
{ title: '创建时间', key: 'createTime', dataIndex: 'createTime', width: 180 }, { title: '创建时间', key: 'createTime', dataIndex: 'createTime', width: 180 },
{ title: '操作', key: 'actions', width: 90, fixed: 'right' } { title: '操作', key: 'actions', width: 100, fixed: 'right' }
] ]
// ========== 表单验证规则 ========== // ========== 表单验证规则 ==========
@@ -362,15 +390,6 @@ async function fetchAudioTextById(fileId) {
} }
} }
function handleFileListChange(info) {
const { fileList: newFileList } = info
if (newFileList) {
fileList.value = newFileList.filter(function(item) {
return item.status !== 'removed'
})
}
}
function handleRemoveFile() { function handleRemoveFile() {
formData.fileId = null formData.fileId = null
fileList.value = [] fileList.value = []
@@ -426,8 +445,8 @@ async function handleSubmit() {
} }
function handleCancel() { function handleCancel() {
modalVisible.value = false modalVisible.value = false
resetForm() resetForm()
} }
function resetForm() { function resetForm() {
@@ -442,7 +461,7 @@ onMounted(function() {
}) })
</script> </script>
<style scoped> <style scoped lang="less">
.search-bar { .search-bar {
background: var(--color-surface); background: var(--color-surface);
border-radius: var(--radius-card); border-radius: var(--radius-card);
@@ -459,10 +478,74 @@ onMounted(function() {
color: var(--color-text); color: var(--color-text);
} }
.upload-hint { .note-text {
font-size: 12px;
color: var(--color-text-secondary); color: var(--color-text-secondary);
margin-top: 8px; }
line-height: 1.5;
// 上传区域样式
.upload-area {
:deep(.ant-upload-drag) {
border: 2px dashed var(--color-border, #d9d9d9);
border-radius: 8px;
background: var(--color-bg-container, #fafafa);
transition: all 0.3s;
padding: 24px 16px;
&:hover {
border-color: var(--color-primary, #1890ff);
background: var(--color-primary-bg, #e6f7ff);
}
}
&.has-file :deep(.ant-upload-drag) {
border-style: solid;
border-color: var(--color-success-border, #b7eb8f);
background: var(--color-success-bg, #f6ffed);
}
}
.upload-icon {
font-size: 40px;
color: var(--color-primary, #1890ff);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--color-text, #333);
margin-bottom: 4px;
}
.upload-hint-inline {
font-size: 12px;
color: var(--color-text-secondary, #999);
}
.file-preview {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
.file-icon {
font-size: 32px;
color: var(--color-primary, #1890ff);
}
.file-info {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
.file-name {
font-size: 14px;
color: var(--color-text, #333);
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
} }
</style> </style>