feat(dialog): 添加关闭事件处理,清理弹窗状态并重置表单数据

This commit is contained in:
zhanghao 2026-09-20 14:03:28 +08:00
parent fe33c529fd
commit 6244d4db77
2 changed files with 98 additions and 25 deletions

View File

@ -4,6 +4,7 @@
:title="title" :title="title"
width="500px" width="500px"
destroy-on-close destroy-on-close
@closed="handleClosed"
> >
<el-form <el-form
ref="formRef" ref="formRef"
@ -33,6 +34,7 @@
:limit="1" :limit="1"
:on-error="uploadError" :on-error="uploadError"
:on-success="uploadSuccess" :on-success="uploadSuccess"
:on-remove="uploadRemove"
class="file-uploader" class="file-uploader"
:on-preview="handlePictureCardPreview" :on-preview="handlePictureCardPreview"
> >
@ -71,7 +73,7 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue' import { nextTick, ref, watch } from 'vue'
import { useDict } from '@/utils/dict' import { useDict } from '@/utils/dict'
import {getToken} from "@/utils/auth.js"; import {getToken} from "@/utils/auth.js";
import {supportType} from "@/enum/index.js"; import {supportType} from "@/enum/index.js";
@ -88,10 +90,10 @@ const props = defineProps({
}, },
formData: { formData: {
type: Object, type: Object,
default: () => {} default: () => ({})
} }
}) })
const emit = defineEmits(['update:visible', 'confirm']) const emit = defineEmits(['update:visible', 'confirm', 'closed'])
const { ti_function_config } = useDict("ti_function_config"); const { ti_function_config } = useDict("ti_function_config");
@ -140,6 +142,20 @@ const uploadSuccess = (e) => {
imgUrl.value = e.msg imgUrl.value = e.msg
ElMessage.success('上传成功') ElMessage.success('上传成功')
} }
/**
* 清理已移除图片对应的待提交地址。
*
* 上传组件只会更新 file-list,不会自动清理独立维护的 imgUrl;如果不处理,用户删除图片后
* 确认仍会提交旧地址,因此在列表为空时同步清空。
*
* @param {*} _uploadFile 被移除的文件
* @param {Array} uploadFiles 移除后的文件列表
*/
const uploadRemove = (_uploadFile, uploadFiles = []) => {
if (!uploadFiles.length) imgUrl.value = ''
}
const uploadError = (e) => { const uploadError = (e) => {
console.log("uploadError", e) console.log("uploadError", e)
} }
@ -156,37 +172,70 @@ const closeViewer = () => {
isViewerOpen.value = false; isViewerOpen.value = false;
} }
/**
* 按本次打开时的表单数据初始化弹窗私有状态。
*
* destroy-on-close 只销毁 Dialog 插槽内容,不会销毁当前组件的 ref;因此每次打开都必须同时
* 处理“有图片”和“无图片”两种情况,避免编辑记录的上传列表残留到新增记录。
*/
const syncDialogState = () => {
const currentUrl = String(props.formData.iconUrl || '')
imgUrl.value = currentUrl
uploadFileList.value = currentUrl ? [{
name: 'image',
url: currentUrl,
response: { msg: currentUrl }
}] : []
uploadFileType.value = null
currentImage.value = ''
isViewerOpen.value = false
nextTick(() => formRef.value?.clearValidate())
}
/**
* 在关闭动画结束后清空全部弹窗私有状态,并通知父组件释放共用表单数据。
*
* 使用 Dialog 的 closed 事件统一覆盖右上角关闭、取消和保存成功,确保所有关闭入口行为一致。
*/
const handleClosed = () => {
imgUrl.value = ''
uploadFileList.value = []
uploadFileType.value = null
currentImage.value = ''
isViewerOpen.value = false
formRef.value?.clearValidate()
emit('closed')
}
watch(() => props.visible, (newVal) => { watch(() => props.visible, (newVal) => {
visible.value = newVal visible.value = newVal
if (props.formData.iconUrl) { if (newVal) syncDialogState()
imgUrl.value = props.formData.iconUrl
uploadFileList.value = [{
name: 'image',
url: props.formData.iconUrl,
response: {
msg: props.formData.iconUrl
}
}]
}
}) })
watch(visible, (newVal) => { watch(visible, (newVal) => {
emit('update:visible', newVal) emit('update:visible', newVal)
}) })
/**
* 校验并提交当前表单。
*
* 校验失败时保留全部输入和上传状态;校验成功后由父组件请求接口,只有父组件关闭弹窗时
* 才统一执行清理,避免接口响应前图片列表提前消失。
*/
function handleConfirm() { function handleConfirm() {
if (!formRef.value) return if (!formRef.value) return
formRef.value.validate((valid) => { formRef.value.validate((valid) => {
if (!valid) return
const obj = { ...props.formData } const obj = { ...props.formData }
if (imgUrl.value && imgUrl.value.length > 0) { obj.iconUrl = imgUrl.value || null
obj.iconUrl = imgUrl.value emit('confirm', true, { ...obj })
}
uploadFileList.value = []
emit('confirm', valid, { ...obj })
}) })
} }
/**
* 关闭弹窗;具体状态清理由 closed 事件统一处理,避免不同关闭入口遗漏字段。
*/
function handleCancel() { function handleCancel() {
visible.value = false visible.value = false
} }

View File

@ -86,6 +86,7 @@
:title="functionDialogTitle" :title="functionDialogTitle"
:form-data="functionFormData" :form-data="functionFormData"
@confirm="handleFunctionConfirm" @confirm="handleFunctionConfirm"
@closed="handleFunctionDialogClosed"
/> />
</div> </div>
</template> </template>
@ -140,7 +141,22 @@ function handleReset() {
const isAdd = ref(true) const isAdd = ref(true)
// 新增功能 /**
* 重置新增、编辑共用的功能表单。
*
* 表单对象由父组件持有,子弹窗的 destroy-on-close 不会释放它;集中重置可确保关闭编辑弹窗后
* 再次新增时不会携带上一条记录的数据。
*/
function resetFunctionFormData() {
functionFormData.funcKey = ''
functionFormData.remark = ''
functionFormData.id = null
functionFormData.iconUrl = null
}
/**
* 打开新增功能弹窗,并确保起始表单为空。
*/
function handleAddFunction() { function handleAddFunction() {
if (props.selectNode?.type !== 'version') { if (props.selectNode?.type !== 'version') {
ElMessage.warning('请先选择车机版本') ElMessage.warning('请先选择车机版本')
@ -148,13 +164,21 @@ function handleAddFunction() {
} }
isAdd.value = true isAdd.value = true
functionDialogTitle.value = '新增功能' functionDialogTitle.value = '新增功能'
functionFormData.funcKey = '' resetFunctionFormData()
functionFormData.remark = ''
functionFormData.iconUrl = null
functionFormData.id = null
functionDialogVisible.value = true functionDialogVisible.value = true
} }
/**
* 响应弹窗完全关闭,释放父组件持有的表单状态。
*
* 该入口同时覆盖取消、右上角关闭和保存成功,避免只清理某一种关闭路径。
*/
function handleFunctionDialogClosed() {
resetFunctionFormData()
functionDialogTitle.value = ''
isAdd.value = true
}
// 确认功能操作 // 确认功能操作
async function handleFunctionConfirm(valid, data) { async function handleFunctionConfirm(valid, data) {
if (valid) { if (valid) {