fix(排期): 发布按钮不再兼任删除,清空排期改为显式操作并加服务端守卫
This commit is contained in:
@@ -741,6 +741,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 主要操作 -->
|
||||
<!-- 清空当天排期:破坏性动作,独立出来(发布按钮不再兼任删除) -->
|
||||
<button
|
||||
:disabled="localScheduledSongs.length === 0"
|
||||
class="shrink-0 w-11 h-11 bg-white border border-red-200 text-red-500 rounded-xl flex items-center justify-center active:scale-95 transition-all disabled:opacity-40 disabled:cursor-not-allowed"
|
||||
title="删除当天全部排期"
|
||||
@click="clearTodaySchedule"
|
||||
>
|
||||
<Trash2 class="w-5 h-5" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!hasChanges"
|
||||
class="flex-1 py-3 bg-blue-600 hover:bg-blue-500 text-white text-xs font-black uppercase tracking-widest rounded-xl shadow-lg shadow-blue-900/20 transition-all active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||||
@@ -933,7 +942,8 @@ import {
|
||||
CalendarDays,
|
||||
Image as ImageIcon,
|
||||
Layers,
|
||||
Inbox
|
||||
Inbox,
|
||||
Trash2
|
||||
} from '@lucide/vue'
|
||||
import AdminDatePicker from './AdminDatePicker.vue'
|
||||
import PlaylistCardGenerator from './PlaylistCardGenerator.vue'
|
||||
@@ -2504,21 +2514,26 @@ watch(
|
||||
)
|
||||
|
||||
// 发布排期(需要确认)
|
||||
//
|
||||
// ⚠️ 这里**只管发布,绝不删除**。
|
||||
//
|
||||
// 以前为了「清空某天排期」把删除偷偷挂在发布按钮上:列表为空时点发布 → 弹「删除排期」→
|
||||
// 调 bulk-publish 传空数组 → 服务端先删光该日期(含草稿)再插入 0 条。
|
||||
// 于是只要**界面上的列表是空的**(数据还没加载回来、时段筛选没匹配上、切换日期后没刷新完…),
|
||||
// 点「发布」就等于清空当天 —— 按钮叫发布,干的是删除。删除已经拆到
|
||||
// clearTodaySchedule(),发布路径不再有任何破坏性分支。
|
||||
const publishSchedule = async () => {
|
||||
try {
|
||||
// 如果列表为空,提示删除排期
|
||||
if (localScheduledSongs.value.length === 0) {
|
||||
confirmDialogTitle.value = '删除排期'
|
||||
confirmDialogMessage.value = '确定要删除当天的所有排期吗?此操作不可恢复。'
|
||||
confirmDialogType.value = 'danger'
|
||||
confirmDialogConfirmText.value = '确认删除'
|
||||
} else {
|
||||
confirmDialogTitle.value = '发布排期'
|
||||
confirmDialogMessage.value = '确定要发布当前排期吗?发布后将立即公示并发送通知。'
|
||||
confirmDialogType.value = 'warning'
|
||||
confirmDialogConfirmText.value = '发布排期'
|
||||
showToast('当前列表没有歌曲,没有需要发布的内容', 'info')
|
||||
return
|
||||
}
|
||||
|
||||
confirmDialogTitle.value = '发布排期'
|
||||
confirmDialogMessage.value = '确定要发布当前排期吗?发布后将立即公示并发送通知。'
|
||||
confirmDialogType.value = 'warning'
|
||||
confirmDialogConfirmText.value = '发布排期'
|
||||
|
||||
confirmAction.value = async () => {
|
||||
await publishScheduleConfirmed()
|
||||
}
|
||||
@@ -2528,6 +2543,56 @@ const publishSchedule = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空当天的排期(含草稿)—— 独立的显式操作,跟「发布」彻底分开。
|
||||
* 服务端 bulk-publish 收到空 songs 数组时会先删该日期全部排期再插入 0 条(即清空),
|
||||
* 所以「删除」这个破坏性动作必须由调用方明确要求,见 bulk-publish.post.ts 里的 confirmClear。
|
||||
*/
|
||||
const clearTodaySchedule = () => {
|
||||
if (localScheduledSongs.value.length === 0) {
|
||||
showToast('当天本来就没有排期', 'info')
|
||||
return
|
||||
}
|
||||
|
||||
confirmDialogTitle.value = '删除当天排期'
|
||||
confirmDialogMessage.value = `确定要删除 ${selectedDate.value} 的全部排期吗?已发布的排期和草稿都会一起删除,此操作不可恢复。`
|
||||
confirmDialogType.value = 'danger'
|
||||
confirmDialogConfirmText.value = '确认删除'
|
||||
|
||||
confirmAction.value = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await $fetch('/api/admin/schedule/bulk-publish', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
playDate: selectedDate.value,
|
||||
playTimeId: selectedPlayTime.value ? parseInt(selectedPlayTime.value) : null,
|
||||
songs: [],
|
||||
confirmClear: true // 明确表示「我就是要清空」,缺了它服务端会拒(防止误清)
|
||||
},
|
||||
...auth.getAuthConfig()
|
||||
})
|
||||
|
||||
hasChanges.value = false
|
||||
await loadData()
|
||||
updateLocalScheduledSongs()
|
||||
|
||||
if (window.$showNotification) {
|
||||
window.$showNotification('当天排期已删除', 'success')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除当天排期失败:', error)
|
||||
if (window.$showNotification) {
|
||||
window.$showNotification('删除失败: ' + (error.data?.message || error.message), 'error')
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
showConfirmDialog.value = true
|
||||
}
|
||||
|
||||
// 确认发布排期
|
||||
const publishScheduleConfirmed = async () => {
|
||||
loading.value = true
|
||||
|
||||
@@ -48,8 +48,16 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
// 获取所有涉及的歌曲详情(用于通知)
|
||||
const songIds = body.songs.map((s: any) => s.songId)
|
||||
if (songIds.length === 0) {
|
||||
// 如果列表为空,说明是清空排期,直接执行删除逻辑即可
|
||||
/*
|
||||
* ⚠️ 空 songs = 「清空该日期排期」:下面第 3 步会先删光该日期(含草稿)的排期,再插入 0 条。
|
||||
* 这是个**破坏性操作**,绝不能因为前端列表没加载出来(数组恰好是空)就被误触发 ——
|
||||
* 以前点「发布」就能把一整天删掉。所以清空必须由调用方显式带 confirmClear: true。
|
||||
*/
|
||||
if (songIds.length === 0 && body.confirmClear !== true) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '歌曲列表为空:发布需要至少一首歌;若要清空当天排期,请显式传 confirmClear: true'
|
||||
})
|
||||
}
|
||||
|
||||
const songDetails =
|
||||
|
||||
Reference in New Issue
Block a user