const SESSION_KEY = 'tkmind_session'; let apiBaseUrl = ''; let cookie = ''; function setApiBaseUrl(value) { apiBaseUrl = String(value || '').replace(/\/$/, ''); } function getMiniProgramAppId() { try { return wx.getAccountInfoSync?.()?.miniProgram?.appId || ''; } catch { return ''; } } function getStoredSession() { const session = wx.getStorageSync(SESSION_KEY); if (session && typeof session === 'object') { cookie = session.cookie || cookie; return session; } return null; } function saveSession(session) { cookie = session?.cookie || cookie; wx.setStorageSync(SESSION_KEY, session || {}); } function clearSession() { cookie = ''; wx.removeStorageSync(SESSION_KEY); } function normalizeSetCookie(headers = {}) { const raw = headers['Set-Cookie'] || headers['set-cookie']; if (!raw) return ''; if (Array.isArray(raw)) { return raw.map((item) => String(item).split(';')[0]).join('; '); } return String(raw) .split(/,(?=\s*[^;,]+=)/) .map((item) => item.trim().split(';')[0]) .filter(Boolean) .join('; '); } function request(path, options = {}) { const url = /^https?:\/\//i.test(path) ? path : `${apiBaseUrl}${path}`; const header = { Accept: 'application/json', ...(options.body ? { 'Content-Type': 'application/json' } : {}), ...(cookie ? { Cookie: cookie } : {}), ...(options.header || {}) }; return new Promise((resolve, reject) => { wx.request({ url, method: options.method || 'GET', data: options.body || undefined, header, timeout: options.timeout || 20000, success(res) { const nextCookie = normalizeSetCookie(res.header); if (nextCookie) { cookie = nextCookie; const previous = getStoredSession() || {}; saveSession({ ...previous, cookie }); } const status = Number(res.statusCode || 0); if (status >= 200 && status < 300) { resolve(res.data); return; } const message = res.data?.message || res.data?.error?.message || (status === 405 ? `接口不支持当前请求方法,请检查 API_BASE_URL 是否指向 Portal 服务:${url}` : `请求失败 (${status || 'network'})`); const error = new Error(message); error.status = status; error.body = res.data; reject(error); }, fail(err) { reject(new Error(err?.errMsg || '网络请求失败')); } }); }); } function portalRequest(path, options = {}) { return request(path, options); } function apiRequest(path, options = {}) { return request(`/api${path}`, options); } async function checkAuth() { return portalRequest('/auth/status'); } async function getMe() { return portalRequest('/auth/me'); } async function loginWithPassword(username, password) { const result = await portalRequest('/auth/login', { method: 'POST', body: { username, password } }); saveSession({ cookie, user: result?.user || result || null, loginType: 'password' }); return result; } function wxLogin() { return new Promise((resolve, reject) => { wx.login({ success(res) { if (res.code) resolve(res.code); else reject(new Error('微信登录未返回 code')); }, fail(err) { reject(new Error(err?.errMsg || '微信登录失败')); } }); }); } async function loginWithWechatCode(loginPath) { const appId = getMiniProgramAppId(); if (!appId || appId === 'touristappid') { throw new Error('当前是游客模式,微信一键登录需要在 project.config.json 配置真实小程序 AppID。'); } const code = await wxLogin(); const result = await portalRequest(loginPath, { method: 'POST', body: { code } }); saveSession({ cookie, user: result?.user || result || null, loginType: 'wechat' }); return result; } async function logout() { try { await portalRequest('/auth/logout', { method: 'POST' }); } finally { clearSession(); } } async function listSessions(options = {}) { const limit = options.limit || 30; const cursor = options.cursor ? `&cursor=${encodeURIComponent(options.cursor)}` : ''; return apiRequest(`/sessions?limit=${encodeURIComponent(limit)}${cursor}`); } async function loadSession(sessionId) { return apiRequest(`/sessions/${encodeURIComponent(sessionId)}`); } async function createAgentRun(input) { return apiRequest('/agent/runs', { method: 'POST', body: input, timeout: 60000 }); } async function getAgentRun(runId) { return apiRequest(`/agent/runs/${encodeURIComponent(runId)}`); } async function listMindSpacePages(options = {}) { const limit = options.limit || 30; const offset = options.offset || 0; return apiRequest( `/mindspace/v1/pages?limit=${encodeURIComponent(limit)}&offset=${encodeURIComponent(offset)}` ); } module.exports = { setApiBaseUrl, getStoredSession, saveSession, clearSession, checkAuth, getMe, loginWithPassword, loginWithWechatCode, logout, listSessions, loadSession, createAgentRun, getAgentRun, listMindSpacePages };