实现pagetype列表页弹窗新建pagetype的功能

This commit is contained in:
jingrow 2026-01-24 05:49:12 +08:00
parent 7aba11a31e
commit e529a35280

View File

@ -284,12 +284,131 @@
</div>
</div>
</div>
<!-- 创建PageType模态对话框 -->
<n-modal
v-model:show="showCreateModal"
preset="dialog"
:title="t('Create PageType')"
:positive-text="t('Create and Continue')"
:negative-text="t('Cancel')"
:loading="creating"
@positive-click="handleCreatePageType"
style="width: 600px"
>
<div style="padding: 16px 0">
<!-- 第一行名称扩展包模块 -->
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; margin-bottom: 16px">
<div>
<div style="margin-bottom: 6px; font-weight: 500; color: #374151; font-size: 13px">
{{ t('Name') }} <span style="color: #ef4444">*</span>
</div>
<n-input
v-model:value="newPageTypeName"
:placeholder="t('Enter name')"
:disabled="creating"
size="small"
/>
</div>
<div>
<div style="margin-bottom: 6px; font-weight: 500; color: #374151; font-size: 13px">
{{ t('Extends') }}
</div>
<n-select
v-model:value="newPageTypeExtends"
:options="packageOptions"
:placeholder="t('Enter extends')"
:disabled="creating"
:loading="loadingPackages"
filterable
clearable
size="small"
:show-arrow="false"
class="no-dropdown-icon"
/>
</div>
<div>
<div style="margin-bottom: 6px; font-weight: 500; color: #374151; font-size: 13px">
{{ t('Module') }} <span style="color: #ef4444">*</span>
</div>
<n-select
v-model:value="newPageTypeModule"
:options="moduleOptions"
:placeholder="t('Enter module')"
:disabled="creating"
:loading="loadingModules"
filterable
clearable
size="small"
:show-arrow="false"
class="no-dropdown-icon"
/>
</div>
</div>
<!-- 复选框选项 -->
<div style="display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsSubmittable" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Submittable') }}</span>
</n-checkbox>
</div>
<div style="font-size: 12px; color: #6b7280; margin-top: -8px; margin-left: 24px">
{{ t('Submittable documents can be submitted and modified, can only be modified or deleted after submission') }}
</div>
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsChild" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Child Table') }}</span>
</n-checkbox>
</div>
<div style="font-size: 12px; color: #6b7280; margin-top: -8px; margin-left: 24px">
{{ t('Child table will be displayed in the form of table collection in the parent PageType') }}
</div>
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsSingle" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Single') }}</span>
</n-checkbox>
</div>
<div style="font-size: 12px; color: #6b7280; margin-top: -8px; margin-left: 24px">
{{ t('Single type has only one record, without name field, saved in tabSingles') }}
</div>
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsTree" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Tree') }}</span>
</n-checkbox>
</div>
<div style="font-size: 12px; color: #6b7280; margin-top: -8px; margin-left: 24px">
{{ t('Tree structure uses parent node collection for nested display') }}
</div>
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsVirtual" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Virtual') }}</span>
</n-checkbox>
</div>
<div style="display: flex; align-items: flex-start">
<n-checkbox v-model:checked="newPageTypeIsTable" :disabled="creating" size="small">
<span style="font-size: 13px">{{ t('Is Table') }}</span>
</n-checkbox>
</div>
</div>
<!-- 提示信息 -->
<div style="margin-top: 16px; padding: 8px 12px; background: #f0f9ff; border-radius: 6px; font-size: 12px; color: #0369a1">
{{ t('The system will automatically generate a friendly URL based on the name') }}
</div>
</div>
</n-modal>
</template>
<script setup lang="ts">
import { onMounted, ref, computed, watch, shallowRef, markRaw } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NPagination, useMessage, useDialog } from 'naive-ui'
import { NPagination, NModal, NInput, NButton, NCheckbox, NSelect, useMessage, useDialog } from 'naive-ui'
import { Icon } from '@iconify/vue'
import axios from 'axios'
import { t } from '@/shared/i18n'
@ -342,6 +461,25 @@ const viewMode = ref<'card' | 'list'>(
//
const filters = ref<Record<string, any>>({})
// PageType
const showCreateModal = ref(false)
const newPageTypeName = ref('')
const newPageTypeModule = ref('')
const newPageTypeExtends = ref('')
const newPageTypeIsSubmittable = ref(false)
const newPageTypeIsChild = ref(false)
const newPageTypeIsSingle = ref(false)
const newPageTypeIsTree = ref(false)
const newPageTypeIsVirtual = ref(false)
const newPageTypeIsTable = ref(false)
const creating = ref(false)
//
const moduleOptions = ref<Array<{label: string; value: string}>>([])
const packageOptions = ref<Array<{label: string; value: string}>>([])
const loadingModules = ref(false)
const loadingPackages = ref(false)
//
function onFilterChange() {
page.value = 1 //
@ -1027,11 +1165,181 @@ async function handleDeleteSelected() {
}
function createRecordHandler() {
// PageType
if (entity.value === 'PageType') {
showCreatePageTypeDialog()
return
}
// name
const randomStr = Math.random().toString(36).substring(2, 12)
const tempName = `new-${pagetypeSlug.value}-${randomStr}`
openDetail(tempName)
}
// PageType
function showCreatePageTypeDialog() {
newPageTypeName.value = ''
newPageTypeModule.value = ''
newPageTypeExtends.value = ''
newPageTypeIsSubmittable.value = false
newPageTypeIsChild.value = false
newPageTypeIsSingle.value = false
newPageTypeIsTree.value = false
newPageTypeIsVirtual.value = false
newPageTypeIsTable.value = false
showCreateModal.value = true
//
loadModules()
loadPackages()
}
//
async function loadModules() {
if (moduleOptions.value.length > 0) return //
loadingModules.value = true
try {
// 使jingrow /api/data/Module Def
const response = await axios.get('/api/data/Module Def', {
params: {
fields: JSON.stringify(['name']),
order_by: 'name asc',
limit_page_length: 1000
},
headers: get_session_api_headers(),
withCredentials: true
})
const modules = response.data?.data || []
moduleOptions.value = modules.map((m: any) => ({
label: m.name,
value: m.name
}))
} catch (error) {
console.error('Load modules error:', error)
} finally {
loadingModules.value = false
}
}
//
async function loadPackages() {
if (packageOptions.value.length > 0) return //
loadingPackages.value = true
try {
// 使jingrow /api/data/Package
const response = await axios.get('/api/data/Package', {
params: {
fields: JSON.stringify(['name']),
order_by: 'name asc',
limit_page_length: 1000
},
headers: get_session_api_headers(),
withCredentials: true
})
const packages = response.data?.data || []
packageOptions.value = packages.map((p: any) => ({
label: p.name,
value: p.name
}))
} catch (error) {
console.error('Load packages error:', error)
} finally {
loadingPackages.value = false
}
}
// PageType
async function handleCreatePageType() {
if (!newPageTypeName.value.trim()) {
message.error(t('Please enter PageType name'))
return
}
if (!newPageTypeModule.value || !newPageTypeModule.value.trim()) {
message.error(t('Please select module'))
return
}
creating.value = true
try {
// namejingrow
const inputName = newPageTypeName.value.trim()
//
const createData: Record<string, any> = {
name: inputName, //
module: newPageTypeModule.value.trim() //
}
//
if (newPageTypeExtends.value && newPageTypeExtends.value.trim()) {
createData.extends = newPageTypeExtends.value.trim()
}
if (newPageTypeIsSubmittable.value) {
createData.is_submittable = 1
}
if (newPageTypeIsChild.value) {
createData.is_child_table = 1
}
if (newPageTypeIsSingle.value) {
createData.issingle = 1
}
if (newPageTypeIsTree.value) {
createData.is_tree = 1
}
if (newPageTypeIsVirtual.value) {
createData.is_virtual = 1
}
if (newPageTypeIsTable.value) {
createData.istable = 1
}
console.log('[CreatePageType] 准备创建PageType:', inputName)
console.log('[CreatePageType] 创建数据:', createData)
const res = await axios.post(
`/api/data/PageType`,
createData,
{
headers: get_session_api_headers(),
withCredentials: true
}
)
console.log('[CreatePageType] API响应:', res)
console.log('[CreatePageType] 响应data:', res.data)
console.log('[CreatePageType] 响应data.data:', res.data?.data)
// res.data.data
if (res.data?.data) {
const createdRecord = res.data.data
const recordName = createdRecord.name || inputName
console.log('[CreatePageType] 创建成功,记录名称:', recordName)
message.success(t('Created successfully'))
showCreateModal.value = false
// PageType
openDetail(recordName)
} else {
console.error('[CreatePageType] 响应数据格式异常:', res.data)
message.error(t('Create failed') + ': ' + t('Invalid response format'))
}
} catch (error: any) {
console.error('[CreatePageType] 创建失败:', error)
console.error('[CreatePageType] 错误详情:', error?.response?.data)
const errorMsg = error?.response?.data?.detail || error?.response?.data?.message || error?.message || t('Create failed')
message.error(errorMsg)
} finally {
creating.value = false
}
}
function editRecord(row: any) {
openDetail(row.name)
}
@ -1599,6 +1907,7 @@ function formatDisplayValue(value: any, fieldName: string) {
text-overflow: ellipsis;
white-space: nowrap;
}
</style>