详情页右上角增加刷新和删除图标

This commit is contained in:
jingrow 2025-11-01 14:33:48 +08:00
parent a7bcc7f06f
commit 026ee28248

View File

@ -8,14 +8,14 @@
<h1 class="page-title">{{ pageTitle }}</h1>
<p class="page-description">{{ pageDescription }}</p>
</div>
<n-space>
<n-space align="center">
<!-- 侧边栏位置切换按钮 -->
<n-button
type="default"
size="small"
size="medium"
@click="toggleSidebarPosition"
:title="sidebarPosition === 'left' ? '切换到右侧' : '切换到左侧'"
class="sidebar-position-toggle-btn"
class="header-action-btn"
>
<template #icon>
<n-icon>
@ -24,6 +24,38 @@
</template>
</n-button>
<!-- 刷新按钮 -->
<n-button
type="default"
size="medium"
@click="handleRefresh"
:disabled="loading || isNew"
:title="t('Refresh')"
class="header-action-btn"
>
<template #icon>
<n-icon>
<Icon icon="tabler:refresh" />
</n-icon>
</template>
</n-button>
<!-- 删除按钮 -->
<n-button
type="default"
size="medium"
@click="handleDelete"
:disabled="loading || isNew"
:title="t('Delete')"
class="header-action-btn"
>
<template #icon>
<n-icon>
<Icon icon="tabler:trash" />
</n-icon>
</template>
</n-button>
<component
v-if="toolbarComponent"
:is="toolbarComponent"
@ -38,13 +70,13 @@
t
}"
/>
<n-button type="default" @click="goBack" :disabled="loading">
<n-button type="default" size="medium" @click="goBack" :disabled="loading">
<template #icon>
<n-icon><Icon icon="tabler:arrow-left" /></n-icon>
</template>
{{ t('Back') }}
</n-button>
<n-button type="primary" :disabled="loading" @click="handleSave" v-if="canEdit">
<n-button type="primary" size="medium" :disabled="loading" @click="handleSave" v-if="canEdit">
{{ t('Save') }}
</n-button>
</n-space>
@ -257,7 +289,7 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, shallowRef, markRaw, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NButton, NSpace, NIcon, useMessage, NLayout, NLayoutSider, NLayoutContent } from 'naive-ui'
import { NButton, NSpace, NIcon, useMessage, useDialog, NLayout, NLayoutSider, NLayoutContent } from 'naive-ui'
import FieldRenderer from '@/core/components/form/FieldRenderer.vue'
import { Icon } from '@iconify/vue'
import { resolveSidebarPanel } from '@/core/registry/sidebarOverride'
@ -281,7 +313,7 @@ const TagSection = defineAsyncComponent(async () => {
import axios from 'axios'
import { t } from '@/shared/i18n'
import { get_session_api_headers } from '@/shared/api/auth'
import { updateRecord, getRecord, getRecordAttachments, deleteAttachment, uploadAttachment } from '@/shared/api/common'
import { updateRecord, getRecord, getRecordAttachments, deleteAttachment, uploadAttachment, deleteRecords } from '@/shared/api/common'
import { downloadImageToLocal } from '@/shared/api/common'
import { usePageTypeSlug } from '@/shared/utils/slug'
import { resolvePagetypeDetailOverride, resolvePagetypeToolbarOverride } from '@/core/registry/pagetypeOverride'
@ -289,6 +321,7 @@ import { resolvePagetypeDetailOverride, resolvePagetypeToolbarOverride } from '@
const route = useRoute()
const router = useRouter()
const message = useMessage()
const dialog = useDialog()
// 使URL slug
const { pagetypeSlug, entity } = usePageTypeSlug(route)
@ -1051,6 +1084,54 @@ function goBack() {
router.push({ name: 'PageTypeList', params: { entity: pagetypeSlug.value } })
}
//
async function handleRefresh() {
if (loading.value || isNew.value) return
try {
await loadDetail()
} catch (error) {
message.error(t('Failed to refresh'))
console.error('Refresh error:', error)
}
}
//
async function handleDelete() {
if (loading.value || isNew.value) return
const recordName = record.value.name || id.value
if (!recordName) {
message.error(t('Cannot delete record without name'))
return
}
dialog.warning({
title: t('Delete Record'),
content: t('Are you sure you want to delete this record? This action cannot be undone.'),
positiveText: t('Delete'),
negativeText: t('Cancel'),
onPositiveClick: async () => {
loading.value = true
try {
const result = await deleteRecords(entity.value, [recordName])
if (result.success) {
message.success(result.message || t('Deleted successfully'))
//
router.push({ name: 'PageTypeList', params: { entity: pagetypeSlug.value } })
} else {
message.error(result.message || t('Failed to delete'))
}
} catch (error) {
message.error(t('Failed to delete'))
console.error('Delete error:', error)
} finally {
loading.value = false
}
}
})
}
onMounted(async () => {
//
window.addEventListener('keydown', handleKeydownSave, { capture: true })
@ -1543,11 +1624,11 @@ watch(() => route.params.entity, async (newEntity, oldEntity) => {
background: #d1d5db !important;
}
/* 侧边栏位置切换按钮样式 */
.sidebar-position-toggle-btn {
height: 32px !important;
min-width: 32px !important;
padding: 0 8px !important;
/* 头部操作按钮统一样式 */
.header-action-btn {
display: inline-flex;
align-items: center;
justify-content: center;
}
/* 响应式设计 - Naive UI Layout 自动处理 */