修复编辑pagetype字段后无法保存的问题
This commit is contained in:
parent
e529a35280
commit
50f99f64d9
@ -14,45 +14,53 @@ import TextControl from "./components/controls/TextControl.vue";
|
|||||||
import TextEditorControl from "./components/controls/TextEditorControl.vue";
|
import TextEditorControl from "./components/controls/TextEditorControl.vue";
|
||||||
|
|
||||||
export function registerGlobalComponents(app) {
|
export function registerGlobalComponents(app) {
|
||||||
app.component("AttachControl", AttachControl)
|
// Helper function to safely register component
|
||||||
.component("AttachImageControl", AttachControl)
|
const safeRegister = (name, component) => {
|
||||||
.component("AutocompleteControl", DataControl)
|
if (!app.component(name)) {
|
||||||
.component("BarcodeControl", DataControl)
|
app.component(name, component);
|
||||||
.component("ButtonControl", ButtonControl)
|
}
|
||||||
.component("CheckControl", CheckControl)
|
return app;
|
||||||
.component("CodeControl", CodeControl)
|
};
|
||||||
.component("ColorControl", DataControl)
|
|
||||||
.component("CurrencyControl", DataControl)
|
safeRegister("AttachControl", AttachControl);
|
||||||
.component("DataControl", DataControl)
|
safeRegister("AttachImageControl", AttachControl);
|
||||||
.component("DateControl", DataControl)
|
safeRegister("AutocompleteControl", DataControl);
|
||||||
.component("DatetimeControl", DataControl)
|
safeRegister("BarcodeControl", DataControl);
|
||||||
.component("DurationControl", DataControl)
|
safeRegister("ButtonControl", ButtonControl);
|
||||||
.component("DynamicLinkControl", DataControl)
|
safeRegister("CheckControl", CheckControl);
|
||||||
.component("FloatControl", DataControl)
|
safeRegister("CodeControl", CodeControl);
|
||||||
.component("GeolocationControl", GeolocationControl)
|
safeRegister("ColorControl", DataControl);
|
||||||
.component("HeadingControl", ButtonControl)
|
safeRegister("CurrencyControl", DataControl);
|
||||||
.component("HTMLControl", DataControl)
|
safeRegister("DataControl", DataControl);
|
||||||
.component("HTMLEditorControl", CodeControl)
|
safeRegister("DateControl", DataControl);
|
||||||
.component("IconControl", DataControl)
|
safeRegister("DatetimeControl", DataControl);
|
||||||
.component("ImageControl", ImageControl)
|
safeRegister("DurationControl", DataControl);
|
||||||
.component("IntControl", DataControl)
|
safeRegister("DynamicLinkControl", DataControl);
|
||||||
.component("JSONControl", CodeControl)
|
safeRegister("FloatControl", DataControl);
|
||||||
.component("LinkControl", LinkControl)
|
safeRegister("GeolocationControl", GeolocationControl);
|
||||||
.component("LongTextControl", TextControl)
|
safeRegister("HeadingControl", ButtonControl);
|
||||||
.component("MarkdownEditorControl", CodeControl)
|
safeRegister("HTMLControl", DataControl);
|
||||||
.component("PasswordControl", DataControl)
|
safeRegister("HTMLEditorControl", CodeControl);
|
||||||
.component("PercentControl", DataControl)
|
safeRegister("IconControl", DataControl);
|
||||||
.component("PhoneControl", DataControl)
|
safeRegister("ImageControl", ImageControl);
|
||||||
.component("ReadOnlyControl", DataControl)
|
safeRegister("IntControl", DataControl);
|
||||||
.component("RatingControl", RatingControl)
|
safeRegister("JSONControl", CodeControl);
|
||||||
.component("SelectControl", SelectControl)
|
safeRegister("LinkControl", LinkControl);
|
||||||
.component("SignatureControl", SignatureControl)
|
safeRegister("LongTextControl", TextControl);
|
||||||
.component("SmallTextControl", TextControl)
|
safeRegister("MarkdownEditorControl", CodeControl);
|
||||||
.component("TableControl", TableControl)
|
safeRegister("PasswordControl", DataControl);
|
||||||
.component("TableMultiSelectControl", DataControl)
|
safeRegister("PercentControl", DataControl);
|
||||||
.component("TextControl", TextControl)
|
safeRegister("PhoneControl", DataControl);
|
||||||
.component("TextEditorControl", TextEditorControl)
|
safeRegister("ReadOnlyControl", DataControl);
|
||||||
.component("TimeControl", DataControl);
|
safeRegister("RatingControl", RatingControl);
|
||||||
|
safeRegister("SelectControl", SelectControl);
|
||||||
|
safeRegister("SignatureControl", SignatureControl);
|
||||||
|
safeRegister("SmallTextControl", TextControl);
|
||||||
|
safeRegister("TableControl", TableControl);
|
||||||
|
safeRegister("TableMultiSelectControl", DataControl);
|
||||||
|
safeRegister("TextControl", TextControl);
|
||||||
|
safeRegister("TextEditorControl", TextEditorControl);
|
||||||
|
safeRegister("TimeControl", DataControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const controls = {
|
export const controls = {
|
||||||
|
|||||||
@ -986,6 +986,12 @@ async function loadDetail() {
|
|||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
async function handleSave() {
|
async function handleSave() {
|
||||||
|
// 触发自定义事件,通知所有 FormBuilder 同步 fields
|
||||||
|
window.dispatchEvent(new CustomEvent('sync-form-builder-fields'))
|
||||||
|
|
||||||
|
// 等待一帧,确保 fields 已同步
|
||||||
|
await new Promise(resolve => requestAnimationFrame(resolve))
|
||||||
|
|
||||||
// 脏检查:无改动则不保存
|
// 脏检查:无改动则不保存
|
||||||
try {
|
try {
|
||||||
if (JSON.stringify(record.value) === JSON.stringify(originalRecord.value)) {
|
if (JSON.stringify(record.value) === JSON.stringify(originalRecord.value)) {
|
||||||
@ -1026,7 +1032,17 @@ async function handleSave() {
|
|||||||
}, 1500)
|
}, 1500)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const res = await updateRecord(entity.value, id.value, record.value)
|
// 准备发送的数据:如果 fields 是字符串,解析为数组(Jingrow API 要求)
|
||||||
|
const dataToSend = { ...record.value }
|
||||||
|
if (typeof dataToSend.fields === 'string') {
|
||||||
|
try {
|
||||||
|
dataToSend.fields = JSON.parse(dataToSend.fields)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse fields:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await updateRecord(entity.value, id.value, dataToSend)
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
message.success(t('Saved successfully'))
|
message.success(t('Saved successfully'))
|
||||||
// 保存成功更新快照
|
// 保存成功更新快照
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
import FormBuilderComponent from '@/core/features/form_builder/FormBuilder.vue'
|
import FormBuilderComponent from '@/core/features/form_builder/FormBuilder.vue'
|
||||||
import { useMessage } from 'naive-ui'
|
import { useMessage } from 'naive-ui'
|
||||||
|
|
||||||
const props = defineProps<{ df: any; record: Record<string, any>; canEdit: boolean; ctx: any }>()
|
const props = defineProps<{ df: any; record: Record<string, any>; canEdit: boolean; ctx: any }>()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
|
// FormBuilder ref
|
||||||
|
const formBuilderRef = ref<InstanceType<typeof FormBuilderComponent> | null>(null)
|
||||||
|
|
||||||
// Label布局:上下结构(vertical) 或 左右结构(horizontal)
|
// Label布局:上下结构(vertical) 或 左右结构(horizontal)
|
||||||
const labelLayout = computed(() => props.df.label_layout || 'vertical')
|
const labelLayout = computed(() => props.df.label_layout || 'vertical')
|
||||||
|
|
||||||
@ -30,6 +33,42 @@ const fields = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 获取最新的 fields(供父组件调用)
|
||||||
|
function getLatestFields() {
|
||||||
|
if (formBuilderRef.value) {
|
||||||
|
return formBuilderRef.value.getFields()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步 fields 到 record(在保存前调用)
|
||||||
|
function syncFieldsToRecord() {
|
||||||
|
if (!isFormBuilder.value || !props.canEdit) return
|
||||||
|
|
||||||
|
const latestFields = getLatestFields()
|
||||||
|
if (latestFields && props.record) {
|
||||||
|
try {
|
||||||
|
props.record.fields = JSON.stringify(latestFields)
|
||||||
|
console.log('[HTML.vue] Synced latest fields to record before save')
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[HTML.vue] Failed to sync fields:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听全局保存事件
|
||||||
|
function handleSyncEvent() {
|
||||||
|
syncFieldsToRecord()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('sync-form-builder-fields', handleSyncEvent)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('sync-form-builder-fields', handleSyncEvent)
|
||||||
|
})
|
||||||
|
|
||||||
// Handle field updates from form builder
|
// Handle field updates from form builder
|
||||||
function handleFieldsUpdate(newFields: any[]) {
|
function handleFieldsUpdate(newFields: any[]) {
|
||||||
if (props.canEdit && isFormBuilder.value) {
|
if (props.canEdit && isFormBuilder.value) {
|
||||||
@ -55,14 +94,21 @@ function handleSave(newFields: any[]) {
|
|||||||
|
|
||||||
// Handle dirty state change
|
// Handle dirty state change
|
||||||
function handleDirtyChange(isDirty: boolean) {
|
function handleDirtyChange(isDirty: boolean) {
|
||||||
// Form builder dirty state changed
|
// 不在这里同步 fields,避免触发组件重新渲染导致输入失焦
|
||||||
|
// fields 只在保存时同步
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expose methods to parent
|
||||||
|
defineExpose({
|
||||||
|
getLatestFields
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- 如果是form_builder字段,渲染Form Builder组件 -->
|
<!-- 如果是form_builder字段,渲染Form Builder组件 -->
|
||||||
<div v-if="isFormBuilder" class="form-builder-field">
|
<div v-if="isFormBuilder" class="form-builder-field">
|
||||||
<FormBuilderComponent
|
<FormBuilderComponent
|
||||||
|
ref="formBuilderRef"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
:pagetype="pagetypeName"
|
:pagetype="pagetypeName"
|
||||||
:pagetype-record="record"
|
:pagetype-record="record"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user