This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,169 @@
Vue.component("csrf-token", {
created: function () {
this.refreshToken()
},
mounted: function () {
let that = this
var form = this.$refs.token.form
// 监听表单提交在提交前刷新token并确保更新到 DOM
form.addEventListener("submit", function (e) {
// 如果正在刷新,等待刷新完成
if (that.refreshing) {
e.preventDefault()
e.stopPropagation()
return false
}
// 阻止默认提交,先刷新 token
e.preventDefault()
e.stopPropagation()
that.refreshing = true
// 刷新 token
that.refreshToken(function () {
// 确保 DOM 中的 token 值是最新的
that.$forceUpdate()
that.$nextTick(function () {
var tokenInput = form.querySelector('input[name="csrfToken"]')
if (tokenInput) {
tokenInput.value = that.token
}
if (that.$refs.token) {
that.$refs.token.value = that.token
}
// 确保 DOM 已更新后,再触发表单提交
setTimeout(function () {
that.refreshing = false
// 重新触发表单提交
Tea.runActionOn(form)
}, 50)
})
})
return false
})
// 自动刷新
setInterval(function () {
that.refreshToken()
}, 10 * 60 * 1000)
// 监听表单提交失败,如果是 CSRF token 错误,自动刷新 token 并重试
this.setupAutoRetry(form)
},
data: function () {
return {
token: "",
retrying: false,
refreshing: false
}
},
methods: {
refreshToken: function (callback) {
let that = this
Tea.action("/csrf/token")
.get()
.success(function (resp) {
that.token = resp.data.token
if (callback) {
callback()
}
})
.fail(function () {
if (callback) {
callback()
}
})
},
setupAutoRetry: function (form) {
let that = this
var originalFail = form.getAttribute("data-tea-fail")
// 确保 Tea.Vue 存在
if (typeof Tea === "undefined" || Tea.Vue == null) {
if (typeof Tea === "undefined") {
window.Tea = {}
}
if (Tea.Vue == null) {
Tea.Vue = {}
}
}
// 创建一个包装的 fail 函数
var wrappedFailName = "csrfAutoRetryFail_" + Math.random().toString(36).substr(2, 9)
form.setAttribute("data-tea-fail", wrappedFailName)
Tea.Vue[wrappedFailName] = function (resp) {
// 检查是否是 CSRF token 错误
var isCSRFError = false
if (resp && resp.message) {
// 检查消息是否包含 "表单已失效" 或 "001"
if (resp.message.indexOf("表单已失效") >= 0 || resp.message.indexOf("(001)") >= 0) {
isCSRFError = true
}
}
// 检查 HTTP 状态码是否为 403 或 400
if (!isCSRFError && resp && (resp.statusCode === 403 || resp.status === 403 || resp.statusCode === 400 || resp.status === 400)) {
isCSRFError = true
}
if (isCSRFError) {
// 如果不是正在重试,则立即刷新 token 并自动重试
if (!that.retrying) {
that.retrying = true
// 立即刷新 token
that.refreshToken(function () {
// 强制更新 Vue确保响应式数据已更新
that.$forceUpdate()
// 使用 $nextTick 等待 Vue 完成 DOM 更新
that.$nextTick(function () {
// 直接查找并更新 DOM 中的 input 元素(通过 name 属性)
var tokenInput = form.querySelector('input[name="csrfToken"]')
if (tokenInput) {
tokenInput.value = that.token
}
// 如果 ref 存在,也更新它
if (that.$refs.token) {
that.$refs.token.value = that.token
}
// 使用 setTimeout 确保 DOM 已完全更新
setTimeout(function () {
// 再次确认 token 值已更新
var finalTokenInput = form.querySelector('input[name="csrfToken"]')
if (finalTokenInput && finalTokenInput.value !== that.token) {
finalTokenInput.value = that.token
}
that.retrying = false
// 重新触发表单提交
Tea.runActionOn(form)
}, 150)
})
})
return // 不调用原始 fail 函数
} else {
// 如果正在重试,说明已经刷新过 token直接调用原始 fail 函数
if (originalFail && typeof Tea.Vue[originalFail] === "function") {
return Tea.Vue[originalFail].call(Tea.Vue, resp)
} else {
Tea.failResponse(resp)
}
}
}
// 不是 CSRF 错误,调用原始 fail 函数或默认处理
if (originalFail && typeof Tea.Vue[originalFail] === "function") {
return Tea.Vue[originalFail].call(Tea.Vue, resp)
} else {
Tea.failResponse(resp)
}
}
}
},
template: `<input type="hidden" name="csrfToken" :value="token" ref="token"/>`
})