Files
2026-09-12 12:07:15 +08:00

447 lines
14 KiB
Smarty
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<basicModal
@register="modalRegister"
ref="modalRef"
class="basicModal basicFormModal"
@on-ok="handleSubmit"
@on-close="dialogClose"
>
<template #default>
<n-form
class="ls-form"
ref="formRef"
:model="formData"
label-placement="left"
label-width="80px"
>
{% for field in form_fields %}
{% if field.is_image %}
<!-- {{ field.comment }}(图片上传) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请上传{{ field.comment }}', trigger: 'change' }"
{% endif %}
>
<UploadImg
@change-file-name="(name) => (formData.{{ field.camel_name }}ImgName = name)"
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif', 'image/webp']"
name="{{ app_name }}"
:fileSize="20"
v-model:image-url="formData.{{ field.camel_name }}"
>
<template #tip>支持扩展名: jpg png jpeg gif webp; 文件大小不超过20M</template>
</UploadImg>
</n-form-item>
{% elif field.is_rich_text %}
<!-- {{ field.comment }}(富文本编辑器) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<div class="flex w-full">
<Editor
ref="{{ field.camel_name }}EditorRef"
:height="editorHeight"
class="flex-1"
name="{{ app_name }}"
/>
</div>
</n-form-item>
{% elif field.type == 'CharField' and ('备注' in field.comment or '介绍' in field.comment or '描述' in field.comment or '说明' in field.comment) %}
<!-- {{ field.comment }}(多行文本) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<n-input
type="textarea"
v-model:value="formData.{{ field.camel_name }}"
placeholder="请输入{{ field.comment }}"
:rows="3"
clearable
/>
</n-form-item>
{% elif field.type == 'CharField' %}
<!-- {{ field.comment }} -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<n-input
class="ls-input"
v-model:value="formData.{{ field.camel_name }}"
placeholder="请输入{{ field.comment }}"
clearable
/>
</n-form-item>
{% elif field.type == 'IntegerField' and field.choices %}
<!-- {{ field.comment }}({% if field.choices|length <= 2 %}单选{% else %}下拉选择{% endif %}) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ type: 'number', required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
{% endif %}
>
{% if field.choices|length <= 2 %}
<n-radio-group v-model:value="formData.{{ field.camel_name }}">
{% for choice in field.choices %}
<n-radio :value="{{ choice.value }}">{{ choice.label }}</n-radio>
{% endfor %}
</n-radio-group>
{% else %}
<n-select
v-model:value="formData.{{ field.camel_name }}"
placeholder="请选择{{ field.comment }}"
clearable
filterable
:options="optionsData.{{ field.camel_name }}List"
/>
{% endif %}
</n-form-item>
{% elif field.type == 'IntegerField' and not field.choices %}
<!-- {{ field.comment }}(数字输入) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<n-input-number
v-model:value="formData.{{ field.camel_name }}"
:min="{{ field.min_value or 0 }}"
:max="{{ field.max_value or 99999 }}"
/>
</n-form-item>
{% elif field.type == 'BooleanField' %}
<!-- {{ field.comment }}(开关) -->
<n-form-item label="{{ field.label }}" path="{{ field.camel_name }}">
<n-switch
v-model:value="formData.{{ field.camel_name }}"
:checked-value="1"
:unchecked-value="0"
/>
</n-form-item>
{% elif field.type == 'DateField' %}
<!-- {{ field.comment }}(日期选择) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
{% endif %}
>
<n-date-picker
v-model:value="formData.{{ field.camel_name }}"
type="date"
placeholder="请选择{{ field.comment }}"
format="yyyy-MM-dd"
/>
</n-form-item>
{% elif field.type == 'DateTimeField' %}
<!-- {{ field.comment }}(日期时间选择) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
{% endif %}
>
<n-date-picker
v-model:value="formData.{{ field.camel_name }}"
type="datetime"
placeholder="请选择{{ field.comment }}"
format="yyyy-MM-dd HH:mm:ss"
/>
</n-form-item>
{% elif field.type == 'TextField' %}
<!-- {{ field.comment }}(文本域) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<n-input
type="textarea"
v-model:value="formData.{{ field.camel_name }}"
placeholder="请输入{{ field.comment }}"
:rows="3"
/>
</n-form-item>
{% elif field.type == 'FloatField' or field.type == 'DecimalField' %}
<!-- {{ field.comment }}(数字输入) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
{% endif %}
>
<n-input-number
v-model:value="formData.{{ field.camel_name }}"
:min="{{ field.min_value or 0 }}"
:max="{{ field.max_value or 999999 }}"
:precision="2"
:step="0.1"
/>
</n-form-item>
{% endif %}
{% endfor %}
</n-form>
</template>
</basicModal>
</template>
<script lang="ts" setup>
import { get{{ model_class_name }}Detail, {{ model_class_name_camel }}Add, {{ model_class_name_camel }}Update } from '@/api/{{ api_path }}';
import { onMounted, reactive, ref, watch } from 'vue';
import { useMessage } from 'naive-ui';
import { useModal } from '@/components/Modal';
{% if has_image_field %}
import UploadImg from '@/components/Upload/Image.vue';
{% endif %}
{% if has_rich_text_field %}
import Editor from '@/components/Editor/tinymce.vue';
{% endif %}
// 定义事件
const emit = defineEmits(['success', 'update:visible']);
// 消息提示
const message = useMessage();
// 表单引用
const formRef = ref();
{% if has_rich_text_field %}
// 富文本编辑器高度
const editorHeight = document.body.clientHeight - 400;
// 富文本编辑器引用
{% for field in form_fields %}
{% if field.is_rich_text %}
const {{ field.camel_name }}EditorRef = ref();
{% endif %}
{% endfor %}
{% endif %}
/**
* 定义选项数据
*/
const optionsData = reactive({
{% for field in form_fields %}
{% if field.type == 'IntegerField' and field.choices and field.choices|length > 2 %}
{{ field.camel_name }}List: [
{% for choice in field.choices %}
{
label: '{{ choice.label }}',
value: {% if choice.value_type == 'string' %}'{{ choice.value }}'{% else %}{{ choice.value }}{% endif %},
},
{% endfor %}
],
{% endif %}
{% endfor %}
});
/**
* 定义表单数据
* 初始化默认值
*/
const formData = reactive({
id: '', // ID字段,新增时为0
{% for field in form_fields %}
{{ field.camel_name }}: {% if field.type == 'CharField' %}''{% elif field.type == 'IntegerField' %}{{ field.default or 0 }}{% elif field.type == 'BooleanField' %}{{ field.default or 0 }}{% elif field.type == 'FloatField' %}{{ field.default or 0 }}{% else %}''{% endif %},
{% endfor %}
{% for field in form_fields %}
{% if field.is_image %}
{{ field.camel_name }}ImgName: '', // {{ field.comment }}文件名
{% endif %}
{% endfor %}
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
{{ primary_key }}: {
type: Number,
required: true,
default: 0,
},
});
/**
* 定义模态框
*/
const [modalRegister, { openModal, setSubLoading, closeModal }] = useModal({
title: props.{{ primary_key }} ? '编辑{{ module_comment }}' : '新增{{ module_comment }}',
subBtuText: '确定',
width: {% if has_rich_text_field %}850{% else %}500{% endif %},
});
/**
* 执行提交表单
* 根据是否有ID判断是新增还是编辑
*/
const handleSubmit = async () => {
// 获取富文本编辑器内容
{% for field in form_fields %}
{% if field.is_rich_text %}
if ({{ field.camel_name }}EditorRef.value) {
formData.{{ field.camel_name }} = {{ field.camel_name }}EditorRef.value.myValue;
}
{% endif %}
{% endfor %}
formRef.value
.validate()
.then(async () => {
try {
props.{{ primary_key }}
? await {{ model_class_name_camel }}Update(formData)
: await {{ model_class_name_camel }}Add(formData);
message.success('操作成功');
setSubLoading(false);
emit('update:visible', false);
emit('success');
} catch (error) {
message.error('操作失败');
setSubLoading(false);
}
})
.catch(() => {
setSubLoading(false);
});
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
/**
* 设置表单数据
* 编辑时获取详情并填充表单
*/
const setFormData = async () => {
try {
const data = await get{{ model_class_name }}Detail(props.{{ primary_key }});
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
// @ts-ignore
formData[key] = data[key];
}
}
// 设置富文本编辑器内容
{% for field in form_fields %}
{% if field.is_rich_text %}
if ({{ field.camel_name }}EditorRef.value && formData.{{ field.camel_name }}) {
{{ field.camel_name }}EditorRef.value.myValue = formData.{{ field.camel_name }};
}
{% endif %}
{% endfor %}
} catch (error) {
console.error('获取{{ module_comment }}详情失败', error);
message.error('获取数据失败');
}
};
/**
* 重置表单
*/
const resetForm = () => {
if (formRef.value) {
formRef.value.restoreValidation();
}
// 重置表单数据
for (const key in formData) {
if (key === 'id') continue;
// @ts-ignore
if (typeof formData[key] === 'string') {
// @ts-ignore
formData[key] = '';
} else if (typeof formData[key] === 'number') {
// @ts-ignore
formData[key] = 0;
}
}
// 清空富文本编辑器内容
{% for field in form_fields %}
{% if field.is_rich_text %}
if ({{ field.camel_name }}EditorRef.value) {
{{ field.camel_name }}EditorRef.value.myValue = '';
}
{% endif %}
{% endfor %}
};
/**
* 监听visible变化,重新加载数据
*/
watch(
() => props.visible,
(newVal) => {
if (newVal && props.{{ primary_key }}) {
setFormData();
openModal();
} else if (newVal && !props.{{ primary_key }}) {
resetForm();
openModal();
}
},
);
/**
* 钩子函数
*/
onMounted(() => {
if (props.visible) {
if (props.{{ primary_key }}) {
setFormData();
} else {
resetForm();
}
openModal();
}
});
/**
* 暴露openModal方法
*/
defineExpose({
openModal,
});
</script>
<style lang="less" scoped>
.flex {
display: flex;
}
.flex-1 {
flex: 1;
}
.w-full {
width: 100%;
}
</style>