优化pagetype默认详情页,更新为支持直接复制详情页工具栏到新的pagetype里面进行修改覆盖默认模板
This commit is contained in:
parent
2760d25b70
commit
67119d3265
@ -17,9 +17,25 @@
|
|||||||
canEdit,
|
canEdit,
|
||||||
loading,
|
loading,
|
||||||
save: handleSave,
|
save: handleSave,
|
||||||
|
refresh: handleRefresh,
|
||||||
|
delete: handleDelete,
|
||||||
|
goBack: goBack,
|
||||||
|
toggleSidebarPosition: toggleSidebarPosition,
|
||||||
|
sidebarPosition,
|
||||||
router,
|
router,
|
||||||
t
|
t
|
||||||
}"
|
}"
|
||||||
|
:entity="entity"
|
||||||
|
:id="id"
|
||||||
|
:record="record"
|
||||||
|
:can-edit="canEdit"
|
||||||
|
:loading="loading"
|
||||||
|
:sidebar-position="sidebarPosition"
|
||||||
|
@toggle-sidebar-position="toggleSidebarPosition"
|
||||||
|
@refresh="handleRefresh"
|
||||||
|
@delete="handleDelete"
|
||||||
|
@go-back="goBack"
|
||||||
|
@save="handleSave"
|
||||||
/>
|
/>
|
||||||
<DefaultToolbar
|
<DefaultToolbar
|
||||||
v-else
|
v-else
|
||||||
|
|||||||
@ -1,5 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-space :size="8">
|
<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>
|
||||||
|
|
||||||
|
<!-- Edit Schema 按钮 -->
|
||||||
<n-button
|
<n-button
|
||||||
type="default"
|
type="default"
|
||||||
size="medium"
|
size="medium"
|
||||||
@ -22,33 +70,79 @@
|
|||||||
:on-save="handleSchemaSave"
|
:on-save="handleSchemaSave"
|
||||||
@close="showSchemaEditor = false"
|
@close="showSchemaEditor = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 返回按钮 -->
|
||||||
|
<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>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
import { NSpace, NButton, NIcon, useMessage } from 'naive-ui'
|
import { NButton, NSpace, NIcon, useMessage } from 'naive-ui'
|
||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
|
import { t } from '@/shared/i18n'
|
||||||
import SchemaEditorModal from '@/core/components/SchemaEditorModal.vue'
|
import SchemaEditorModal from '@/core/components/SchemaEditorModal.vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { get_session_api_headers } from '@/shared/api/auth'
|
||||||
|
|
||||||
const props = defineProps<{ context: {
|
interface Props {
|
||||||
entity: any
|
entity: string
|
||||||
id: any
|
id: string
|
||||||
record: any
|
record?: any
|
||||||
canEdit: any
|
canEdit: boolean
|
||||||
loading: any
|
loading: boolean
|
||||||
save: () => Promise<void> | void
|
sidebarPosition?: 'left' | 'right'
|
||||||
router: any
|
}
|
||||||
t: (k: string) => string
|
|
||||||
} }>()
|
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: () => ({})
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const t = props.context.t
|
|
||||||
const isNew = computed(() => String(props.context.id?.value || props.context.id) === 'new')
|
|
||||||
const showSchemaEditor = ref(false)
|
|
||||||
|
|
||||||
const nodeName = computed(() => String(props.context.id?.value || props.context.id))
|
// 计算是否为新建记录
|
||||||
const nodeRecord = computed(() => props.context.record?.value || props.context.record || {})
|
const isNew = computed(() => {
|
||||||
|
const idValue = props.id
|
||||||
|
return idValue === 'new' || idValue.startsWith('new-')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Schema 编辑器相关
|
||||||
|
const showSchemaEditor = ref(false)
|
||||||
|
const nodeName = computed(() => String(props.id))
|
||||||
|
const nodeRecord = computed(() => props.record || {})
|
||||||
|
|
||||||
function openSchemaEditor() {
|
function openSchemaEditor() {
|
||||||
if (isNew.value) return
|
if (isNew.value) return
|
||||||
@ -63,28 +157,150 @@ function openSchemaEditor() {
|
|||||||
|
|
||||||
async function handleSchemaSave(schemaData: any) {
|
async function handleSchemaSave(schemaData: any) {
|
||||||
try {
|
try {
|
||||||
// 更新本地记录
|
// 保存 Schema 数据到后端
|
||||||
if (props.context.record?.value) {
|
const response = await axios.put(
|
||||||
props.context.record.value.node_schema = schemaData
|
`/api/data/${encodeURIComponent(props.entity)}/${encodeURIComponent(nodeName.value)}`,
|
||||||
} else if (props.context.record) {
|
{
|
||||||
props.context.record.node_schema = schemaData
|
node_schema: schemaData
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
headers: get_session_api_headers(),
|
||||||
|
withCredentials: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// 调用父组件的保存方法(不传参数,让父组件处理)
|
if (response.data?.success !== false) {
|
||||||
if (props.context.save) {
|
// 更新本地记录
|
||||||
await props.context.save()
|
if (props.record) {
|
||||||
|
props.record.node_schema = schemaData
|
||||||
|
}
|
||||||
|
message.success(t('Schema saved successfully'))
|
||||||
|
showSchemaEditor.value = false
|
||||||
} else {
|
} else {
|
||||||
throw new Error('No save method provided')
|
throw new Error(response.data?.message || t('Save failed'))
|
||||||
}
|
}
|
||||||
|
} catch (error: any) {
|
||||||
} catch (e) {
|
console.error('保存 Schema 失败:', error)
|
||||||
throw e // 让组件处理错误显示
|
message.error(error?.response?.data?.message || error?.message || t('Save failed, please check permission and server logs'))
|
||||||
|
throw error // 让组件处理错误显示
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从 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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<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;
|
||||||
|
}
|
||||||
|
|
||||||
/* 工具栏按钮基础样式 - 与返回按钮一致,使用badge配色方案 */
|
/* 工具栏按钮基础样式 - 与返回按钮一致,使用badge配色方案 */
|
||||||
.toolbar-btn {
|
.toolbar-btn {
|
||||||
background: #f3f4f6 !important;
|
background: #f3f4f6 !important;
|
||||||
@ -136,3 +352,4 @@ async function handleSchemaSave(schemaData: any) {
|
|||||||
border-color: transparent !important;
|
border-color: transparent !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user