feat(miniapp): scaffold WeChat mini program MVP

This commit is contained in:
john
2026-07-11 08:46:08 +08:00
parent 32fb2cdeaf
commit 9e5a59b7d9
29 changed files with 948 additions and 0 deletions
+188
View File
@@ -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
};
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
API_BASE_URL: 'https://h5.tkmind.cn',
MINIAPP_LOGIN_PATH: '/auth/wechat-miniapp/login',
AGENT_RUN_POLL_MS: 1200,
AGENT_RUN_MAX_POLLS: 120
};
+41
View File
@@ -0,0 +1,41 @@
function createUserMessage(text) {
return {
id: `mp_${Date.now()}_${Math.random().toString(16).slice(2)}`,
role: 'user',
created: Math.floor(Date.now() / 1000),
content: [{ type: 'text', text }],
metadata: {
source: 'wechat-miniapp',
userVisible: true,
agentVisible: true,
displayText: text
}
};
}
function messageText(message) {
if (!message) return '';
if (typeof message.text === 'string') return message.text;
if (Array.isArray(message.content)) {
return message.content
.filter((part) => part && part.type === 'text')
.map((part) => part.text || '')
.join('');
}
return '';
}
function normalizeMessages(messages = []) {
return messages.map((message) => ({
id: message.id || `${message.role}_${message.created || Date.now()}`,
role: message.role || 'assistant',
text: messageText(message),
created: message.created || 0
}));
}
module.exports = {
createUserMessage,
messageText,
normalizeMessages
};