feat(albums): soft-delete albums (admin+owner, hidden & irreversible, both app entries)
契约 deleteAlbum(DELETE /albums/{albumId} → 204 幂等)+ status enum 'deleted':
- 服务端:softDelete(canView 404→canManage 403 防枚举;乐观锁 claim +
outbox album.updated priority=high + audit album.delete);列表/详情/更新/
成员/资产/分类/水印/照片/展示位绑定全部 deleted→404;公开端 cn
(status!=='active')与 ov(isAlbumVisibleOv)天然屏蔽;ov 副本经
album.updated 载荷 status 直投自动下线
- Admin:列表表格操作「删除」+ 详情页头「删除相册」(确认含不可恢复说明)
- App:操作面板「删除相册」(红字、二次确认、成功退回列表并刷新)
- 验证:API 56/56、App 397/397(analyze 0)、admin typecheck/lint/test/build 绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,9 @@
|
||||
>
|
||||
{{ $t('albumsManage.detail.edit') }}
|
||||
</ElButton>
|
||||
<ElButton type="danger" plain data-test="album-detail-delete" @click="removeAlbum">
|
||||
{{ $t('albumsManage.detail.delete') }}
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,6 +107,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import AlbumSummaryHeader from '@/components/business/albums/AlbumSummaryHeader.vue'
|
||||
import AlbumBannerUpload from './AlbumBannerUpload.vue'
|
||||
@@ -113,12 +117,14 @@
|
||||
import AlbumWatermark from './AlbumWatermark.vue'
|
||||
import AlbumShareCard from './AlbumShareCard.vue'
|
||||
import AlbumTransferDialog from './AlbumTransferDialog.vue'
|
||||
import { fetchAlbum } from '@/api/albums'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { fetchAlbum, fetchDeleteAlbum } from '@/api/albums'
|
||||
|
||||
defineOptions({ name: 'AlbumsDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
const albumId = computed(() => String(route.params.albumId ?? ''))
|
||||
|
||||
@@ -152,6 +158,26 @@
|
||||
return preferred?.title ?? target.translations[0]?.title ?? target.id
|
||||
}
|
||||
|
||||
/** 软删除相册(admin/owner):确认 → DELETE → 回列表 */
|
||||
async function removeAlbum() {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('albumsManage.list.deleteConfirm', { title: titleOf(album.value) }),
|
||||
t('common.tips'),
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel')
|
||||
}
|
||||
)
|
||||
} catch {
|
||||
return // 用户取消
|
||||
}
|
||||
await fetchDeleteAlbum(albumId.value)
|
||||
ElMessage.success(t('albumsManage.list.deleted'))
|
||||
void router.replace({ name: 'AlbumsManage' })
|
||||
}
|
||||
|
||||
/** 列表「成员」入口带 #members 锚点:直达成员页签 */
|
||||
watch(
|
||||
() => route.hash,
|
||||
|
||||
@@ -155,6 +155,9 @@
|
||||
<ElButton link type="primary" data-test="album-detail-btn" @click="gotoDetail(row)">
|
||||
{{ $t('albumsManage.list.actionDetail') }}
|
||||
</ElButton>
|
||||
<ElButton link type="danger" data-test="album-delete-btn" @click="remove(row)">
|
||||
{{ $t('albumsManage.list.actionDelete') }}
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
@@ -179,7 +182,8 @@
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Search, Menu, Grid } from '@element-plus/icons-vue'
|
||||
import AlbumCoverCard from '@/components/business/albums/AlbumCoverCard.vue'
|
||||
import { fetchAlbumList } from '@/api/albums'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { fetchAlbumList, fetchDeleteAlbum } from '@/api/albums'
|
||||
import { useCursorList } from '@/views/albums/composables/useCursorList'
|
||||
import { formatDateTime } from '@/utils/albums/format'
|
||||
|
||||
@@ -258,6 +262,26 @@
|
||||
router.push({ name: 'AlbumsDetail', params: { albumId: album.id }, hash: '#members' })
|
||||
}
|
||||
|
||||
/** 软删除:确认(不可恢复说明)→ DELETE → 重载列表 */
|
||||
async function remove(album: Api.Album.Summary) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('albumsManage.list.deleteConfirm', { title: titleOf(album) }),
|
||||
t('common.tips'),
|
||||
{
|
||||
type: 'warning',
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel')
|
||||
}
|
||||
)
|
||||
} catch {
|
||||
return // 用户取消
|
||||
}
|
||||
await fetchDeleteAlbum(album.id)
|
||||
ElMessage.success(t('albumsManage.list.deleted'))
|
||||
loadFirst()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadFirst()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user