功能特点: - 支持8种方言(普通话、四川话、粤语、上海话、客家话、闽南话、东北话、河南话) - 用户注册登录系统(用户名、手机、邮箱可选、密码确认) - 对话功能(文字输入、语音识别、文件图片上传) - 多对话管理(新建、切换、删除) - 移动端适配(响应式设计、触摸友好) 技术栈: - Flask后端API - 原生HTML/CSS/JS前端 - Web Speech API语音识别 - JWT用户认证 - 大模型: qwen3.5-4b 端口: 19002
217 lines
11 KiB
HTML
217 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>方言AI助手 - 登录</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
|
<style>
|
|
* { -webkit-tap-highlight-color: transparent; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
|
.gradient-bg { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-100 min-h-screen">
|
|
<div class="min-h-screen flex flex-col">
|
|
<!-- 头部 -->
|
|
<div class="gradient-bg text-white p-6 pb-12">
|
|
<h1 class="text-2xl font-bold text-center">🗣️ 方言AI助手</h1>
|
|
<p class="text-center text-white/80 mt-2 text-sm">用家乡话聊天,更亲切</p>
|
|
</div>
|
|
|
|
<!-- 表单区域 -->
|
|
<div class="flex-1 -mt-6">
|
|
<div class="bg-white rounded-t-3xl shadow-lg p-6 max-w-md mx-auto">
|
|
<!-- Tab切换 -->
|
|
<div class="flex mb-6 bg-gray-100 rounded-lg p-1">
|
|
<button id="loginTab" onclick="showTab('login')"
|
|
class="flex-1 py-2 rounded-lg bg-white shadow text-gray-800 font-medium transition-all">
|
|
登录
|
|
</button>
|
|
<button id="registerTab" onclick="showTab('register')"
|
|
class="flex-1 py-2 rounded-lg text-gray-500 transition-all">
|
|
注册
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 登录表单 -->
|
|
<form id="loginForm" class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">用户名</label>
|
|
<div class="relative">
|
|
<i class="ri-user-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="text" id="loginUsername" placeholder="请输入用户名"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">密码</label>
|
|
<div class="relative">
|
|
<i class="ri-lock-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="password" id="loginPassword" placeholder="请输入密码"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent">
|
|
</div>
|
|
</div>
|
|
<button type="submit"
|
|
class="w-full py-3 gradient-bg text-white rounded-lg font-medium hover:opacity-90 transition-opacity">
|
|
登录
|
|
</button>
|
|
</form>
|
|
|
|
<!-- 注册表单 -->
|
|
<form id="registerForm" class="space-y-4 hidden">
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">用户名 <span class="text-red-500">*</span></label>
|
|
<div class="relative">
|
|
<i class="ri-user-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="text" id="regUsername" placeholder="至少2个字符"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">手机号 <span class="text-red-500">*</span></label>
|
|
<div class="relative">
|
|
<i class="ri-phone-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="tel" id="regPhone" placeholder="请输入手机号"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">邮箱 <span class="text-gray-400">(可选)</span></label>
|
|
<div class="relative">
|
|
<i class="ri-mail-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="email" id="regEmail" placeholder="选填"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">密码 <span class="text-red-500">*</span></label>
|
|
<div class="relative">
|
|
<i class="ri-lock-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="password" id="regPassword" placeholder="至少6个字符"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-600 mb-1">确认密码 <span class="text-red-500">*</span></label>
|
|
<div class="relative">
|
|
<i class="ri-lock-2-line absolute left-3 top-3 text-gray-400"></i>
|
|
<input type="password" id="regConfirmPassword" placeholder="再次输入密码"
|
|
class="w-full pl-10 pr-4 py-3 border border-gray-200 rounded-lg focus:ring-2 focus:ring-purple-500">
|
|
</div>
|
|
</div>
|
|
<button type="submit"
|
|
class="w-full py-3 gradient-bg text-white rounded-lg font-medium hover:opacity-90">
|
|
注册
|
|
</button>
|
|
</form>
|
|
|
|
<!-- 错误提示 -->
|
|
<div id="errorMsg" class="mt-4 p-3 bg-red-50 text-red-500 rounded-lg text-sm hidden"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 底部 -->
|
|
<div class="text-center p-4 text-gray-400 text-sm">
|
|
方言AI助手 © 2026
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const API_URL = '';
|
|
let currentTab = 'login';
|
|
|
|
function showTab(tab) {
|
|
currentTab = tab;
|
|
document.getElementById('loginForm').classList.toggle('hidden', tab !== 'login');
|
|
document.getElementById('registerForm').classList.toggle('hidden', tab !== 'register');
|
|
document.getElementById('loginTab').classList.toggle('bg-white', tab === 'login');
|
|
document.getElementById('loginTab').classList.toggle('shadow', tab === 'login');
|
|
document.getElementById('loginTab').classList.toggle('text-gray-800', tab === 'login');
|
|
document.getElementById('loginTab').classList.toggle('text-gray-500', tab !== 'login');
|
|
document.getElementById('registerTab').classList.toggle('bg-white', tab === 'register');
|
|
document.getElementById('registerTab').classList.toggle('shadow', tab === 'register');
|
|
document.getElementById('registerTab').classList.toggle('text-gray-800', tab === 'register');
|
|
document.getElementById('registerTab').classList.toggle('text-gray-500', tab !== 'register');
|
|
document.getElementById('errorMsg').classList.add('hidden');
|
|
}
|
|
|
|
function showError(msg) {
|
|
const el = document.getElementById('errorMsg');
|
|
el.textContent = msg;
|
|
el.classList.remove('hidden');
|
|
}
|
|
|
|
// 登录
|
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const username = document.getElementById('loginUsername').value.trim();
|
|
const password = document.getElementById('loginPassword').value;
|
|
|
|
if (!username || !password) {
|
|
showError('请输入用户名和密码');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('/api/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
localStorage.setItem('token', data.token);
|
|
localStorage.setItem('user', JSON.stringify(data.user));
|
|
window.location.href = '/chat';
|
|
} else {
|
|
showError(data.error);
|
|
}
|
|
} catch (err) {
|
|
showError('网络错误,请重试');
|
|
}
|
|
});
|
|
|
|
// 注册
|
|
document.getElementById('registerForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const username = document.getElementById('regUsername').value.trim();
|
|
const phone = document.getElementById('regPhone').value.trim();
|
|
const email = document.getElementById('regEmail').value.trim();
|
|
const password = document.getElementById('regPassword').value;
|
|
const confirm_password = document.getElementById('regConfirmPassword').value;
|
|
|
|
if (!username || !phone || !password || !confirm_password) {
|
|
showError('请填写必填项');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('/api/register', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ username, phone, email, password, confirm_password })
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.success) {
|
|
localStorage.setItem('token', data.token);
|
|
localStorage.setItem('user', JSON.stringify(data.user));
|
|
window.location.href = '/chat';
|
|
} else {
|
|
showError(data.error);
|
|
}
|
|
} catch (err) {
|
|
showError('网络错误,请重试');
|
|
}
|
|
});
|
|
|
|
// 检查是否已登录
|
|
if (localStorage.getItem('token')) {
|
|
window.location.href = '/chat';
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |