Files
xk-doctor-wx/subPackages/sub_salesperson/common/submitGuard.js

116 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 表单提交 loading / 防重复点击 / 「未发起请求」超时守卫。
* 为什么抽成公共模块:门店录入与医生录入提交流程一致,避免两页各自维护一套定时器与异常收尾逻辑。
*/
/** 点击后若超过该毫秒仍未真正发起请求,则取消 loading 并提示 */
export const SUBMIT_PREP_TIMEOUT_MS = 10000
/**
* 清理「未发起请求」倒计时,避免页面销毁或重复 begin 时残留定时器。
* @param {object} ctx 页面/组件实例(需挂 _submitPrepTimer
*/
function clearPrepTimer(ctx) {
if (ctx && ctx._submitPrepTimer) {
clearTimeout(ctx._submitPrepTimer)
ctx._submitPrepTimer = null
}
}
/**
* 开始提交:立刻 loading + 防重复 + 启动 10s「未发起请求」倒计时。
* @param {object} ctx 需有 data.submitting
* @param {{ title?: string }} [options]
* @returns {boolean} false 表示已在提交中,调用方应直接 return
*/
export function beginSubmit(ctx, options = {}) {
if (!ctx || ctx.submitting) return false
ctx.submitting = true
ctx._submitRequestStarted = false
clearPrepTimer(ctx)
uni.showLoading({ title: options.title || '提交中...', mask: true })
// 10 秒内若仍未 markRequestStarted说明卡在校验/组 payload需收起 loading 并友好提示
ctx._submitPrepTimer = setTimeout(() => {
ctx._submitPrepTimer = null
if (ctx._submitRequestStarted) return
endSubmit(ctx, { toast: '提交超时,请稍后重试' })
}, SUBMIT_PREP_TIMEOUT_MS)
return true
}
/**
* 标记已真正发起 API 请求清除「未发起请求」倒计时loading 继续等待接口返回。
* @param {object} ctx
*/
export function markRequestStarted(ctx) {
if (!ctx) return
ctx._submitRequestStarted = true
clearPrepTimer(ctx)
}
/**
* 结束提交:清定时器、复位 submitting默认关 loading可选 toast。
* 校验失败时 showError 已 showToast会顶掉 loading须传 skipHideLoading否则 hideLoading 会把 toast 清掉。
* @param {object} ctx
* @param {{ toast?: string, skipHideLoading?: boolean }} [options]
*/
export function endSubmit(ctx, options = {}) {
if (!ctx) return
clearPrepTimer(ctx)
ctx._submitRequestStarted = false
ctx.submitting = false
if (!options.skipHideLoading) {
try {
uni.hideLoading()
} catch (e) {
// hideLoading 在无 loading 时偶发抛错,忽略以免二次异常
}
}
if (options.toast) {
uni.showToast({ title: options.toast, icon: 'none' })
}
}
/**
* 统一跑完「校验 → 发请求 → 成功/失败/异常收尾」。
* @param {object} ctx
* @param {{
* validate: () => boolean,
* request: () => Promise<{ ok?: boolean, res?: any, msg?: string, data?: any }>,
* onSuccess: (w: any) => void,
* loadingTitle?: string,
* }} options
*/
export function runSubmit(ctx, options) {
const { validate, request, onSuccess, loadingTitle } = options || {}
if (!beginSubmit(ctx, { title: loadingTitle })) return
try {
if (typeof validate === 'function' && !validate()) {
// 校验失败showError 已 toast顶掉 loading只复位状态勿再 hideLoading
endSubmit(ctx, { skipHideLoading: true })
return
}
markRequestStarted(ctx)
const reqPromise = typeof request === 'function' ? request() : null
if (!reqPromise || typeof reqPromise.then !== 'function') {
endSubmit(ctx, { toast: '提交异常,请稍后重试' })
return
}
reqPromise
.then((w) => {
if (w && w.ok) {
endSubmit(ctx)
if (typeof onSuccess === 'function') onSuccess(w)
return
}
const msg = (w && w.res && w.res.msg) || (w && w.msg) || '提交失败'
endSubmit(ctx, { toast: msg })
})
.catch(() => {
endSubmit(ctx, { toast: '提交异常,请稍后重试' })
})
} catch (e) {
endSubmit(ctx, { toast: '提交异常,请稍后重试' })
}
}