feat(frontend): add loading state to publish button to prevent duplicate clicks

- Add publishing state property to each tab to track publishing status
- Implement loading indicator on publish button with visual feedback
- Prevent duplicate clicks during active publishing process
- Update button text to show "发布中..." (Publishing...) when loading
- Ensure publishing state is properly reset in all scenarios (success, failure, validation errors)
- Add duplicate click prevention with user-friendly error message

The publish button now shows a loading spinner and prevents multiple clicks
during the publishing process, improving user experience and preventing
duplicate uploads to social media platforms.
This commit is contained in:
Deroino
2025-11-13 07:53:23 +08:00
parent 1a02b8fa50
commit c0e7b64b94
+24 -2
View File
@@ -457,7 +457,14 @@
<!-- 操作按钮 --> <!-- 操作按钮 -->
<div class="action-buttons"> <div class="action-buttons">
<el-button size="small" @click="cancelPublish(tab)">取消</el-button> <el-button size="small" @click="cancelPublish(tab)">取消</el-button>
<el-button size="small" type="primary" @click="confirmPublish(tab)">发布</el-button> <el-button
size="small"
type="primary"
@click="confirmPublish(tab)"
:loading="tab.publishing || false"
>
{{ tab.publishing ? '发布中...' : '发布' }}
</el-button>
</div> </div>
</div> </div>
</div> </div>
@@ -526,7 +533,8 @@ const defaultTabInit = {
videosPerDay: 1, // 每天发布视频数量 videosPerDay: 1, // 每天发布视频数量
dailyTimes: ['10:00'], // 每天发布时间点列表 dailyTimes: ['10:00'], // 每天发布时间点列表
startDays: 0, // 从今天开始计算的发布天数,0表示明天,1表示后天 startDays: 0, // 从今天开始计算的发布天数,0表示明天,1表示后天
publishStatus: null // 发布状态,包含message和type publishStatus: null, // 发布状态,包含message和type
publishing: false // 发布状态,用于控制按钮loading效果
} }
// helper to create a fresh deep-copied tab from defaultTabInit // helper to create a fresh deep-copied tab from defaultTabInit
@@ -733,25 +741,36 @@ const cancelPublish = (tab) => {
// 确认发布 // 确认发布
const confirmPublish = async (tab) => { const confirmPublish = async (tab) => {
// 防止重复点击
if (tab.publishing) {
return Promise.reject(new Error('正在发布中,请稍候...'))
}
tab.publishing = true // 设置发布状态为进行中
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 数据验证 // 数据验证
if (tab.fileList.length === 0) { if (tab.fileList.length === 0) {
ElMessage.error('请先上传视频文件') ElMessage.error('请先上传视频文件')
tab.publishing = false // 重置发布状态
reject(new Error('请先上传视频文件')) reject(new Error('请先上传视频文件'))
return return
} }
if (!tab.title.trim()) { if (!tab.title.trim()) {
ElMessage.error('请输入标题') ElMessage.error('请输入标题')
tab.publishing = false // 重置发布状态
reject(new Error('请输入标题')) reject(new Error('请输入标题'))
return return
} }
if (!tab.selectedPlatform) { if (!tab.selectedPlatform) {
ElMessage.error('请选择发布平台') ElMessage.error('请选择发布平台')
tab.publishing = false // 重置发布状态
reject(new Error('请选择发布平台')) reject(new Error('请选择发布平台'))
return return
} }
if (tab.selectedAccounts.length === 0) { if (tab.selectedAccounts.length === 0) {
ElMessage.error('请选择发布账号') ElMessage.error('请选择发布账号')
tab.publishing = false // 重置发布状态
reject(new Error('请选择发布账号')) reject(new Error('请选择发布账号'))
return return
} }
@@ -815,6 +834,9 @@ const confirmPublish = async (tab) => {
} }
reject(error) reject(error)
}) })
.finally(() => {
tab.publishing = false // 重置发布状态
})
}) })
} }