<template>
|
<ElDialog
|
:title="dialogTitle"
|
:model-value="visible"
|
width="820px"
|
align-center
|
@update:model-value="handleCancel"
|
@closed="handleClosed"
|
>
|
<ArtForm
|
ref="formRef"
|
v-model="form"
|
:items="formItems"
|
:rules="rules"
|
:span="12"
|
:gutter="20"
|
label-width="100px"
|
:show-reset="false"
|
:show-submit="false"
|
>
|
<template #val>
|
<div class="w-full">
|
<ElInput
|
v-model="form.val"
|
clearable
|
:placeholder="t('pages.system.config.placeholders.value')"
|
/>
|
|
<div v-if="isProjectLogoConfig || isImageConfigValue(form.val)" class="mt-3">
|
<div class="flex flex-wrap items-center gap-3">
|
<ElUpload
|
accept="image/*"
|
:show-file-list="false"
|
:before-upload="beforeLogoUpload"
|
:http-request="handleLogoUpload"
|
>
|
<ElButton :loading="uploading">
|
{{ t('pages.system.config.actions.uploadLogo') }}
|
</ElButton>
|
</ElUpload>
|
<span class="text-xs text-g-500">
|
{{
|
isProjectLogoConfig
|
? t('pages.system.config.messages.projectLogoHint', { flag: projectLogoFlag })
|
: t('pages.system.config.messages.imagePreviewHint')
|
}}
|
</span>
|
</div>
|
|
<ElImage
|
v-if="isImageConfigValue(form.val)"
|
:src="form.val"
|
fit="contain"
|
preview-teleported
|
class="mt-3 h-24 w-24 rounded border border-[var(--art-border-color)] bg-[var(--art-main-bg-color)]"
|
/>
|
</div>
|
</div>
|
</template>
|
</ArtForm>
|
|
<template #footer>
|
<span class="dialog-footer">
|
<ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton>
|
<ElButton type="primary" @click="handleSubmit">{{ t('common.confirm') }}</ElButton>
|
</span>
|
</template>
|
</ElDialog>
|
</template>
|
|
<script setup>
|
import { ElMessage } from 'element-plus'
|
import ArtForm from '@/components/core/forms/art-form/index.vue'
|
import { fetchUploadProjectLogo } from '@/api/system-manage'
|
import { useI18n } from 'vue-i18n'
|
import {
|
buildConfigDialogModel,
|
createConfigFormState,
|
getConfigTypeOptions,
|
isImageConfigValue,
|
PROJECT_LOGO_FLAG
|
} from '../configPage.helpers'
|
|
const props = defineProps({
|
visible: { type: Boolean, default: false },
|
configData: { type: Object, default: () => ({}) }
|
})
|
|
const emit = defineEmits(['update:visible', 'submit'])
|
const { t } = useI18n()
|
const formRef = ref()
|
const form = reactive(createConfigFormState())
|
const uploading = ref(false)
|
|
const isEdit = computed(() => Boolean(form.id))
|
const isProjectLogoConfig = computed(() => String(form.flag || '').trim().toUpperCase() === PROJECT_LOGO_FLAG)
|
const projectLogoFlag = PROJECT_LOGO_FLAG
|
const dialogTitle = computed(() =>
|
isEdit.value ? t('pages.system.config.dialog.titleEdit') : t('pages.system.config.dialog.titleCreate')
|
)
|
|
const rules = computed(() => ({
|
name: [{ required: true, message: t('pages.system.config.validation.name'), trigger: 'blur' }],
|
flag: [{ required: true, message: t('pages.system.config.validation.flag'), trigger: 'blur' }]
|
}))
|
|
const formItems = computed(() => [
|
{
|
label: t('table.code'),
|
key: 'uuid',
|
type: 'input',
|
props: {
|
disabled: true,
|
placeholder: t('pages.system.config.placeholders.uuid')
|
}
|
},
|
{
|
label: t('table.name'),
|
key: 'name',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: t('pages.system.config.placeholders.name')
|
}
|
},
|
{
|
label: t('pages.system.config.table.flag'),
|
key: 'flag',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: t('pages.system.config.placeholders.flag')
|
}
|
},
|
{
|
label: t('pages.system.config.table.type'),
|
key: 'type',
|
type: 'select',
|
props: {
|
options: getConfigTypeOptions(t),
|
placeholder: t('pages.system.config.placeholders.type')
|
}
|
},
|
{
|
label: t('pages.system.config.table.value'),
|
key: 'val',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: t('pages.system.config.placeholders.value')
|
}
|
},
|
{
|
label: t('table.status'),
|
key: 'status',
|
type: 'select',
|
props: {
|
options: [
|
{ label: t('common.status.normal'), value: 1 },
|
{ label: t('common.status.frozen'), value: 0 }
|
],
|
placeholder: t('pages.system.config.placeholders.status')
|
}
|
},
|
{
|
label: t('pages.system.config.table.content'),
|
key: 'content',
|
type: 'input',
|
span: 24,
|
props: {
|
type: 'textarea',
|
rows: 3,
|
placeholder: t('pages.system.config.placeholders.content')
|
}
|
},
|
{
|
label: t('table.memo'),
|
key: 'memo',
|
type: 'input',
|
span: 24,
|
props: {
|
type: 'textarea',
|
rows: 3,
|
placeholder: t('pages.system.config.placeholders.memo')
|
}
|
}
|
])
|
|
function resetForm() {
|
Object.assign(form, createConfigFormState())
|
formRef.value?.clearValidate?.()
|
}
|
|
function loadFormData() {
|
Object.assign(form, buildConfigDialogModel(props.configData))
|
}
|
|
function beforeLogoUpload(rawFile) {
|
const isImageFile =
|
String(rawFile?.type || '').startsWith('image/') || /\.(png|jpe?g|gif|bmp|webp|svg)$/i.test(rawFile?.name || '')
|
if (!isImageFile) {
|
ElMessage.error(t('pages.system.config.messages.uploadOnlyImage'))
|
return false
|
}
|
|
const isLt5MB = Number(rawFile?.size || 0) / 1024 / 1024 < 5
|
if (!isLt5MB) {
|
ElMessage.error(t('pages.system.config.messages.uploadSizeLimit'))
|
return false
|
}
|
|
return true
|
}
|
|
async function handleLogoUpload(option) {
|
uploading.value = true
|
try {
|
const response = await fetchUploadProjectLogo(option.file)
|
form.val = response?.url || ''
|
option.onSuccess?.(response)
|
ElMessage.success(t('pages.system.config.messages.uploadSuccess'))
|
} catch (error) {
|
option.onError?.(error)
|
ElMessage.error(error?.message || t('pages.system.config.messages.uploadFailed'))
|
} finally {
|
uploading.value = false
|
}
|
}
|
|
async function handleSubmit() {
|
if (!formRef.value) return
|
try {
|
await formRef.value.validate()
|
emit('submit', { ...form })
|
} catch {
|
return
|
}
|
}
|
|
function handleCancel() {
|
emit('update:visible', false)
|
}
|
|
function handleClosed() {
|
resetForm()
|
}
|
|
watch(
|
() => props.visible,
|
(visible) => {
|
if (visible) {
|
loadFormData()
|
nextTick(() => formRef.value?.clearValidate?.())
|
}
|
},
|
{ immediate: true }
|
)
|
|
watch(
|
() => props.configData,
|
() => {
|
if (props.visible) {
|
loadFormData()
|
}
|
},
|
{ deep: true }
|
)
|
</script>
|