feat(miniapp): scaffold WeChat mini program MVP
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
const SESSION_KEY = 'tkmind_session';
|
||||
|
||||
let apiBaseUrl = '';
|
||||
let cookie = '';
|
||||
|
||||
function setApiBaseUrl(value) {
|
||||
apiBaseUrl = String(value || '').replace(/\/$/, '');
|
||||
}
|
||||
|
||||
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 || '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 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
|
||||
};
|
||||
Reference in New Issue
Block a user