原代码
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 块重置状态,这符合业务逻辑