This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+264
View File
@@ -0,0 +1,264 @@
<template>
<el-dialog
v-model="visible"
:title="editId ? $t('common.edit') : $t('common.add')"
width="600px"
@close="handleClose"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="120px"
>
<<range .FormFields>>
<el-form-item :label="$t('<<$.ModuleName>>.<<.Name>>')" prop="<<.Name>>">
<<if eq .FormType "input">>
<el-input v-model="form.<<.Name>>" :placeholder="$t('<<$.ModuleName>>.<<.Name>>')" />
<<else if eq .FormType "textarea">>
<el-input
v-model="form.<<.Name>>"
type="textarea"
:rows="4"
:placeholder="$t('<<$.ModuleName>>.<<.Name>>')" />
<<else if eq .FormType "select">>
<el-select v-model="form.<<.Name>>" :placeholder="$t('common.select')">
<el-option
v-for="item in <<.Name>>Options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<<else if eq .FormType "switch">>
<el-switch v-model="form.<<.Name>>" />
<<else if eq .FormType "date-picker">>
<el-date-picker
v-model="form.<<.Name>>"
type="date"
:placeholder="$t('common.select_date')" style="width: 100%" />
<<else if eq .FormType "datetime-picker">>
<el-date-picker
v-model="form.<<.Name>>"
type="datetime"
:placeholder="$t('common.select_datetime')" style="width: 100%" />
<<else if eq .FormType "image-upload">>
<el-upload
class="image-uploader"
action="/api/admin/attachments/upload"
:show-file-list="false"
:on-success="handleImageSuccess"
>
<img v-if="form.<<.Name>>" :src="form.<<.Name>>" class="image-preview" />
<el-icon v-else class="image-uploader-icon"><Plus /></el-icon>
</el-upload>
<<else if eq .FormType "file-upload">>
<el-upload
action="/api/admin/attachments/upload"
:show-file-list="true"
:on-success="handleFileSuccess"
>
<el-button type="primary">{{ $t('common.upload') }}</el-button>
</el-upload>
<<end>>
</el-form-item>
<<- end>>
</el-form>
<template #footer>
<el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">
{{ $t('common.confirm') }}
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import {
<<if .HasCreate>>create<<.ModelName>>,<<end>>
<<if .HasEdit>>update<<.ModelName>>,<<end>>
get<<.ModelName>>Detail
} from '../../api/<<.ModuleName>>'
import { getOptions } from '../../api/option'
import ErrorHandler from '../../utils/errorHandler'
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
editId: {
type: Number,
default: null
}
})
const emit = defineEmits(['update:modelValue', 'success'])
const { t } = useI18n()
const formRef = ref(null)
const submitting = ref(false)
<<range .FormFields>>
<<if eq .FormType "select">>
const <<.Name>>Options = ref([])
<<end>>
<<- end>>
const visible = ref(props.modelValue)
watch(() => props.modelValue, (val) => {
visible.value = val
})
watch(visible, (val) => {
emit('update:modelValue', val)
})
const form = ref({
<<range .FormFields>>
<<.Name>>: null,
<<- end>>
})
const rules = {
<<range .FormFields>>
<<.Name>>: [
{ required: <<.Required>>, message: t('<<$.ModuleName>>.<<.Name>>_required'), trigger: 'blur' }
],
<<- end>>
}
const handleSubmit = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
submitting.value = true
if (props.editId) {
<<if .HasEdit>>
await update<<.ModelName>>(props.editId, form.value)
ElMessage.success(t('common.update_success'))
<<else>>
ElMessage.error(t('common.operation_failed'))
<<end>>
} else {
<<if .HasCreate>>
await create<<.ModelName>>(form.value)
ElMessage.success(t('common.create_success'))
<<else>>
ElMessage.error(t('common.operation_failed'))
<<end>>
}
emit('success')
handleClose()
} catch (error) {
ErrorHandler.handle(error)
} finally {
submitting.value = false
}
}
const handleClose = () => {
visible.value = false
formRef.value?.resetFields()
}
const handleImageSuccess = (response) => {
form.value.image = response.data.url
}
const handleFileSuccess = (response) => {
form.value.file = response.data.url
}
const loadOptions = async () => {
<<range .FormFields>>
<<if eq .FormType "select">>
try {
<<if eq .Dictionary "">>
//
// const res = await getOptions('<<.Name>>')
// <<.Name>>Options.value = res.data
<<else>>
const res = await getOptions('dictionary', { dictionary_type: '<<.Dictionary>>' })
if (res.data) {
<<.Name>>Options.value = res.data
}
<<end>>
} catch (error) {
console.error('Failed to load <<.Name>> options:', error)
}
<<end>>
<<- end>>
}
const loadData = async () => {
if (!props.editId) return
try {
const res = await get<<.ModelName>>Detail(props.editId)
if (res.data && res.data.<<.ModuleName>>) {
const data = res.data.<<.ModuleName>>
form.value = {
<<range .FormFields>>
<<.Name>>: data.<<.Name>>,
<<- end>>
}
}
} catch (error) {
ErrorHandler.handle(error)
}
}
watch(visible, (val) => {
if (val) {
loadOptions()
if (props.editId) {
loadData()
} else {
formRef.value?.resetFields()
form.value = {
<<range .FormFields>>
<<.Name>>: null,
<<- end>>
}
}
}
})
</script>
<style scoped>
.image-uploader {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 178px;
height: 178px;
display: flex;
align-items: center;
justify-content: center;
}
.image-uploader:hover {
border-color: #409EFF;
}
.image-preview {
width: 178px;
height: 178px;
object-fit: cover;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
}
</style>