Files
shanxia2.0/miniprogram/api/wechat-notices.js
T
wuzilongandCursor e7c1762113 fix: 小程序服务号绑定先打开门户域名再跳转微信授权。
web-view 不能直接打开 open.weixin.qq.com,移动端改为打开已配置的业务域名中转页。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-29 01:44:40 +08:00

70 lines
3.1 KiB
JavaScript

import { resolveApiBase, resolveWebOrigin } from '@/config/api'
import { request, parseResponseJson } from '@/utils/request'
const LAUNCH_PATH = '/api/public/wechat-notices/oauth/launch'
function httpsHost(raw) {
const match = String(raw || '').match(/^https:\/\/([^/?#]+)/i)
return match ? match[1].toLowerCase() : ''
}
export async function fetchWechatNoticeStatus() {
const response = await request({
url: '/web/wechat-notices/binding',
method: 'GET',
timeout: 15000
})
const result = parseResponseJson(response)
const data = result?.data
if (
response.statusCode !== 200 || result?.code !== 200 || !data ||
['enabled', 'bound', 'subscribed'].some((key) => typeof data[key] !== 'boolean')
) {
throw new Error('暂时无法确认服务号关注状态')
}
return { enabled: data.enabled, bound: data.bound, subscribed: data.subscribed }
}
async function bindingRequest(method, path, data) {
const response = await request({ url: `/web/wechat-notices/binding${path}`, method, data, timeout: 15000 })
const result = parseResponseJson(response)
if (response.statusCode !== 200 || result?.code !== 200 || !result?.data) {
throw new Error(typeof result?.message === 'string' ? result.message : '绑定操作失败,请稍后重试')
}
return result.data
}
export function isWechatAuthorizeUrl(value) {
// web-view 只能打开业务域名。这里只接受门户上的授权中转页,不直接打开 open.weixin.qq.com。
if (typeof value !== 'string' || value.length > 300) return false
const match = value.match(/^https:\/\/([^/?#@]+)(\/[^?#]*)\?state=([A-Za-z0-9_-]{20,100})$/)
if (!match || match[2] !== LAUNCH_PATH) return false
const allowed = new Set([httpsHost(resolveWebOrigin()), httpsHost(resolveApiBase())].filter(Boolean))
return allowed.has(match[1].toLowerCase())
}
export async function startWechatBinding() {
const data = await bindingRequest('POST', '/start', { mode: 'mobile' })
if (!/^[A-Za-z0-9_-]{20,100}$/.test(data.sessionId || '') || !isWechatAuthorizeUrl(data.authorizeUrl)) {
throw new Error('授权地址无效,请稍后重试')
}
return { sessionId: data.sessionId, authorizeUrl: data.authorizeUrl }
}
export async function fetchWechatBindingSession(sessionId) {
const data = await bindingRequest('GET', `/session?sessionId=${encodeURIComponent(sessionId)}`)
if (!['waiting', 'scanned', 'confirmed', 'expired'].includes(data.status) || typeof data.subscribed !== 'boolean' ||
(data.status === 'scanned' && !/^\d{6}$/.test(data.verificationCode || ''))) {
throw new Error('授权状态异常,请重新绑定')
}
return { status: data.status, subscribed: data.subscribed, verificationCode: data.verificationCode || '' }
}
export async function confirmWechatBinding(sessionId) {
const data = await bindingRequest('POST', '/confirm', { sessionId })
if (['enabled', 'bound', 'subscribed'].some(key => typeof data[key] !== 'boolean')) {
throw new Error('绑定结果异常,请刷新状态')
}
return { enabled: data.enabled, bound: data.bound, subscribed: data.subscribed }
}