实现pagetype列表页弹窗新建pagetype的功能
This commit is contained in:
parent
7aba11a31e
commit
e529a35280
@ -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 {
|
||||
// 保持name原样(包含空格),与jingrow系统一致
|
||||
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>
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user