feat(miniapp): improve session navigation and auth guard
This commit is contained in:
@@ -2,9 +2,14 @@ const {
|
|||||||
checkAuth,
|
checkAuth,
|
||||||
createAgentRun,
|
createAgentRun,
|
||||||
getAgentRun,
|
getAgentRun,
|
||||||
loadSession
|
loadSession,
|
||||||
|
logout
|
||||||
} = require('../../utils/api');
|
} = require('../../utils/api');
|
||||||
const { AGENT_RUN_MAX_POLLS, AGENT_RUN_POLL_MS } = require('../../utils/config');
|
const {
|
||||||
|
AGENT_RUN_MAX_POLLS,
|
||||||
|
AGENT_RUN_POLL_MS,
|
||||||
|
SELECTED_SESSION_KEY
|
||||||
|
} = require('../../utils/config');
|
||||||
const { createUserMessage, normalizeMessages } = require('../../utils/messages');
|
const { createUserMessage, normalizeMessages } = require('../../utils/messages');
|
||||||
|
|
||||||
function delay(ms) {
|
function delay(ms) {
|
||||||
@@ -17,6 +22,7 @@ Page({
|
|||||||
messages: [],
|
messages: [],
|
||||||
draft: '',
|
draft: '',
|
||||||
loading: false,
|
loading: false,
|
||||||
|
error: '',
|
||||||
scrollIntoView: ''
|
scrollIntoView: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -25,6 +31,14 @@ Page({
|
|||||||
const status = await checkAuth();
|
const status = await checkAuth();
|
||||||
if (!status?.authenticated) {
|
if (!status?.authenticated) {
|
||||||
wx.redirectTo({ url: '/pages/login/index' });
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const selectedSessionId = wx.getStorageSync(SELECTED_SESSION_KEY);
|
||||||
|
if (selectedSessionId) {
|
||||||
|
wx.removeStorageSync(SELECTED_SESSION_KEY);
|
||||||
|
if (selectedSessionId !== this.data.sessionId) {
|
||||||
|
await this.openSession(selectedSessionId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
wx.redirectTo({ url: '/pages/login/index' });
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
@@ -49,7 +63,7 @@ Page({
|
|||||||
...this.data.messages,
|
...this.data.messages,
|
||||||
{ id: userMessage.id, role: 'user', text }
|
{ id: userMessage.id, role: 'user', text }
|
||||||
];
|
];
|
||||||
this.setData({ messages: nextMessages, draft: '', loading: true });
|
this.setData({ messages: nextMessages, draft: '', loading: true, error: '' });
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -61,6 +75,7 @@ Page({
|
|||||||
const run = await createAgentRun(payload);
|
const run = await createAgentRun(payload);
|
||||||
await this.waitForRun(run?.id || run?.runId);
|
await this.waitForRun(run?.id || run?.runId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.setData({ error: error?.message || '发送失败' });
|
||||||
wx.showToast({ title: error?.message || '发送失败', icon: 'none' });
|
wx.showToast({ title: error?.message || '发送失败', icon: 'none' });
|
||||||
} finally {
|
} finally {
|
||||||
this.setData({ loading: false });
|
this.setData({ loading: false });
|
||||||
@@ -92,6 +107,35 @@ Page({
|
|||||||
async refreshSession(sessionId) {
|
async refreshSession(sessionId) {
|
||||||
const detail = await loadSession(sessionId);
|
const detail = await loadSession(sessionId);
|
||||||
const messages = normalizeMessages(detail?.messages || detail?.data?.messages || []);
|
const messages = normalizeMessages(detail?.messages || detail?.data?.messages || []);
|
||||||
this.setData({ messages });
|
this.setData({ sessionId, messages, error: '' });
|
||||||
|
},
|
||||||
|
|
||||||
|
async openSession(sessionId) {
|
||||||
|
this.setData({ loading: true, error: '' });
|
||||||
|
try {
|
||||||
|
await this.refreshSession(sessionId);
|
||||||
|
} catch (error) {
|
||||||
|
this.setData({ error: error?.message || '会话加载失败' });
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
this.scrollToBottom();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startNewChat() {
|
||||||
|
wx.removeStorageSync(SELECTED_SESSION_KEY);
|
||||||
|
this.setData({ sessionId: '', messages: [], draft: '', error: '' });
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleLogout() {
|
||||||
|
this.setData({ loading: true, error: '' });
|
||||||
|
try {
|
||||||
|
await logout();
|
||||||
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
} catch (error) {
|
||||||
|
this.setData({ error: error?.message || '退出失败' });
|
||||||
|
} finally {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
<view class="page chat-page">
|
<view class="page chat-page">
|
||||||
|
<view class="chat-header">
|
||||||
|
<view class="chat-title">
|
||||||
|
<text>{{sessionId ? '继续会话' : '新会话'}}</text>
|
||||||
|
<text wx:if="{{error}}" class="header-error">{{error}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="header-actions">
|
||||||
|
<button class="header-button" bindtap="startNewChat">新聊天</button>
|
||||||
|
<button class="header-button" bindtap="handleLogout">退出</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<scroll-view class="messages" scroll-y scroll-into-view="{{scrollIntoView}}">
|
<scroll-view class="messages" scroll-y scroll-into-view="{{scrollIntoView}}">
|
||||||
|
<view wx:if="{{messages.length === 0 && !loading}}" class="empty-state">
|
||||||
|
<text>发一条消息开始使用 TKMind。</text>
|
||||||
|
</view>
|
||||||
<view wx:for="{{messages}}" wx:key="id" id="msg-{{index}}" class="message {{item.role}}">
|
<view wx:for="{{messages}}" wx:key="id" id="msg-{{index}}" class="message {{item.role}}">
|
||||||
<text>{{item.text}}</text>
|
<text>{{item.text}}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -5,12 +5,63 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
padding: 20rpx 24rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-bottom: 1rpx solid #dbe3eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4rpx;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-error {
|
||||||
|
max-width: 420rpx;
|
||||||
|
color: #b42318;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-button {
|
||||||
|
width: 112rpx;
|
||||||
|
height: 58rpx;
|
||||||
|
line-height: 58rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
background: #eef6f5;
|
||||||
|
color: #0f766e;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.messages {
|
.messages {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 28rpx;
|
padding: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
margin: 160rpx auto 0;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 28rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
max-width: 84%;
|
max-width: 84%;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const {
|
const {
|
||||||
|
checkAuth,
|
||||||
loginWithPassword,
|
loginWithPassword,
|
||||||
loginWithWechatCode
|
loginWithWechatCode
|
||||||
} = require('../../utils/api');
|
} = require('../../utils/api');
|
||||||
@@ -13,6 +14,17 @@ Page({
|
|||||||
passwordLoading: false
|
passwordLoading: false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async onLoad() {
|
||||||
|
try {
|
||||||
|
const status = await checkAuth();
|
||||||
|
if (status?.authenticated) {
|
||||||
|
wx.switchTab({ url: '/pages/chat/index' });
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Stay on the login page when the existing session cannot be verified.
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleUsername(event) {
|
handleUsername(event) {
|
||||||
this.setData({ username: event.detail.value, error: '' });
|
this.setData({ username: event.detail.value, error: '' });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { listSessions } = require('../../utils/api');
|
const { checkAuth, listSessions } = require('../../utils/api');
|
||||||
|
const { SELECTED_SESSION_KEY } = require('../../utils/config');
|
||||||
|
|
||||||
function formatTime(value) {
|
function formatTime(value) {
|
||||||
const timestamp = Number(value || 0);
|
const timestamp = Number(value || 0);
|
||||||
@@ -15,7 +16,20 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.loadSessions();
|
this.ensureAndLoad();
|
||||||
|
},
|
||||||
|
|
||||||
|
async ensureAndLoad() {
|
||||||
|
try {
|
||||||
|
const status = await checkAuth();
|
||||||
|
if (!status?.authenticated) {
|
||||||
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.loadSessions();
|
||||||
|
} catch {
|
||||||
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadSessions() {
|
async loadSessions() {
|
||||||
@@ -40,6 +54,7 @@ Page({
|
|||||||
openSession(event) {
|
openSession(event) {
|
||||||
const id = event.currentTarget.dataset.id;
|
const id = event.currentTarget.dataset.id;
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
wx.setStorageSync(SELECTED_SESSION_KEY, id);
|
||||||
wx.switchTab({ url: '/pages/chat/index' });
|
wx.switchTab({ url: '/pages/chat/index' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { listMindSpacePages } = require('../../utils/api');
|
const { checkAuth, listMindSpacePages } = require('../../utils/api');
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
@@ -8,7 +8,20 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.loadPages();
|
this.ensureAndLoad();
|
||||||
|
},
|
||||||
|
|
||||||
|
async ensureAndLoad() {
|
||||||
|
try {
|
||||||
|
const status = await checkAuth();
|
||||||
|
if (!status?.authenticated) {
|
||||||
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.loadPages();
|
||||||
|
} catch {
|
||||||
|
wx.redirectTo({ url: '/pages/login/index' });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async loadPages() {
|
async loadPages() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
API_BASE_URL: 'https://h5.tkmind.cn',
|
API_BASE_URL: 'https://h5.tkmind.cn',
|
||||||
MINIAPP_LOGIN_PATH: '/auth/wechat-miniapp/login',
|
MINIAPP_LOGIN_PATH: '/auth/wechat-miniapp/login',
|
||||||
|
SELECTED_SESSION_KEY: 'tkmind_selected_session_id',
|
||||||
AGENT_RUN_POLL_MS: 1200,
|
AGENT_RUN_POLL_MS: 1200,
|
||||||
AGENT_RUN_MAX_POLLS: 120
|
AGENT_RUN_MAX_POLLS: 120
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user