pagetype详情页拆分工具栏为独立的子组件
This commit is contained in:
parent
aa06768238
commit
2760d25b70
@ -7,54 +7,6 @@
|
|||||||
<h1 class="page-title">{{ pageTitle }}</h1>
|
<h1 class="page-title">{{ pageTitle }}</h1>
|
||||||
<p class="page-description">{{ pageDescription }}</p>
|
<p class="page-description">{{ pageDescription }}</p>
|
||||||
</div>
|
</div>
|
||||||
<n-space align="center">
|
|
||||||
<!-- 侧边栏位置切换按钮 -->
|
|
||||||
<n-button
|
|
||||||
type="default"
|
|
||||||
size="medium"
|
|
||||||
@click="toggleSidebarPosition"
|
|
||||||
:title="sidebarPosition === 'left' ? '切换到右侧' : '切换到左侧'"
|
|
||||||
class="header-action-btn"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<Icon :icon="sidebarPosition === 'left' ? 'fluent:panel-right-16-regular' : 'fluent:panel-left-16-regular'" />
|
|
||||||
</n-icon>
|
|
||||||
</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 delete-btn"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<Icon icon="tabler:trash" />
|
|
||||||
</n-icon>
|
|
||||||
</template>
|
|
||||||
</n-button>
|
|
||||||
|
|
||||||
<component
|
<component
|
||||||
v-if="toolbarComponent"
|
v-if="toolbarComponent"
|
||||||
:is="toolbarComponent"
|
:is="toolbarComponent"
|
||||||
@ -69,21 +21,20 @@
|
|||||||
t
|
t
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<n-button type="default" size="medium" @click="goBack" :disabled="loading">
|
<DefaultToolbar
|
||||||
<template #icon>
|
v-else
|
||||||
<n-icon><Icon icon="tabler:arrow-left" /></n-icon>
|
:entity="entity"
|
||||||
</template>
|
:id="id"
|
||||||
{{ t('Back') }}
|
:record="record"
|
||||||
</n-button>
|
:can-edit="canEdit"
|
||||||
<n-button type="primary" size="medium" :disabled="loading" @click="handleSave" v-if="canEdit" class="save-btn-brand">
|
:loading="loading"
|
||||||
<template #icon>
|
:sidebar-position="sidebarPosition"
|
||||||
<n-icon>
|
@toggle-sidebar-position="toggleSidebarPosition"
|
||||||
<Icon icon="tabler:check" />
|
@refresh="handleRefresh"
|
||||||
</n-icon>
|
@delete="handleDelete"
|
||||||
</template>
|
@go-back="goBack"
|
||||||
{{ t('Save') }}
|
@save="handleSave"
|
||||||
</n-button>
|
/>
|
||||||
</n-space>
|
|
||||||
</n-space>
|
</n-space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -321,6 +272,7 @@ import { updateRecord, getRecord, getRecordAttachments, deleteAttachment, upload
|
|||||||
import { downloadImageToLocal } from '@/shared/api/common'
|
import { downloadImageToLocal } from '@/shared/api/common'
|
||||||
import { usePageTypeSlug } from '@/shared/utils/slug'
|
import { usePageTypeSlug } from '@/shared/utils/slug'
|
||||||
import { resolvePagetypeToolbarOverride } from '@/core/registry/pagetypeOverride'
|
import { resolvePagetypeToolbarOverride } from '@/core/registry/pagetypeOverride'
|
||||||
|
import DefaultToolbar from './default_toolbar.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -1618,98 +1570,6 @@ watch(() => route.params.entity, async (newEntity, oldEntity) => {
|
|||||||
background: #d1d5db !important;
|
background: #d1d5db !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 头部操作按钮统一样式 */
|
|
||||||
.header-action-btn {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 删除按钮悬浮时使用红色 */
|
|
||||||
.header-action-btn.delete-btn:hover:not(:disabled) {
|
|
||||||
background: #ef4444 !important;
|
|
||||||
border-color: #ef4444 !important;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__border),
|
|
||||||
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__state-border) {
|
|
||||||
border-color: #ef4444 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 保存按钮 - 使用柔和的品牌色系,与列表页创建按钮一致 */
|
|
||||||
.save-btn-brand {
|
|
||||||
background: #e6f8f0 !important;
|
|
||||||
border: 1px solid #1fc76f !important;
|
|
||||||
color: #0d684b !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand :deep(.n-button__border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand :deep(.n-button__state-border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:hover {
|
|
||||||
background: #dcfce7 !important;
|
|
||||||
border-color: #1fc76f !important;
|
|
||||||
border: 1px solid #1fc76f !important;
|
|
||||||
color: #166534 !important;
|
|
||||||
box-shadow: 0 2px 8px rgba(31, 199, 111, 0.15) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:hover :deep(.n-button__border),
|
|
||||||
.save-btn-brand:hover :deep(.n-button__state-border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:focus {
|
|
||||||
background: #dcfce7 !important;
|
|
||||||
border-color: #1fc76f !important;
|
|
||||||
border: 1px solid #1fc76f !important;
|
|
||||||
color: #166534 !important;
|
|
||||||
box-shadow: 0 0 0 2px rgba(31, 199, 111, 0.2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:focus :deep(.n-button__border),
|
|
||||||
.save-btn-brand:focus :deep(.n-button__state-border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:active {
|
|
||||||
background: #1fc76f !important;
|
|
||||||
border-color: #1fc76f !important;
|
|
||||||
border: 1px solid #1fc76f !important;
|
|
||||||
color: white !important;
|
|
||||||
box-shadow: 0 1px 4px rgba(31, 199, 111, 0.2) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:active :deep(.n-button__border),
|
|
||||||
.save-btn-brand:active :deep(.n-button__state-border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:disabled {
|
|
||||||
background: #f1f5f9 !important;
|
|
||||||
border: 1px solid #e2e8f0 !important;
|
|
||||||
border-color: #e2e8f0 !important;
|
|
||||||
color: #94a3b8 !important;
|
|
||||||
opacity: 0.6 !important;
|
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn-brand:disabled :deep(.n-button__border),
|
|
||||||
.save-btn-brand:disabled :deep(.n-button__state-border) {
|
|
||||||
border: none !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式设计 - Naive UI Layout 自动处理 */
|
/* 响应式设计 - Naive UI Layout 自动处理 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|||||||
228
apps/jingrow/frontend/src/core/pagetype/default_toolbar.vue
Normal file
228
apps/jingrow/frontend/src/core/pagetype/default_toolbar.vue
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<n-space align="center">
|
||||||
|
<!-- 侧边栏位置切换按钮 -->
|
||||||
|
<n-button
|
||||||
|
type="default"
|
||||||
|
size="medium"
|
||||||
|
@click="$emit('toggle-sidebar-position')"
|
||||||
|
:title="sidebarPosition === 'left' ? '切换到右侧' : '切换到左侧'"
|
||||||
|
class="header-action-btn"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<Icon :icon="sidebarPosition === 'left' ? 'fluent:panel-right-16-regular' : 'fluent:panel-left-16-regular'" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
|
||||||
|
<!-- 刷新按钮 -->
|
||||||
|
<n-button
|
||||||
|
type="default"
|
||||||
|
size="medium"
|
||||||
|
@click="$emit('refresh')"
|
||||||
|
: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="$emit('delete')"
|
||||||
|
:disabled="loading || isNew"
|
||||||
|
:title="t('Delete')"
|
||||||
|
class="header-action-btn delete-btn"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<Icon icon="tabler:trash" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
|
||||||
|
<!-- 返回按钮 -->
|
||||||
|
<n-button type="default" size="medium" @click="$emit('go-back')" :disabled="loading">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon><Icon icon="tabler:arrow-left" /></n-icon>
|
||||||
|
</template>
|
||||||
|
{{ t('Back') }}
|
||||||
|
</n-button>
|
||||||
|
|
||||||
|
<!-- 保存按钮 -->
|
||||||
|
<n-button
|
||||||
|
type="primary"
|
||||||
|
size="medium"
|
||||||
|
:disabled="loading"
|
||||||
|
@click="$emit('save')"
|
||||||
|
v-if="canEdit"
|
||||||
|
class="save-btn-brand"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<Icon icon="tabler:check" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
{{ t('Save') }}
|
||||||
|
</n-button>
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
|
import { NButton, NSpace, NIcon } from 'naive-ui'
|
||||||
|
import { Icon } from '@iconify/vue'
|
||||||
|
import { t } from '@/shared/i18n'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
entity: string
|
||||||
|
id: string
|
||||||
|
record?: any
|
||||||
|
canEdit: boolean
|
||||||
|
loading: boolean
|
||||||
|
sidebarPosition?: 'left' | 'right'
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'toggle-sidebar-position'): void
|
||||||
|
(e: 'refresh'): void
|
||||||
|
(e: 'delete'): void
|
||||||
|
(e: 'go-back'): void
|
||||||
|
(e: 'save'): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
sidebarPosition: 'left',
|
||||||
|
record: () => ({})
|
||||||
|
})
|
||||||
|
|
||||||
|
defineEmits<Emits>()
|
||||||
|
|
||||||
|
// 计算是否为新建记录
|
||||||
|
const isNew = computed(() => {
|
||||||
|
const idValue = props.id
|
||||||
|
return idValue === 'new' || idValue.startsWith('new-')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 从 localStorage 读取侧边栏位置(如果父组件没有传入)
|
||||||
|
const sidebarPosition = ref<'left' | 'right'>(props.sidebarPosition || 'left')
|
||||||
|
|
||||||
|
// 监听 props 变化
|
||||||
|
watch(() => props.sidebarPosition, (newPos) => {
|
||||||
|
if (newPos) {
|
||||||
|
sidebarPosition.value = newPos
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 如果没有传入 sidebarPosition,尝试从 localStorage 读取
|
||||||
|
if (!props.sidebarPosition) {
|
||||||
|
const savedPosition = localStorage.getItem('jingrow-sidebar-position')
|
||||||
|
if (savedPosition === 'left' || savedPosition === 'right') {
|
||||||
|
sidebarPosition.value = savedPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 头部操作按钮统一样式 */
|
||||||
|
.header-action-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 删除按钮悬浮时使用红色 */
|
||||||
|
.header-action-btn.delete-btn:hover:not(:disabled) {
|
||||||
|
background: #ef4444 !important;
|
||||||
|
border-color: #ef4444 !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__border),
|
||||||
|
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__state-border) {
|
||||||
|
border-color: #ef4444 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 保存按钮 - 使用柔和的品牌色系,与列表页创建按钮一致 */
|
||||||
|
.save-btn-brand {
|
||||||
|
background: #e6f8f0 !important;
|
||||||
|
border: 1px solid #1fc76f !important;
|
||||||
|
color: #0d684b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand :deep(.n-button__border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand :deep(.n-button__state-border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:hover {
|
||||||
|
background: #dcfce7 !important;
|
||||||
|
border-color: #1fc76f !important;
|
||||||
|
border: 1px solid #1fc76f !important;
|
||||||
|
color: #166534 !important;
|
||||||
|
box-shadow: 0 2px 8px rgba(31, 199, 111, 0.15) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:hover :deep(.n-button__border),
|
||||||
|
.save-btn-brand:hover :deep(.n-button__state-border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:focus {
|
||||||
|
background: #dcfce7 !important;
|
||||||
|
border-color: #1fc76f !important;
|
||||||
|
border: 1px solid #1fc76f !important;
|
||||||
|
color: #166534 !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(31, 199, 111, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:focus :deep(.n-button__border),
|
||||||
|
.save-btn-brand:focus :deep(.n-button__state-border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:active {
|
||||||
|
background: #1fc76f !important;
|
||||||
|
border-color: #1fc76f !important;
|
||||||
|
border: 1px solid #1fc76f !important;
|
||||||
|
color: white !important;
|
||||||
|
box-shadow: 0 1px 4px rgba(31, 199, 111, 0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:active :deep(.n-button__border),
|
||||||
|
.save-btn-brand:active :deep(.n-button__state-border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:disabled {
|
||||||
|
background: #f1f5f9 !important;
|
||||||
|
border: 1px solid #e2e8f0 !important;
|
||||||
|
border-color: #e2e8f0 !important;
|
||||||
|
color: #94a3b8 !important;
|
||||||
|
opacity: 0.6 !important;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn-brand:disabled :deep(.n-button__border),
|
||||||
|
.save-btn-brand:disabled :deep(.n-button__state-border) {
|
||||||
|
border: none !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user