Files
zydi-roundtable/space.html
T
2025-01-12 07:44:51 +00:00

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>