606 lines
21 KiB
HTML
606 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title data-i18n="spacetitle">黑盒广场</title>
|
|
<script src="lang-1.7.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: 'Helvetica Neue', Arial, sans-serif;
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 50px;
|
|
line-height: 1.8;
|
|
background-color: #f5f5f5;
|
|
color: #333;
|
|
position: relative;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 3.2em;
|
|
color: #1a1a1a;
|
|
margin-bottom: 40px;
|
|
text-align: center;
|
|
letter-spacing: 5px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.card-container {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 20px;
|
|
margin-top: 40px;
|
|
}
|
|
|
|
.card {
|
|
background-color: white;
|
|
border-radius: 15px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
padding: 25px;
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
border-left: 4px solid #1a1a1a;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 6px 12px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.card-title {
|
|
font-weight: 600;
|
|
margin-bottom: 15px;
|
|
color: #1a1a1a;
|
|
font-size: 1.1em;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.card-placeholder {
|
|
min-height: 150px; /* Adjust this value based on your actual card height */
|
|
}
|
|
|
|
#content-display {
|
|
margin-top: 40px;
|
|
}
|
|
|
|
.message-container {
|
|
background-color: white;
|
|
border-radius: 15px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
margin-bottom: 25px;
|
|
padding: 25px;
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
border-left: 4px solid #1a1a1a;
|
|
}
|
|
|
|
.message-role {
|
|
font-weight: 600;
|
|
margin-bottom: 15px;
|
|
color: #1a1a1a;
|
|
font-size: 1.1em;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.message-text {
|
|
white-space: pre-wrap;
|
|
margin-bottom: 20px;
|
|
line-height: 1.8;
|
|
color: #333;
|
|
}
|
|
|
|
.audio-player {
|
|
width: 100%;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
body {
|
|
padding: 30px;
|
|
}
|
|
|
|
.card-container {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
.new-meeting-btn {
|
|
display: block;
|
|
width: 200px;
|
|
margin: 30px auto;
|
|
padding: 15px 20px;
|
|
font-size: 1.2em;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
color: white;
|
|
background-color: #1a1a1a;
|
|
border: none;
|
|
border-radius: 10px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.new-meeting-btn:hover {
|
|
background-color: #333;
|
|
}
|
|
|
|
.pagination {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.pagination button {
|
|
margin: 0 5px;
|
|
padding: 5px 10px;
|
|
background-color: #ccc;
|
|
color: black;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease, color 0.3s ease;
|
|
}
|
|
|
|
.pagination button.active {
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
}
|
|
|
|
.pagination button:hover {
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
}
|
|
|
|
/* 添加语言选择器样式 */
|
|
.container {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
padding: 20px 0;
|
|
width: 100%;
|
|
max-width: 1000px;
|
|
box-sizing: border-box;
|
|
margin: 0 auto;
|
|
}
|
|
.right-section {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
#language-selector {
|
|
margin: 10px;
|
|
}
|
|
|
|
#language-select {
|
|
padding: 10px 20px;
|
|
font-size: 16px;
|
|
border: none;
|
|
border-radius: 25px;
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
width: auto; /* Allow the width to adjust to content */
|
|
min-width: 40px; /* Set a minimum width */
|
|
}
|
|
|
|
#language-select:hover {
|
|
background-color: #333;
|
|
}
|
|
|
|
#language-select option {
|
|
background-color: white;
|
|
color: black;
|
|
padding: 10px;
|
|
}
|
|
|
|
#language-select:focus {
|
|
outline: none;
|
|
box-shadow: 0 0 0 2px rgba(255,255,255,0.5);
|
|
}
|
|
.avatar {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
margin-right: 20px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.message-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.user-info {
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
cursor: pointer;
|
|
margin-left: auto; /* 将用户信息推到右侧 */
|
|
}
|
|
|
|
.user-avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-weight: bold;
|
|
font-size: 20px;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.user-dropdown {
|
|
display: none;
|
|
position: absolute;
|
|
top: 100%;
|
|
right: 0;
|
|
background-color: white;
|
|
border: 1px solid #ccc;
|
|
border-radius: 5px;
|
|
padding: 10px;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.user-dropdown.show {
|
|
display: block;
|
|
}
|
|
|
|
.logout-btn {
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 10px; /* Increased padding */
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
width: 100%; /* Make the button full width within its container */
|
|
min-width: 60px; /* Set a minimum width */
|
|
font-size: 13px; /* Increased font size */
|
|
transition: background-color 0.3s ease; /* Smooth transition for hover effect */
|
|
}
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
.container {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 10px;
|
|
width: calc(100% - 30px);
|
|
}
|
|
|
|
.right-section {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-left: auto; /* 将右侧部分推到最右边 */
|
|
}
|
|
|
|
#language-select {
|
|
font-size: 14px;
|
|
padding: 8px 16px;
|
|
white-space: nowrap;
|
|
width: 100px;
|
|
min-width: 100px;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.user-info {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.user-dropdown {
|
|
right: 0;
|
|
left: auto;
|
|
transform: none;
|
|
}
|
|
|
|
.logout-btn {
|
|
background-color: #1a1a1a;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 8px;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
width: auto; /* 调整为自动宽度 */
|
|
min-width: 60px;
|
|
font-size: 13px;
|
|
transition: background-color 0.3s ease;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="right-section">
|
|
<div id="language-selector">
|
|
<select id="language-select">
|
|
<option value="zh">中文</option>
|
|
<option value="en">English</option>
|
|
<option value="ko">한국어</option>
|
|
</select>
|
|
</div>
|
|
<div class="user-info" id="userInfo">
|
|
<div class="user-avatar" id="userAvatar"></div>
|
|
<span id="username"></span>
|
|
<div class="user-dropdown" id="userDropdown">
|
|
<button class="logout-btn" id="logoutBtn" data-i18n="logout">登出</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<h1 data-i18n="spacetitle">黑盒广场</h1>
|
|
<button class="new-meeting-btn" onclick="window.location.href='https://beta.obscura.work/boxtable.html'" data-i18n="newMeeting">进入黑盒圆桌</button>
|
|
|
|
<div class="card-container" id="cardContainer"></div>
|
|
|
|
<div class="pagination" id="pagination"></div>
|
|
|
|
<div id="content-display"></div>
|
|
|
|
<script>
|
|
const BASE_URL = 'https://dev.obscura.work/user';
|
|
const cardContainer = document.getElementById('cardContainer');
|
|
const contentDisplay = document.getElementById('content-display');
|
|
const paginationContainer = document.getElementById('pagination');
|
|
const ITEMS_PER_PAGE = 9;
|
|
let currentPage = 1;
|
|
let allSessions = [];
|
|
|
|
// 获取URL参数中的语言设置
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
let currentLanguage = urlParams.get('lang') || localStorage.getItem('preferredLanguage') || 'zh';
|
|
|
|
// 修改 checkLoginStatus 函数
|
|
async function checkLoginStatus() {
|
|
const token = localStorage.getItem('access_token');
|
|
if (!token) {
|
|
console.log('未找到访问令牌,正在跳转到登录页面');
|
|
window.location.href = '/login.html';
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`${BASE_URL}/me`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('未登录或会话已过期');
|
|
}
|
|
|
|
console.log('用户已登录,正在获取用户信息');
|
|
await fetchUserInfo();
|
|
return true;
|
|
} catch (error) {
|
|
console.error('检查登录状态时出错:', error);
|
|
localStorage.removeItem('access_token');
|
|
console.log('登录状态无效,正在跳转到登录页面');
|
|
window.location.href = '/login.html';
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 修改 fetchUserInfo 函数
|
|
async function fetchUserInfo() {
|
|
try {
|
|
const response = await fetch(`${BASE_URL}/user-info`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
|
|
}
|
|
});
|
|
if (response.ok) {
|
|
const userData = await response.json();
|
|
// console.log('成功获取用户信息:', userData);
|
|
usernameSpan.textContent = userData.username;
|
|
userAvatar.textContent = userData.username.charAt(0).toUpperCase();
|
|
console.log('用户信息已更新');
|
|
} else {
|
|
throw new Error('Failed to fetch user info');
|
|
}
|
|
} catch (error) {
|
|
console.error('获取用户信息时出错:', error);
|
|
// 不再调用 hideUserInfo
|
|
}
|
|
}
|
|
|
|
async function getSessionData() {
|
|
try {
|
|
const lang = document.getElementById('language-select').value;
|
|
const response = await fetch(`${BASE_URL}/api/get-session-id?language=${lang}`);
|
|
if (!response.ok) {
|
|
throw new Error(translations[currentLanguage].fetchError);
|
|
}
|
|
const data = await response.json();
|
|
return data.sessions;
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
cardContainer.innerHTML = `<p>${translations[currentLanguage].fetchErrorMessage}</p>`;
|
|
return [];
|
|
}
|
|
}
|
|
function openDiscussion(sessionId, discussionNumber) {
|
|
const lang = document.getElementById('language-select').value;
|
|
window.open(`history.html?session_id=${encodeURIComponent(sessionId)}&discussion_number=${encodeURIComponent(discussionNumber)}&lang=${lang}`, '_blank');
|
|
}
|
|
|
|
// 在 getSessionData 函数之后添加一个新的排序函数
|
|
function sortSessionsByTimestamp(sessions) {
|
|
return sessions.sort((a, b) => {
|
|
const dateA = new Date(a.timestamp);
|
|
const dateB = new Date(b.timestamp);
|
|
return dateB - dateA; // 倒序排列,最新的在前
|
|
});
|
|
}
|
|
|
|
// 修改 initializePage 函数
|
|
async function initializePage() {
|
|
console.log('开始初始化页面');
|
|
await checkLoginStatus(); // 如果未登录,这里会直接跳转到登录页面
|
|
|
|
allSessions = await getSessionData();
|
|
if (allSessions && allSessions.length > 0) {
|
|
allSessions = sortSessionsByTimestamp(allSessions); // 对会话进行排序
|
|
const totalPages = Math.ceil(allSessions.length / ITEMS_PER_PAGE);
|
|
changePage(1);
|
|
} else {
|
|
cardContainer.innerHTML = `<p>${translations[currentLanguage].noSessions}</p>`;
|
|
}
|
|
}
|
|
|
|
// 修改 displaySessionCards 函数
|
|
function displaySessionCards(sessions) {
|
|
cardContainer.innerHTML = '';
|
|
for (let i = 0; i < ITEMS_PER_PAGE; i++) {
|
|
if (i < sessions.length) {
|
|
const session = sessions[i];
|
|
const discussionNumber = allSessions.length - ((currentPage - 1) * ITEMS_PER_PAGE + i); // 修改讨论编号计算方式
|
|
const card = document.createElement('div');
|
|
card.className = 'card';
|
|
card.innerHTML = `
|
|
<div class="card-title">${translations[currentLanguage].historytitle.replace('{0}', discussionNumber)}</div>
|
|
<div class="card-topic">${session.topic}</div>
|
|
<div class="card-timestamp">${session.timestamp}</div>
|
|
`;
|
|
card.onclick = () => openDiscussion(session.session_id, discussionNumber);
|
|
cardContainer.appendChild(card);
|
|
} else {
|
|
const placeholder = document.createElement('div');
|
|
placeholder.className = 'card-placeholder';
|
|
cardContainer.appendChild(placeholder);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function displayPagination(totalPages) {
|
|
paginationContainer.innerHTML = '';
|
|
|
|
const prevButton = document.createElement('button');
|
|
prevButton.textContent = translations[currentLanguage].prevPage;
|
|
prevButton.onclick = () => changePage(currentPage - 1);
|
|
paginationContainer.appendChild(prevButton);
|
|
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
const pageButton = document.createElement('button');
|
|
pageButton.textContent = i;
|
|
pageButton.onclick = () => changePage(i);
|
|
if (i === currentPage) {
|
|
pageButton.classList.add('active');
|
|
}
|
|
paginationContainer.appendChild(pageButton);
|
|
}
|
|
|
|
const nextButton = document.createElement('button');
|
|
nextButton.textContent = translations[currentLanguage].nextPage;
|
|
nextButton.onclick = () => changePage(currentPage + 1);
|
|
paginationContainer.appendChild(nextButton);
|
|
}
|
|
|
|
function changePage(newPage) {
|
|
const totalPages = Math.ceil(allSessions.length / ITEMS_PER_PAGE);
|
|
if (newPage < 1 || newPage > totalPages) {
|
|
return;
|
|
}
|
|
currentPage = newPage;
|
|
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
|
|
const endIndex = startIndex + ITEMS_PER_PAGE;
|
|
const sessionsToDisplay = allSessions.slice(startIndex, endIndex);
|
|
displaySessionCards(sessionsToDisplay);
|
|
displayPagination(totalPages);
|
|
}
|
|
|
|
// 修改初始化页面的函数
|
|
async function initializePage() {
|
|
console.log('开始初始化页面');
|
|
await checkLoginStatus(); // 如果未登录,这里会直接跳转到登录页面
|
|
|
|
allSessions = await getSessionData();
|
|
if (allSessions && allSessions.length > 0) {
|
|
allSessions = sortSessionsByTimestamp(allSessions); // 对会话进行排序
|
|
const totalPages = Math.ceil(allSessions.length / ITEMS_PER_PAGE);
|
|
changePage(1);
|
|
} else {
|
|
cardContainer.innerHTML = `<p>${translations[currentLanguage].noSessions}</p>`;
|
|
}
|
|
}
|
|
|
|
function updateLanguage(lang) {
|
|
currentLanguage = lang;
|
|
localStorage.setItem('preferredLanguage', lang);
|
|
document.documentElement.lang = lang;
|
|
document.querySelectorAll('[data-i18n]').forEach(element => {
|
|
const key = element.getAttribute('data-i18n');
|
|
if (translations[lang][key]) {
|
|
element.textContent = translations[lang][key];
|
|
}
|
|
});
|
|
|
|
// 更新URL,不刷新页面
|
|
const newUrl = new URL(window.location.href);
|
|
newUrl.searchParams.set('lang', lang);
|
|
window.history.pushState({}, '', newUrl);
|
|
|
|
// 重新加载卡片和分页
|
|
initializePage();
|
|
}
|
|
|
|
document.getElementById('language-select').addEventListener('change', function() {
|
|
updateLanguage(this.value);
|
|
});
|
|
|
|
// 修改 DOMContentLoaded 事件监听器
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
console.log('DOM 内容已加载,开始初始化');
|
|
document.getElementById('language-select').value = currentLanguage;
|
|
updateLanguage(currentLanguage);
|
|
await initializePage();
|
|
console.log('页面初始化完成');
|
|
});
|
|
|
|
// 修改新会议按钮的点击事件
|
|
document.querySelector('.new-meeting-btn').addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
const lang = document.getElementById('language-select').value;
|
|
window.location.href = `https://beta.obscura.work/boxtable.html?lang=${lang}`;
|
|
});
|
|
|
|
// 添加用户信息和登出功能
|
|
const userInfo = document.getElementById('userInfo');
|
|
const userDropdown = document.getElementById('userDropdown');
|
|
const logoutBtn = document.getElementById('logoutBtn');
|
|
const usernameSpan = document.getElementById('username');
|
|
const userAvatar = document.getElementById('userAvatar');
|
|
|
|
userInfo.addEventListener('click', () => {
|
|
userDropdown.classList.toggle('show');
|
|
});
|
|
|
|
logoutBtn.addEventListener('click', async () => {
|
|
try {
|
|
const response = await fetch(`${BASE_URL}/logout`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
|
|
}
|
|
});
|
|
if (response.ok) {
|
|
localStorage.removeItem('access_token');
|
|
window.location.href = '/login.html';
|
|
}
|
|
} catch (error) {
|
|
console.error('Error logging out:', error);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|