使用try-finally結構執行狀態重置
原代碼
const commitForm = async () => { btnLoading.value = true; isCommitted.value = true; //過濾出顯示字段的列表 let showFieldsList = []; for (let comp of compList.value) { if (comp.isShow) { showFieldsList.push(comp); } } //必填校驗 for (let comp of showFieldsList) { if (comp.isRequired && comp.isShow) { if (comp.type === "showPic") { if (comp.picUrl) { formData.value[comp.prop] = comp.picUrl; } } else if (comp.type === "subForm") { const subForm = comp.subForm; if (subForm) { // 子表單必填字段列表 let propList = []; for (let subComp of subForm) { if (subComp.isConfigRequired) { propList.push({ prop: subComp.prop, label: subComp.label, }); } } const subFormFillDataStr = formData.value[comp.prop]; const subFormFillDataArr = JSON.parse(subFormFillDataStr ?? "[]"); if (subFormFillDataArr.length === 0 && propList.length > 0) { message.error(`請填寫子表單數據`); return; } for (let item of propList) { for (let subFormFillData of subFormFillDataArr) { if ((subFormFillData[item.prop] ?? "") === "") { message.warning(`${item.label}是必填字段`); return; } } } } } else if (comp.type === "checkBox") { if ( formData.value[comp.prop] == "others" || (Array.isArray(formData.value[comp.prop]) && formData.value[comp.prop].length === 0) || (formData.value[comp.prop] ?? "") === "" ) { message.warning(`${comp.label}是必填字段`); return; } if ( formData.value[comp.prop].includes("others") && !formData.value[comp.prop].some((item) => item.startsWith("others-")) ) { message.warning(`${comp.label}字段的其他選項勾選但未填寫`); return; } } else if ((formData.value[comp.prop] ?? "") === "") { message.warning(`${comp.label}是必填字段`); return; } //校驗手機號 if (comp.isValidateTel) { if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(comp.sensitiveInfoTxt)) { message.warning(`${comp.label}格式錯誤`); return; } } // 正則表達式校驗 if (comp.regExp && comp.regExp !== "") { const res = validateCompValue(comp); if (!res) { return; } } //相等校驗 if (comp.sameValueAsCompValue) { if ( formData.value[comp.prop] !== formData.value[comp.sameValueAsCompValue] ) { message.warning(`${comp.label}字段配置的兩次輸入內容不同`); return; } } } } const copyFormState = JSON.parse(JSON.stringify(formData.value)); for (let comp of compList.value) { if (["checkBox", "dataBind"].includes(comp.type)) { if (Array.isArray(copyFormState[comp.prop])) { copyFormState[comp.prop] = copyFormState[comp.prop].join(","); copyFormState[comp.prop] = rearrangeOthers(copyFormState[comp.prop]); } } if (comp.type === "dateTime") { if (copyFormState[comp.prop]) { copyFormState[comp.prop] = dayjs(copyFormState[comp.prop]).format( "YYYY-MM-DD HH:mm" ); } } } const res = await validateTryUpdateOrder( props.workConfCode, props.formWebUuid ); if (res === "covered") { return; } const params = { workConfCode: props.workConfCode, parentOrderId: route.query.orderId, subFormWebUuid: props.formWebUuid, }; SmartFormApi.subFormNewRecord(params, copyFormState) .then(async (result) => { if (result.data.code === 200) { message.success("已提交表單"); emit("updateFormStatus", "已完成"); } else { message.error(result.data.message); btnLoading.value = false; isCommitted.value = false; } }) .catch((err) => { console.error(err); btnLoading.value = false; isCommitted.value = false; }); };
需要一進入這個函數就給按鈕置灰,防止重復提交,但是函數內部return很多。
如果給每個return前都加上恢復按鈕正常功能,則會造成大量的工作量和代碼冗余,且不利于后續擴展。
可以使用try-finally結構,將代碼改為
const commitForm = async () => { btnLoading.value = true; isCommitted.value = true; try { //過濾出顯示字段的列表 let showFieldsList = []; for (let comp of compList.value) { if (comp.isShow) { showFieldsList.push(comp); } } //必填校驗 for (let comp of showFieldsList) { if (comp.isRequired && comp.isShow) { if (comp.type === "showPic") { if (comp.picUrl) { formData.value[comp.prop] = comp.picUrl; } } else if (comp.type === "subForm") { const subForm = comp.subForm; if (subForm) { // 子表單必填字段列表 let propList = []; for (let subComp of subForm) { if (subComp.isConfigRequired) { propList.push({ prop: subComp.prop, label: subComp.label, }); } } const subFormFillDataStr = formData.value[comp.prop]; const subFormFillDataArr = JSON.parse(subFormFillDataStr ?? "[]"); if (subFormFillDataArr.length === 0 && propList.length > 0) { message.error(`請填寫子表單數據`); return; // 校驗失敗,退出執行 } for (let item of propList) { for (let subFormFillData of subFormFillDataArr) { if ((subFormFillData[item.prop] ?? "") === "") { message.warning(`${item.label}是必填字段`); return; // 校驗失敗,退出執行 } } } } } else if (comp.type === "checkBox") { if ( formData.value[comp.prop] == "others" || (Array.isArray(formData.value[comp.prop]) && formData.value[comp.prop].length === 0) || (formData.value[comp.prop] ?? "") === "" ) { message.warning(`${comp.label}是必填字段`); return; // 校驗失敗,退出執行 } if ( formData.value[comp.prop].includes("others") && !formData.value[comp.prop].some((item) => item.startsWith("others-")) ) { message.warning(`${comp.label}字段的其他選項勾選但未填寫`); return; // 校驗失敗,退出執行 } } else if ((formData.value[comp.prop] ?? "") === "") { message.warning(`${comp.label}是必填字段`); return; // 校驗失敗,退出執行 } //校驗手機號 if (comp.isValidateTel) { if (!/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(comp.sensitiveInfoTxt)) { message.warning(`${comp.label}格式錯誤`); return; // 校驗失敗,退出執行 } } // 正則表達式校驗 if (comp.regExp && comp.regExp !== "") { const res = validateCompValue(comp); if (!res) { return; // 校驗失敗,退出執行 } } //相等校驗 if (comp.sameValueAsCompValue) { if ( formData.value[comp.prop] !== formData.value[comp.sameValueAsCompValue] ) { message.warning(`${comp.label}字段配置的兩次輸入內容不同`); return; // 校驗失敗,退出執行 } } } } const copyFormState = JSON.parse(JSON.stringify(formData.value)); for (let comp of compList.value) { if (["checkBox", "dataBind"].includes(comp.type)) { if (Array.isArray(copyFormState[comp.prop])) { copyFormState[comp.prop] = copyFormState[comp.prop].join(","); copyFormState[comp.prop] = rearrangeOthers(copyFormState[comp.prop]); } } if (comp.type === "dateTime") { if (copyFormState[comp.prop]) { copyFormState[comp.prop] = dayjs(copyFormState[comp.prop]).format( "YYYY-MM-DD HH:mm" ); } } } const res = await validateTryUpdateOrder( props.workConfCode, props.formWebUuid ); if (res === "covered") { return; // 校驗失敗,退出執行 } const params = { workConfCode: props.workConfCode, parentOrderId: route.query.orderId, subFormWebUuid: props.formWebUuid, }; await SmartFormApi.subFormNewRecord(params, copyFormState) .then((result) => { if (result.data.code === 200) { message.success("已提交表單"); emit("updateFormStatus", "已完成"); } else { message.error(result.data.message); // 接口返回錯誤,需要重置狀態 throw new Error(result.data.message); } }); } catch (err) { console.error(err); } finally { // 無論成功失敗,最終都重置狀態 btnLoading.value = false; isCommitted.value = false; } };
主要優化點說明:
1. 使用 try-finally 結構,確保在任何情況下(包括所有 return 點)都會執行狀態重置
2. 將所有校驗失敗的情況通過 return 退出,最終都會走到 finally 塊
3. 接口調用失敗時通過 throw new Error 觸發 catch 塊,最終也會走到 finally 塊
4. 成功提交后仍然會執行 finally 塊重置狀態,這符合業務邏輯

浙公網安備 33010602011771號