Files
DjangoAdmin_Django_NaiveVue/public/templates/ui2/edit.vue.tpl
T
2026-09-12 12:07:15 +08:00

436 lines
13 KiB
Smarty
Raw 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
ref="formRef"
:model="formData"
label-placement="left"
label-width="80px"
>
{% for field in form_fields %}
{% if field.camel_name == parent_id_field %}
<!-- {{ field.comment }}(树形选择器) -->
<n-form-item
label="{{ field.label }}"
path="{{ field.camel_name }}"
{% if field.required %}
:rule="{ type: 'number', required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
{% endif %}
>
<n-tree-select
class="flex-1"
v-model:value="formData.{{ field.camel_name }}"
:options="treeOptions"
label-field="{{ display_field_camel }}"
key-field="{{ primary_key }}"
default-expand-all
placeholder="请选择{{ field.comment }}"
clearable
/>
</n-form-item>
{% elif 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.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"
style="width: 100%"
/>
</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"
style="width: 100%"
/>
</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 }}List, 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';
import { buildTree } from '@/utils/auth';
{% if has_image_field %}
import UploadImg from '@/components/Upload/Image.vue';
{% endif %}
// 定义事件
const emit = defineEmits(['success', 'update:visible']);
// 消息提示
const message = useMessage();
// 表单引用
const formRef = ref();
// 树形选项数据
const treeOptions = ref<any[]>([]);
/**
* 定义选项数据
*/
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,
},
// 新增时传入的父级ID(驼峰格式)
parentId: {
type: Number,
default: 0,
},
});
/**
* 定义模态框
*/
const [modalRegister, { openModal, setSubLoading, closeModal }] = useModal({
title: props.{{ primary_key }} ? '编辑{{ module_comment }}' : '新增{{ module_comment }}',
subBtuText: '确定',
width: 500,
});
/**
* 获取树形数据
*/
const get{{ model_class_name }}Tree = async () => {
const data = await get{{ model_class_name }}List();
// 构建顶级节点
const tree: any = [{ id: 0, {{ display_field_camel }}: '顶级', children: [] }];
const lists = buildTree(data);
tree[0].children.push(...lists);
treeOptions.value = tree;
};
/**
* 执行提交表单
* 根据是否有ID判断是新增还是编辑
*/
const handleSubmit = async () => {
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 = () => {
closeModal();
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];
}
}
} 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;
}
}
// 设置父级ID默认值(使用驼峰格式)
formData.{{ parent_id_field }} = props.parentId || 0;
};
/**
* 监听visible变化,重新加载数据
*/
watch(
() => props.visible,
(newVal) => {
if (newVal && props.{{ primary_key }}) {
setFormData();
openModal();
} else if (newVal && !props.{{ primary_key }}) {
resetForm();
get{{ model_class_name }}Tree();
openModal();
}
},
);
/**
* 钩子函数
*/
onMounted(() => {
get{{ model_class_name }}Tree();
if (props.visible) {
if (props.{{ primary_key }}) {
setFormData();
} else {
resetForm();
}
openModal();
}
});
/**
* 暴露openModal方法
*/
defineExpose({
openModal,
});
</script>
<style lang="less" scoped>
.flex-1 {
flex: 1;
}
.form-tips {
font-size: 12px;
color: #999;
line-height: 1.5;
margin-top: 4px;
}
</style>