// 角色管理页面脚本 - 包含角色权重系统 document.addEventListener('DOMContentLoaded', () => { // DOM元素 const charactersContainer = document.getElementById('characters-container'); const characterSearch = document.getElementById('character-search'); const characterTypeFilter = document.getElementById('character-type-filter'); const newCharacterBtn = document.getElementById('new-character-btn'); // 所有模态框 const characterModal = document.getElementById('character-modal'); const eventModal = document.getElementById('event-modal'); const characterDetailModal = document.getElementById('character-detail-modal'); const confirmModal = document.getElementById('confirm-modal'); // 角色表单元素 const characterForm = document.getElementById('character-form'); const characterIdInput = document.getElementById('character-id'); const characterNameInput = document.getElementById('character-name'); const characterTitleInput = document.getElementById('character-title'); const characterAvatarInput = document.getElementById('character-avatar'); const characterAvatarPathInput = document.getElementById('character-avatar-path'); const characterTypeInput = document.getElementById('character-type'); const characterWeightInput = document.getElementById('character-weight'); // 权重输入字段 // 事件表单元素 const eventForm = document.getElementById('event-form'); const eventCharacterIdInput = document.getElementById('event-character-id'); const eventIdInput = document.getElementById('event-id'); const eventTextInput = document.getElementById('event-text'); const optionATextInput = document.getElementById('option-a-text'); const optionBTextInput = document.getElementById('option-b-text'); // 详情页元素 const detailTitle = document.getElementById('detail-title'); const detailAvatar = document.getElementById('detail-avatar'); const detailName = document.getElementById('detail-name'); const detailTitleText = document.getElementById('detail-title-text'); const detailType = document.getElementById('detail-type'); const editCharacterBtn = document.getElementById('edit-character-btn'); const deleteCharacterBtn = document.getElementById('delete-character-btn'); const addEventBtn = document.getElementById('add-event-btn'); const eventsContainer = document.getElementById('events-container'); // 确认对话框元素 const confirmTitle = document.getElementById('confirm-title'); const confirmMessage = document.getElementById('confirm-message'); const confirmOkBtn = document.getElementById('confirm-ok'); const confirmCancelBtn = document.getElementById('confirm-cancel'); // 状态变量 let characters = []; let currentCharacter = null; let filteredCharacters = []; let confirmCallback = null; // 初始化 loadCharacters(); setupEventListeners(); // 设置事件监听器 function setupEventListeners() { // 搜索和过滤 characterSearch.addEventListener('input', filterCharacters); characterTypeFilter.addEventListener('change', filterCharacters); // 新建角色按钮 newCharacterBtn.addEventListener('click', () => { openNewCharacterModal(); }); // 表单提交 characterForm.addEventListener('submit', saveCharacter); eventForm.addEventListener('submit', saveEvent); // 编辑角色按钮 editCharacterBtn.addEventListener('click', () => { if (currentCharacter) { // 先关闭详情模态框 closeModal(characterDetailModal); // 再打开编辑模态框 setTimeout(() => { openEditCharacterModal(currentCharacter); }, 300); } }); // 删除角色按钮 deleteCharacterBtn.addEventListener('click', () => { if (currentCharacter) { openConfirmModal( '删除角色', `确定要删除角色 "${currentCharacter.name}" 吗?此操作不可恢复,且会删除该角色的所有事件。`, () => deleteCharacter(currentCharacter.id) ); } }); // 添加事件按钮 addEventBtn.addEventListener('click', () => { if (currentCharacter) { // 先关闭详情模态框 closeModal(characterDetailModal); // 再打开事件模态框 setTimeout(() => { openNewEventModal(currentCharacter.id); }, 300); } }); // 确认对话框按钮 confirmOkBtn.addEventListener('click', () => { if (confirmCallback) { confirmCallback(); } closeModal(confirmModal); }); confirmCancelBtn.addEventListener('click', () => { closeModal(confirmModal); }); // 关闭按钮 document.querySelectorAll('.close-modal, .close-btn').forEach(btn => { btn.addEventListener('click', (e) => { const modal = e.target.closest('.modal'); if (modal) { closeModal(modal); } }); }); // 点击模态框背景关闭 document.querySelectorAll('.modal').forEach(modal => { modal.addEventListener('click', (e) => { if (e.target === modal) { closeModal(modal); } }); }); // 防止冒泡 document.querySelectorAll('.modal-content').forEach(content => { content.addEventListener('click', (e) => { e.stopPropagation(); }); }); } // 加载所有角色 function loadCharacters() { charactersContainer.innerHTML = '
加载中...
'; fetch('/api/admin/characters') .then(response => response.json()) .then(data => { characters = data.characters || []; filteredCharacters = [...characters]; renderCharacters(); }) .catch(error => { console.error('加载角色失败:', error); charactersContainer.innerHTML = '
加载失败,请刷新页面重试。
'; }); } // 过滤角色 function filterCharacters() { const searchTerm = characterSearch.value.toLowerCase(); const typeFilter = characterTypeFilter.value; filteredCharacters = characters.filter(character => { const nameMatch = (character.name || '').toLowerCase().includes(searchTerm) || ((character.title || '').toLowerCase().includes(searchTerm)); const typeMatch = typeFilter === 'all' || character.type === typeFilter; return nameMatch && typeMatch; }); renderCharacters(); } // 渲染角色列表 function renderCharacters() { if (filteredCharacters.length === 0) { charactersContainer.innerHTML = '
没有找到符合条件的角色
'; return; } charactersContainer.innerHTML = ''; filteredCharacters.forEach(character => { const card = document.createElement('div'); card.className = 'character-card'; card.dataset.id = character.id; // 设置角色类型标签 let typeLabel = '未知'; let typeClass = ''; switch(character.type) { case 'resident': typeLabel = '常驻角色'; typeClass = 'type-resident'; break; case 'special': typeLabel = '特殊角色'; typeClass = 'type-special'; break; case 'status': typeLabel = '状态效果'; typeClass = 'type-status'; break; } // 添加权重标签 const weightLabel = `
权重: ${character.weight || 100}
`; card.innerHTML = `
${character.avatar || '👤'}

