feat(embed-slots): soft-delete slots — admin entry, ov shutdown via enabled=false snapshot
- 契约 deleteEmbedSlot(DELETE /admin/embed-slots/{id} → 204 幂等;admin 专属)
- cn schema:embed_slots.deletedAt(迁移 20260923120000,本地已应用)
- softDelete:乐观锁 claim + outbox slot.updated(payload enabled 强制 false
——ov 副本无墓碑,enabled=false 快照即公开端 404 下线;priority=high)+ audit
- 列表/加载/更新过滤 deletedAt → 同码 404
- Admin 列表操作「删除」(确认:已接入网站将停止展示、不可恢复)
- API 56/56、admin 87/87 + build 全绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -23,3 +23,8 @@ export function fetchCreateEmbedSlot(data: Api.EmbedSlot.CreatePayload) {
|
||||
export function fetchUpdateEmbedSlot(id: string, data: Api.EmbedSlot.UpdatePayload) {
|
||||
return request.patch<Api.EmbedSlot.Item>({ url: `/v1/admin/embed-slots/${id}`, data })
|
||||
}
|
||||
|
||||
/** 软删除展示位(deletedAt 标记:列表隐藏、ov 快照下线;幂等 204) */
|
||||
export function fetchDeleteEmbedSlot(id: string) {
|
||||
return request.del<void>({ url: `/v1/admin/embed-slots/${id}` })
|
||||
}
|
||||
|
||||
@@ -820,7 +820,10 @@
|
||||
"actionBind": "Bind Album",
|
||||
"actionCode": "Embed Code",
|
||||
"subtitle": "Manage floating photo widgets: album binding, toggles and embed code.",
|
||||
"tableTitle": "Slots"
|
||||
"tableTitle": "Slots",
|
||||
"actionDelete": "Delete",
|
||||
"deleteConfirm": "Delete slot \"{name}\"? Sites using it will stop showing it; this cannot be undone.",
|
||||
"deleted": "Slot deleted"
|
||||
},
|
||||
"form": {
|
||||
"nameLabel": "Name",
|
||||
|
||||
@@ -820,7 +820,10 @@
|
||||
"actionBind": "绑定相册",
|
||||
"actionCode": "嵌入代码",
|
||||
"subtitle": "管理官网悬浮照片展示位:绑定相册、启停与接入代码。",
|
||||
"tableTitle": "展示位列表"
|
||||
"tableTitle": "展示位列表",
|
||||
"actionDelete": "删除",
|
||||
"deleteConfirm": "确定删除展示位「{name}」?删除后已接入的网站将停止展示,且不可恢复。",
|
||||
"deleted": "展示位已删除"
|
||||
},
|
||||
"form": {
|
||||
"nameLabel": "名称",
|
||||
|
||||
@@ -89,6 +89,9 @@
|
||||
<ElButton link type="primary" data-test="slot-code-btn" @click="openCode(row)">
|
||||
{{ $t('embedSlotsManage.list.actionCode') }}
|
||||
</ElButton>
|
||||
<ElButton link type="danger" data-test="slot-delete-btn" @click="remove(row)">
|
||||
{{ $t('embedSlotsManage.list.actionDelete') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
@@ -124,11 +127,11 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import SlotFormDialog from './SlotFormDialog.vue'
|
||||
import SlotBindDialog from './SlotBindDialog.vue'
|
||||
import EmbedCodeDialog from './EmbedCodeDialog.vue'
|
||||
import { fetchEmbedSlots, fetchUpdateEmbedSlot } from '@/api/embedSlots'
|
||||
import { fetchDeleteEmbedSlot, fetchEmbedSlots, fetchUpdateEmbedSlot } from '@/api/embedSlots'
|
||||
import { useCursorList } from '@/views/albums/composables/useCursorList'
|
||||
import { formatDateTime } from '@/utils/albums/format'
|
||||
|
||||
@@ -207,6 +210,26 @@
|
||||
codeVisible.value = true
|
||||
}
|
||||
|
||||
/** 软删除:确认(已接入网站将停止展示)→ DELETE → 重载列表 */
|
||||
async function remove(row: Api.EmbedSlot.Item): Promise<void> {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('embedSlotsManage.list.deleteConfirm', { name: row.name }),
|
||||
t('common.tips'),
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel')
|
||||
}
|
||||
)
|
||||
} catch {
|
||||
return // 用户取消
|
||||
}
|
||||
await fetchDeleteEmbedSlot(row.id)
|
||||
ElMessage.success(t('embedSlotsManage.list.deleted'))
|
||||
loadFirst()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void loadFirst()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user