feat: 登录注册系统 + 游客使用限制
功能: - 登录/注册界面(本地存储用户数据) - 我的页面显示用户状态、登录/退出按钮 - 游客配额显示(对话会话/消息/智能体消息) 游客限制: - 每天最多1个对话会话 - 每天最多20条对话消息 - 只能使用通用助手智能体 - 每天最多20条智能体消息 - 登录用户无限制 限制提示: - 达到限制弹出提示对话框 - 提示登录解锁全部功能
This commit is contained in:
606
www/app.js
606
www/app.js
@@ -67,6 +67,166 @@ let pinnedAgents = {
|
||||
|
||||
let currentAgent = null; // 当前选中的智能体
|
||||
|
||||
// 用户状态
|
||||
let currentUser = null; // 当前登录用户 { username, password, registeredAt }
|
||||
|
||||
// 每日使用统计(未登录用户)
|
||||
let dailyUsage = {
|
||||
date: null, // 日期 YYYY-MM-DD
|
||||
chatSessions: 0, // 对话会话数
|
||||
chatMessages: 0, // 对话消息数
|
||||
agentUsed: null, // 使用的智能体ID(只能用一个)
|
||||
agentMessages: 0 // 智能体消息数
|
||||
};
|
||||
|
||||
// 未登录用户限制
|
||||
const GUEST_LIMITS = {
|
||||
maxChatSessionsPerDay: 1, // 每天最多1个对话会话
|
||||
maxChatMessagesPerDay: 20, // 每天最多20条对话消息
|
||||
maxAgentPerDay: 1, // 每天只能用1个智能体(通用助手)
|
||||
maxAgentMessagesPerDay: 20 // 每天最多20条智能体消息
|
||||
};
|
||||
|
||||
// 获取今日日期字符串
|
||||
function getTodayDate() {
|
||||
const today = new Date();
|
||||
return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// 检查并重置每日使用统计
|
||||
function checkDailyUsage() {
|
||||
const today = getTodayDate();
|
||||
if (dailyUsage.date !== today) {
|
||||
// 新的一天,重置统计
|
||||
dailyUsage = {
|
||||
date: today,
|
||||
chatSessions: 0,
|
||||
chatMessages: 0,
|
||||
agentUsed: null,
|
||||
agentMessages: 0
|
||||
};
|
||||
saveDailyUsage();
|
||||
}
|
||||
}
|
||||
|
||||
// 保存用户状态
|
||||
function saveCurrentUser() {
|
||||
if (currentUser) {
|
||||
localStorage.setItem('currentUser', JSON.stringify(currentUser));
|
||||
} else {
|
||||
localStorage.removeItem('currentUser');
|
||||
}
|
||||
}
|
||||
|
||||
// 保存每日使用统计
|
||||
function saveDailyUsage() {
|
||||
localStorage.setItem('dailyUsage', JSON.stringify(dailyUsage));
|
||||
}
|
||||
|
||||
// 检查是否可以创建新对话(未登录用户)
|
||||
function canCreateNewChat() {
|
||||
if (currentUser) return true; // 登录用户无限制
|
||||
|
||||
checkDailyUsage();
|
||||
return dailyUsage.chatSessions < GUEST_LIMITS.maxChatSessionsPerDay;
|
||||
}
|
||||
|
||||
// 检查是否可以发送对话消息(未登录用户)
|
||||
function canSendChatMessage() {
|
||||
if (currentUser) return true; // 登录用户无限制
|
||||
|
||||
checkDailyUsage();
|
||||
return dailyUsage.chatMessages < GUEST_LIMITS.maxChatMessagesPerDay;
|
||||
}
|
||||
|
||||
// 检查是否可以使用智能体(未登录用户)
|
||||
function canUseAgent(agentId) {
|
||||
if (currentUser) return true; // 登录用户无限制
|
||||
|
||||
checkDailyUsage();
|
||||
|
||||
// 未登录用户只能使用通用助手
|
||||
if (agentId !== 'assistant') {
|
||||
return { allowed: false, reason: 'guest_agent_only' };
|
||||
}
|
||||
|
||||
// 如果今天还没用智能体,可以用
|
||||
if (!dailyUsage.agentUsed) {
|
||||
return { allowed: true };
|
||||
}
|
||||
|
||||
// 如果已经用了其他智能体,不能换
|
||||
if (dailyUsage.agentUsed !== agentId) {
|
||||
return { allowed: false, reason: 'guest_one_agent_only' };
|
||||
}
|
||||
|
||||
return { allowed: true };
|
||||
}
|
||||
|
||||
// 检查是否可以发送智能体消息(未登录用户)
|
||||
function canSendAgentMessage() {
|
||||
if (currentUser) return true; // 登录用户无限制
|
||||
|
||||
checkDailyUsage();
|
||||
return dailyUsage.agentMessages < GUEST_LIMITS.maxAgentMessagesPerDay;
|
||||
}
|
||||
|
||||
// 增加对话会话计数
|
||||
function incrementChatSession() {
|
||||
if (!currentUser) {
|
||||
checkDailyUsage();
|
||||
dailyUsage.chatSessions++;
|
||||
saveDailyUsage();
|
||||
}
|
||||
}
|
||||
|
||||
// 增加对话消息计数
|
||||
function incrementChatMessage() {
|
||||
if (!currentUser) {
|
||||
checkDailyUsage();
|
||||
dailyUsage.chatMessages++;
|
||||
saveDailyUsage();
|
||||
}
|
||||
}
|
||||
|
||||
// 设置使用的智能体(未登录用户)
|
||||
function setAgentUsed(agentId) {
|
||||
if (!currentUser) {
|
||||
checkDailyUsage();
|
||||
if (!dailyUsage.agentUsed) {
|
||||
dailyUsage.agentUsed = agentId;
|
||||
saveDailyUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 增加智能体消息计数
|
||||
function incrementAgentMessage() {
|
||||
if (!currentUser) {
|
||||
checkDailyUsage();
|
||||
dailyUsage.agentMessages++;
|
||||
saveDailyUsage();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取剩余配额提示
|
||||
function getRemainingQuota() {
|
||||
if (currentUser) return null; // 登录用户无限制
|
||||
|
||||
checkDailyUsage();
|
||||
|
||||
const chatSessionRemain = GUEST_LIMITS.maxChatSessionsPerDay - dailyUsage.chatSessions;
|
||||
const chatMsgRemain = GUEST_LIMITS.maxChatMessagesPerDay - dailyUsage.chatMessages;
|
||||
const agentMsgRemain = GUEST_LIMITS.maxAgentMessagesPerDay - dailyUsage.agentMessages;
|
||||
|
||||
return {
|
||||
chatSessionRemain,
|
||||
chatMsgRemain,
|
||||
agentMsgRemain,
|
||||
agentUsed: dailyUsage.agentUsed
|
||||
};
|
||||
}
|
||||
|
||||
// 获取使用智能体的对话列表(按时间倒序)
|
||||
function getAgentConversationHistory(limit = 5) {
|
||||
return conversations
|
||||
@@ -145,6 +305,21 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
pinnedAgents = JSON.parse(savedPinnedAgents);
|
||||
}
|
||||
|
||||
// 加载用户登录状态
|
||||
const savedUser = localStorage.getItem('currentUser');
|
||||
if (savedUser) {
|
||||
currentUser = JSON.parse(savedUser);
|
||||
}
|
||||
|
||||
// 加载每日使用统计
|
||||
const savedDailyUsage = localStorage.getItem('dailyUsage');
|
||||
if (savedDailyUsage) {
|
||||
dailyUsage = JSON.parse(savedDailyUsage);
|
||||
}
|
||||
|
||||
// 检查并重置每日使用统计
|
||||
checkDailyUsage();
|
||||
|
||||
// 根据用户配置更新显示的智能体
|
||||
updateAgentsDisplay();
|
||||
|
||||
@@ -1113,6 +1288,8 @@ function showAgentFavoritePage() {
|
||||
// ==================== 我的页面 ====================
|
||||
|
||||
function renderProfilePage() {
|
||||
const quota = getRemainingQuota();
|
||||
|
||||
return `
|
||||
<div class="profile-page">
|
||||
<header class="page-header">
|
||||
@@ -1121,15 +1298,46 @@ function renderProfilePage() {
|
||||
|
||||
<div class="profile-content">
|
||||
<div class="profile-card">
|
||||
<div class="profile-avatar">👤</div>
|
||||
<div class="profile-name">用户</div>
|
||||
<div class="profile-avatar">${currentUser ? '👤' : '👤'}</div>
|
||||
<div class="profile-name">${currentUser ? currentUser.username : '游客'}</div>
|
||||
${currentUser
|
||||
? `<div class="profile-status">已登录</div>
|
||||
<button class="logout-btn" id="logoutBtn">退出登录</button>`
|
||||
: `<div class="profile-status guest">未登录</div>
|
||||
<div class="profile-login-buttons">
|
||||
<button class="login-btn" id="loginBtn">登录</button>
|
||||
<button class="register-btn" id="registerBtn">注册</button>
|
||||
<button class="skip-btn" id="skipBtn">跳过,继续使用</button>
|
||||
</div>`
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="profile-section">
|
||||
<div class="profile-item" id="settingsBtn">
|
||||
<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M19.14 12.94c.04-.31.06-.63.06-.94 0-.31-.02-.63-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.44.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>
|
||||
<span>设置</span>
|
||||
${!currentUser && quota ? `
|
||||
<div class="quota-card">
|
||||
<div class="quota-title">今日使用配额(游客)</div>
|
||||
<div class="quota-items">
|
||||
<div class="quota-item">
|
||||
<span class="quota-label">对话会话</span>
|
||||
<span class="quota-value">${quota.chatSessionRemain}/${GUEST_LIMITS.maxChatSessionsPerDay}</span>
|
||||
</div>
|
||||
<div class="quota-item">
|
||||
<span class="quota-label">对话消息</span>
|
||||
<span class="quota-value">${quota.chatMsgRemain}/${GUEST_LIMITS.maxChatMessagesPerDay}</span>
|
||||
</div>
|
||||
<div class="quota-item">
|
||||
<span class="quota-label">智能体消息</span>
|
||||
<span class="quota-value">${quota.agentMsgRemain}/${GUEST_LIMITS.maxAgentMessagesPerDay}</span>
|
||||
</div>
|
||||
<div class="quota-item">
|
||||
<span class="quota-label">可用智能体</span>
|
||||
<span class="quota-value">仅通用助手 🤖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quota-tip">登录后解锁全部功能</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="profile-section">
|
||||
<div class="profile-item" id="aboutBtn">
|
||||
<svg viewBox="0 0 24 24" width="20" height="20"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>
|
||||
<span>关于</span>
|
||||
@@ -1141,7 +1349,7 @@ function renderProfilePage() {
|
||||
</div>
|
||||
|
||||
<div class="profile-footer">
|
||||
<p>AI助手 v3.2.1</p>
|
||||
<p>AI助手 v3.3.0</p>
|
||||
<p>基于智谱 GLM-4.5-Air</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1150,12 +1358,53 @@ function renderProfilePage() {
|
||||
}
|
||||
|
||||
function bindProfilePageEvents() {
|
||||
// 登录按钮
|
||||
const loginBtn = document.getElementById('loginBtn');
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener('click', () => {
|
||||
showLoginPage();
|
||||
});
|
||||
}
|
||||
|
||||
// 注册按钮
|
||||
const registerBtn = document.getElementById('registerBtn');
|
||||
if (registerBtn) {
|
||||
registerBtn.addEventListener('click', () => {
|
||||
showRegisterPage();
|
||||
});
|
||||
}
|
||||
|
||||
// 跳过按钮(游客模式)
|
||||
const skipBtn = document.getElementById('skipBtn');
|
||||
if (skipBtn) {
|
||||
skipBtn.addEventListener('click', () => {
|
||||
showToast('以游客模式继续使用');
|
||||
switchPage('chats');
|
||||
});
|
||||
}
|
||||
|
||||
// 退出登录按钮
|
||||
const logoutBtn = document.getElementById('logoutBtn');
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener('click', () => {
|
||||
if (confirm('确定要退出登录吗?')) {
|
||||
currentUser = null;
|
||||
saveCurrentUser();
|
||||
showToast('已退出登录');
|
||||
switchPage('profile');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清除数据按钮
|
||||
const clearDataBtn = document.getElementById('clearDataBtn');
|
||||
if (clearDataBtn) {
|
||||
clearDataBtn.addEventListener('click', () => {
|
||||
if (confirm('确定要清除所有数据吗?这将删除所有对话记录。')) {
|
||||
if (confirm('确定要清除所有数据吗?这将删除所有对话记录和账户信息。')) {
|
||||
localStorage.clear();
|
||||
conversations = [];
|
||||
currentUser = null;
|
||||
dailyUsage = { date: null, chatSessions: 0, chatMessages: 0, agentUsed: null, agentMessages: 0 };
|
||||
showToast('数据已清除');
|
||||
showMainPage();
|
||||
}
|
||||
@@ -1163,6 +1412,280 @@ function bindProfilePageEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 登录页面 ====================
|
||||
|
||||
function showLoginPage() {
|
||||
const loginHtml = `
|
||||
<div class="auth-page">
|
||||
<header class="auth-header">
|
||||
<button class="back-btn-white" id="loginBackBtn">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
|
||||
</button>
|
||||
<h1>登录</h1>
|
||||
</header>
|
||||
|
||||
<div class="auth-content">
|
||||
<div class="auth-form">
|
||||
<div class="auth-input-group">
|
||||
<label>用户名</label>
|
||||
<input type="text" id="loginUsername" placeholder="请输入用户名" autocomplete="username">
|
||||
</div>
|
||||
<div class="auth-input-group">
|
||||
<label>密码</label>
|
||||
<input type="password" id="loginPassword" placeholder="请输入密码" autocomplete="current-password">
|
||||
</div>
|
||||
<button class="auth-submit-btn" id="loginSubmitBtn">登录</button>
|
||||
</div>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>还没有账号?<span class="auth-link" id="goToRegister">立即注册</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
appContainer.innerHTML = loginHtml;
|
||||
|
||||
// 绑定事件
|
||||
const backBtn = document.getElementById('loginBackBtn');
|
||||
if (backBtn) {
|
||||
backBtn.addEventListener('click', () => {
|
||||
showMainPage();
|
||||
});
|
||||
}
|
||||
|
||||
const submitBtn = document.getElementById('loginSubmitBtn');
|
||||
if (submitBtn) {
|
||||
submitBtn.addEventListener('click', handleLogin);
|
||||
}
|
||||
|
||||
const goToRegister = document.getElementById('goToRegister');
|
||||
if (goToRegister) {
|
||||
goToRegister.addEventListener('click', () => {
|
||||
showRegisterPage();
|
||||
});
|
||||
}
|
||||
|
||||
// 回车登录
|
||||
document.getElementById('loginPassword')?.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') handleLogin();
|
||||
});
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
const username = document.getElementById('loginUsername')?.value.trim();
|
||||
const password = document.getElementById('loginPassword')?.value;
|
||||
|
||||
if (!username) {
|
||||
showToast('请输入用户名');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
showToast('请输入密码');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查本地存储的用户
|
||||
const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]');
|
||||
const user = users.find(u => u.username === username && u.password === password);
|
||||
|
||||
if (user) {
|
||||
currentUser = { username: user.username, registeredAt: user.registeredAt };
|
||||
saveCurrentUser();
|
||||
showToast('登录成功');
|
||||
showMainPage();
|
||||
} else {
|
||||
showToast('用户名或密码错误');
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 注册页面 ====================
|
||||
|
||||
function showRegisterPage() {
|
||||
const registerHtml = `
|
||||
<div class="auth-page">
|
||||
<header class="auth-header">
|
||||
<button class="back-btn-white" id="registerBackBtn">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24"><path fill="currentColor" d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
|
||||
</button>
|
||||
<h1>注册</h1>
|
||||
</header>
|
||||
|
||||
<div class="auth-content">
|
||||
<div class="auth-form">
|
||||
<div class="auth-input-group">
|
||||
<label>用户名</label>
|
||||
<input type="text" id="registerUsername" placeholder="请输入用户名(3-20字符)" autocomplete="username">
|
||||
</div>
|
||||
<div class="auth-input-group">
|
||||
<label>密码</label>
|
||||
<input type="password" id="registerPassword" placeholder="请输入密码(6-20字符)" autocomplete="new-password">
|
||||
</div>
|
||||
<div class="auth-input-group">
|
||||
<label>确认密码</label>
|
||||
<input type="password" id="registerPasswordConfirm" placeholder="请再次输入密码" autocomplete="new-password">
|
||||
</div>
|
||||
<button class="auth-submit-btn" id="registerSubmitBtn">注册</button>
|
||||
</div>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>已有账号?<span class="auth-link" id="goToLogin">立即登录</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
appContainer.innerHTML = registerHtml;
|
||||
|
||||
// 绑定事件
|
||||
const backBtn = document.getElementById('registerBackBtn');
|
||||
if (backBtn) {
|
||||
backBtn.addEventListener('click', () => {
|
||||
showMainPage();
|
||||
});
|
||||
}
|
||||
|
||||
const submitBtn = document.getElementById('registerSubmitBtn');
|
||||
if (submitBtn) {
|
||||
submitBtn.addEventListener('click', handleRegister);
|
||||
}
|
||||
|
||||
const goToLogin = document.getElementById('goToLogin');
|
||||
if (goToLogin) {
|
||||
goToLogin.addEventListener('click', () => {
|
||||
showLoginPage();
|
||||
});
|
||||
}
|
||||
|
||||
// 回车注册
|
||||
document.getElementById('registerPasswordConfirm')?.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') handleRegister();
|
||||
});
|
||||
}
|
||||
|
||||
function handleRegister() {
|
||||
const username = document.getElementById('registerUsername')?.value.trim();
|
||||
const password = document.getElementById('registerPassword')?.value;
|
||||
const passwordConfirm = document.getElementById('registerPasswordConfirm')?.value;
|
||||
|
||||
if (!username || username.length < 3 || username.length > 20) {
|
||||
showToast('用户名需要3-20个字符');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password || password.length < 6 || password.length > 20) {
|
||||
showToast('密码需要6-20个字符');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
showToast('两次密码不一致');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
const users = JSON.parse(localStorage.getItem('registeredUsers') || '[]');
|
||||
if (users.find(u => u.username === username)) {
|
||||
showToast('用户名已存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 注册新用户
|
||||
const newUser = {
|
||||
username,
|
||||
password,
|
||||
registeredAt: Date.now()
|
||||
};
|
||||
|
||||
users.push(newUser);
|
||||
localStorage.setItem('registeredUsers', JSON.stringify(users));
|
||||
|
||||
// 自动登录
|
||||
currentUser = { username: newUser.username, registeredAt: newUser.registeredAt };
|
||||
saveCurrentUser();
|
||||
|
||||
showToast('注册成功');
|
||||
showMainPage();
|
||||
}
|
||||
|
||||
// ==================== 限制提示 ====================
|
||||
|
||||
function showLimitDialog(type) {
|
||||
let title = '';
|
||||
let message = '';
|
||||
let showLoginBtn = true;
|
||||
|
||||
switch (type) {
|
||||
case 'chat_session':
|
||||
title = '对话会话已达上限';
|
||||
message = `游客每天只能创建 ${GUEST_LIMITS.maxChatSessionsPerDay} 个对话会话。\n登录后即可无限使用。`;
|
||||
break;
|
||||
case 'chat_message':
|
||||
title = '对话消息已达上限';
|
||||
message = `游客每天最多发送 ${GUEST_LIMITS.maxChatMessagesPerDay} 条对话消息。\n登录后即可无限使用。`;
|
||||
break;
|
||||
case 'agent_type':
|
||||
title = '智能体限制';
|
||||
message = `游客只能使用「通用助手」智能体。\n登录后即可使用全部智能体。`;
|
||||
break;
|
||||
case 'agent_change':
|
||||
title = '智能体切换限制';
|
||||
message = `游客每天只能使用一个智能体。\n您今天已使用过智能体,明天才能更换。\n登录后即可自由切换智能体。`;
|
||||
break;
|
||||
case 'agent_message':
|
||||
title = '智能体消息已达上限';
|
||||
message = `游客每天最多发送 ${GUEST_LIMITS.maxAgentMessagesPerDay} 条智能体消息。\n登录后即可无限使用。`;
|
||||
break;
|
||||
default:
|
||||
title = '使用限制';
|
||||
message = '登录后解锁全部功能。';
|
||||
}
|
||||
|
||||
const dialogHtml = `
|
||||
<div class="limit-dialog" id="limitDialog">
|
||||
<div class="limit-dialog-content">
|
||||
<div class="limit-dialog-icon">⚠️</div>
|
||||
<div class="limit-dialog-title">${title}</div>
|
||||
<div class="limit-dialog-message">${message}</div>
|
||||
<div class="limit-dialog-actions">
|
||||
${showLoginBtn ? '<button class="limit-dialog-btn login" id="limitLoginBtn">登录</button>' : ''}
|
||||
<button class="limit-dialog-btn cancel" id="limitCancelBtn">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 添加到页面
|
||||
const existingDialog = document.getElementById('limitDialog');
|
||||
if (existingDialog) existingDialog.remove();
|
||||
|
||||
document.body.insertAdjacentHTML('beforeend', dialogHtml);
|
||||
|
||||
// 绑定事件
|
||||
const loginBtn = document.getElementById('limitLoginBtn');
|
||||
if (loginBtn) {
|
||||
loginBtn.addEventListener('click', () => {
|
||||
document.getElementById('limitDialog')?.remove();
|
||||
showLoginPage();
|
||||
});
|
||||
}
|
||||
|
||||
const cancelBtn = document.getElementById('limitCancelBtn');
|
||||
if (cancelBtn) {
|
||||
cancelBtn.addEventListener('click', () => {
|
||||
document.getElementById('limitDialog')?.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// 点击背景关闭
|
||||
document.getElementById('limitDialog')?.addEventListener('click', (e) => {
|
||||
if (e.target.id === 'limitDialog') {
|
||||
document.getElementById('limitDialog')?.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 查看全部历史使用
|
||||
function showAgentHistoryPage() {
|
||||
const allAgentConvos = getAgentConversationHistory(100); // 获取所有
|
||||
@@ -1222,11 +1745,36 @@ function openAgent(agentId) {
|
||||
currentAgent = systemAgents.find(a => a.id === agentId);
|
||||
if (!currentAgent) return;
|
||||
|
||||
// 检查未登录用户的智能体限制
|
||||
if (!currentUser) {
|
||||
const check = canUseAgent(agentId);
|
||||
if (!check.allowed) {
|
||||
if (check.reason === 'guest_agent_only') {
|
||||
showLimitDialog('agent_type');
|
||||
return;
|
||||
} else if (check.reason === 'guest_one_agent_only') {
|
||||
showLimitDialog('agent_change');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 记录使用的智能体
|
||||
setAgentUsed(agentId);
|
||||
}
|
||||
|
||||
// 创建新对话并设置智能体
|
||||
createNewConversation();
|
||||
currentConversation.agentId = agentId;
|
||||
currentConversation.title = currentAgent.name;
|
||||
const newConv = {
|
||||
id: Date.now().toString(),
|
||||
title: currentAgent.name,
|
||||
messages: [],
|
||||
agentId: agentId,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now()
|
||||
};
|
||||
|
||||
conversations.unshift(newConv);
|
||||
saveConversations();
|
||||
currentConversation = newConv;
|
||||
|
||||
// 显示对话界面
|
||||
showAgentChatPage();
|
||||
@@ -1895,6 +2443,12 @@ function togglePinConversation(convId) {
|
||||
|
||||
// 创建新对话
|
||||
function createNewConversation() {
|
||||
// 检查未登录用户的对话限制
|
||||
if (!currentUser && !canCreateNewChat()) {
|
||||
showLimitDialog('chat_session');
|
||||
return;
|
||||
}
|
||||
|
||||
const newConv = {
|
||||
id: Date.now().toString(),
|
||||
title: '新对话',
|
||||
@@ -1905,6 +2459,10 @@ function createNewConversation() {
|
||||
|
||||
conversations.unshift(newConv);
|
||||
saveConversations();
|
||||
|
||||
// 增加对话会话计数(未登录用户)
|
||||
incrementChatSession();
|
||||
|
||||
openConversation(newConv.id);
|
||||
}
|
||||
|
||||
@@ -2161,6 +2719,23 @@ async function sendMessage() {
|
||||
|
||||
const text = userInput.value.trim();
|
||||
if (!text || isLoading) return;
|
||||
|
||||
// 检查未登录用户的消息限制
|
||||
if (!currentUser) {
|
||||
if (currentConversation.agentId) {
|
||||
// 智能体对话
|
||||
if (!canSendAgentMessage()) {
|
||||
showLimitDialog('agent_message');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 普通对话
|
||||
if (!canSendChatMessage()) {
|
||||
showLimitDialog('chat_message');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏欢迎界面
|
||||
welcome.style.display = 'none';
|
||||
@@ -2181,6 +2756,15 @@ async function sendMessage() {
|
||||
currentConversation.updatedAt = Date.now();
|
||||
saveConversations();
|
||||
|
||||
// 增加消息计数(未登录用户)
|
||||
if (!currentUser) {
|
||||
if (currentConversation.agentId) {
|
||||
incrementAgentMessage();
|
||||
} else {
|
||||
incrementChatMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// 发送新消息时启用自动滚动
|
||||
autoScrollEnabled = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user