${character.name || '无名角色'}

${character.title || '无头衔'}

${typeLabel}
${weightLabel} `; card.addEventListener('click', () => openCharacterDetail(character)); charactersContainer.appendChild(card); }); } // 打开新角色模态框 function openNewCharacterModal() { // 重置表单 characterForm.reset(); characterIdInput.value = generateUUID(); // 设置默认权重值 characterWeightInput.value = 5; // 设置标题 document.getElementById('modal-title').textContent = '新建人物'; // 打开模态框 openModal(characterModal); } // 打开编辑角色模态框 function openEditCharacterModal(character) { // 设置标题 document.getElementById('modal-title').textContent = '编辑人物'; // 填充表单 characterIdInput.value = character.id; characterNameInput.value = character.name || ''; characterTitleInput.value = character.title || ''; characterAvatarInput.value = character.avatar || ''; characterAvatarPathInput.value = character.avatarPath || ''; characterTypeInput.value = character.type || 'resident'; characterWeightInput.value = character.weight || 100; // 设置权重值 // 打开模态框 openModal(characterModal); } // 打开新事件模态框 function openNewEventModal(characterId) { // 重置表单 eventForm.reset(); eventCharacterIdInput.value = characterId; eventIdInput.value = generateUUID(); // 设置所有数值为0 document.querySelectorAll('.effect-item input[type="number"]').forEach(input => { input.value = 0; }); // 设置标题 document.getElementById('event-modal-title').textContent = '新建事件'; // 打开模态框 openModal(eventModal); } // 打开编辑事件模态框 function openEditEventModal(characterId, event) { // 设置标题 document.getElementById('event-modal-title').textContent = '编辑事件'; // 填充表单基本信息 eventCharacterIdInput.value = characterId; eventIdInput.value = event.id; eventTextInput.value = event.text || ''; // 填充选项A if (event.optionA) { optionATextInput.value = event.optionA.text || ''; if (event.optionA.effects) { document.getElementById('option-a-loyalty').value = event.optionA.effects.loyalty || 0; document.getElementById('option-a-chaos').value = event.optionA.effects.chaos || 0; document.getElementById('option-a-population').value = event.optionA.effects.population || 0; document.getElementById('option-a-military').value = event.optionA.effects.military || 0; document.getElementById('option-a-resources').value = event.optionA.effects.resources || 0; } document.getElementById('option-a-add-status').value = event.optionA.add_status || ''; document.getElementById('option-a-remove-status').value = event.optionA.remove_status || ''; } // 填充选项B if (event.optionB) { optionBTextInput.value = event.optionB.text || ''; if (event.optionB.effects) { document.getElementById('option-b-loyalty').value = event.optionB.effects.loyalty || 0; document.getElementById('option-b-chaos').value = event.optionB.effects.chaos || 0; document.getElementById('option-b-population').value = event.optionB.effects.population || 0; document.getElementById('option-b-military').value = event.optionB.effects.military || 0; document.getElementById('option-b-resources').value = event.optionB.effects.resources || 0; } document.getElementById('option-b-add-status').value = event.optionB.add_status || ''; document.getElementById('option-b-remove-status').value = event.optionB.remove_status || ''; } // 打开模态框 openModal(eventModal); } // 打开角色详情 function openCharacterDetail(character) { // 保存当前角色 currentCharacter = character; // 填充详情 detailTitle.textContent = '角色详情: ' + character.name; detailAvatar.textContent = character.avatar || '👤'; detailName.textContent = character.name || '无名角色'; detailTitleText.textContent = character.title || '无头衔'; // 显示权重 const weightElement = document.getElementById('detail-weight').querySelector('span'); if (weightElement) { weightElement.textContent = character.weight || 100; } // 设置角色类型 let typeLabel = '未知类型'; switch(character.type) { case 'resident': typeLabel = '常驻角色'; break; case 'special': typeLabel = '特殊角色'; break; case 'status': typeLabel = '状态效果'; break; } detailType.textContent = typeLabel; // 渲染事件列表 renderEvents(character); // 打开模态框 openModal(characterDetailModal); } // 打开确认对话框 function openConfirmModal(title, message, callback) { // 设置内容 confirmTitle.textContent = title; confirmMessage.textContent = message; confirmCallback = callback; // 打开模态框 openModal(confirmModal); } // 打开模态框通用函数 function openModal(modal) { // 禁止背景滚动 document.body.style.overflow = 'hidden'; // 确保模态框在DOM中 if (!document.body.contains(modal)) { document.body.appendChild(modal); } // 显示模态框 modal.style.display = 'block'; } // 关闭模态框通用函数 function closeModal(modal) { modal.style.display = 'none'; // 恢复背景滚动 document.body.style.overflow = ''; } // 渲染角色的事件列表 function renderEvents(character) { if (!character.events || character.events.length === 0) { eventsContainer.innerHTML = '
该角色暂无事件
'; return; } eventsContainer.innerHTML = ''; character.events.forEach(event => { const eventItem = document.createElement('div'); eventItem.className = 'event-item'; eventItem.innerHTML = `

事件ID: ${event.id}

${event.text || '无描述'}

`; // 编辑事件按钮 eventItem.querySelector('.edit-event-btn').addEventListener('click', (e) => { e.stopPropagation(); closeModal(characterDetailModal); setTimeout(() => { openEditEventModal(character.id, event); }, 300); }); // 删除事件按钮 eventItem.querySelector('.delete-event-btn').addEventListener('click', (e) => { e.stopPropagation(); openConfirmModal( '删除事件', `确定要删除此事件吗?此操作不可恢复。`, () => deleteEvent(character.id, event.id) ); }); eventsContainer.appendChild(eventItem); }); } // 保存角色 function saveCharacter(e) { e.preventDefault(); // 获取表单数据 const characterData = { id: characterIdInput.value, name: characterNameInput.value, title: characterTitleInput.value, avatar: characterAvatarInput.value, avatarPath: characterAvatarPathInput.value, type: characterTypeInput.value, weight: parseInt(characterWeightInput.value) || 100, // 添加权重字段 events: [] }; // 如果是编辑现有角色,保留原有事件 const existingCharacter = characters.find(c => c.id === characterData.id); if (existingCharacter && existingCharacter.events) { characterData.events = existingCharacter.events; } // 发送请求 fetch('/api/admin/character', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(characterData) }) .then(response => response.json()) .then(data => { if (data.success) { // 更新列表 loadCharacters(); // 关闭模态框 closeModal(characterModal); // 如果是编辑现有角色,更新详情页 if (currentCharacter && currentCharacter.id === characterData.id) { currentCharacter = characterData; setTimeout(() => { openCharacterDetail(currentCharacter); }, 300); } } else { alert('保存失败: ' + (data.error || '未知错误')); } }) .catch(error => { console.error('保存角色失败:', error); alert('保存失败,请稍后重试'); }); } // 保存事件 function saveEvent(e) { e.preventDefault(); // 收集表单数据 const characterId = eventCharacterIdInput.value; const eventData = { id: eventIdInput.value, text: eventTextInput.value, optionA: { text: optionATextInput.value, effects: { loyalty: parseInt(document.getElementById('option-a-loyalty').value) || 0, chaos: parseInt(document.getElementById('option-a-chaos').value) || 0, population: parseInt(document.getElementById('option-a-population').value) || 0, military: parseInt(document.getElementById('option-a-military').value) || 0, resources: parseInt(document.getElementById('option-a-resources').value) || 0 } }, optionB: { text: optionBTextInput.value, effects: { loyalty: parseInt(document.getElementById('option-b-loyalty').value) || 0, chaos: parseInt(document.getElementById('option-b-chaos').value) || 0, population: parseInt(document.getElementById('option-b-population').value) || 0, military: parseInt(document.getElementById('option-b-military').value) || 0, resources: parseInt(document.getElementById('option-b-resources').value) || 0 } } }; // 添加状态效果(如果有) const optionAAddStatus = document.getElementById('option-a-add-status').value; if (optionAAddStatus) { eventData.optionA.add_status = optionAAddStatus; } const optionARemoveStatus = document.getElementById('option-a-remove-status').value; if (optionARemoveStatus) { eventData.optionA.remove_status = optionARemoveStatus; } const optionBAddStatus = document.getElementById('option-b-add-status').value; if (optionBAddStatus) { eventData.optionB.add_status = optionBAddStatus; } const optionBRemoveStatus = document.getElementById('option-b-remove-status').value; if (optionBRemoveStatus) { eventData.optionB.remove_status = optionBRemoveStatus; } // 判断是新增还是更新 const isNewEvent = !characters.some(c => c.id === characterId && c.events && c.events.some(e => e.id === eventData.id) ); const url = isNewEvent ? `/api/admin/character/${characterId}/event` : `/api/admin/character/${characterId}/event/${eventData.id}`; const method = isNewEvent ? 'POST' : 'PUT'; // 发送请求 fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(eventData) }) .then(response => response.json()) .then(data => { if (data.success) { // 重新加载数据 loadCharacters(); // 关闭模态框 closeModal(eventModal); // 如果当前有打开的角色详情,更新详情 if (currentCharacter && currentCharacter.id === characterId) { fetch(`/api/admin/character/${characterId}`) .then(response => response.json()) .then(data => { if (data.character) { currentCharacter = data.character; setTimeout(() => { openCharacterDetail(currentCharacter); }, 300); } }); } } else { alert('保存失败: ' + (data.error || '未知错误')); } }) .catch(error => { console.error('保存事件失败:', error); alert('保存失败,请稍后重试'); }); } // 删除角色 function deleteCharacter(characterId) { fetch(`/api/admin/character/${characterId}`, { method: 'DELETE' }) .then(response => response.json()) .then(data => { if (data.success) { // 更新角色列表 loadCharacters(); // 关闭所有模态框 closeModal(characterDetailModal); closeModal(confirmModal); // 清空当前角色 currentCharacter = null; } else { alert('删除失败: ' + (data.error || '未知错误')); } }) .catch(error => { console.error('删除角色失败:', error); alert('删除失败,请稍后重试'); }); } // 删除事件 function deleteEvent(characterId, eventId) { fetch(`/api/admin/character/${characterId}/event/${eventId}`, { method: 'DELETE' }) .then(response => response.json()) .then(data => { if (data.success) { // 如果当前有打开的角色详情,更新详情 if (currentCharacter && currentCharacter.id === characterId) { fetch(`/api/admin/character/${characterId}`) .then(response => response.json()) .then(data => { if (data.character) { // 更新当前角色数据 currentCharacter = data.character; // 重新渲染事件列表 renderEvents(currentCharacter); } }); } // 更新角色列表 loadCharacters(); // 关闭确认框 closeModal(confirmModal); } else { alert('删除失败: ' + (data.error || '未知错误')); } }) .catch(error => { console.error('删除事件失败:', error); alert('删除失败,请稍后重试'); }); } // 生成UUID function generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } });