/**
* 种子问题管理模块 JavaScript
* 提供所有种子问题的查看和导出功能(管理员)
*/
(function() {
'use strict';
// 引用全局的翻译函数
// 翻译函数由 i18n-helper.js 提供
// 模块私有状态
let adminPaginator = null;
let container = null;
// 种子问题管理模块
const SeedQuestionManagement = {
init: function(containerElement) {
container = containerElement;
this.initPaginators();
this.initEventListeners();
// 等待 i18next 初始化完成后再加载数据
const loadData = () => {
this.loadAllQuestions();
};
// 检查 i18next 是否已可用(通过测试一个翻译键)
const checkI18nReady = () => {
if (window.i18next && window.i18next.t) {
try {
const test = window.i18next.t('common.loading');
// 如果翻译键正常工作(返回值不是键名本身),开始加载数据
if (test && test !== 'common.loading') {
loadData();
return true;
}
} catch (e) {
// i18next 还没准备好
}
}
return false;
};
// 立即检查一次
if (checkI18nReady()) {
return;
}
// 等待 i18next 初始化
const checkI18n = setInterval(() => {
if (checkI18nReady()) {
clearInterval(checkI18n);
}
}, 100);
// 超时保护(10秒后强制加载)
setTimeout(() => {
clearInterval(checkI18n);
console.warn('i18next initialization timeout or check failed, loading data anyway');
loadData();
}, 10000);
},
initPaginators: function() {
// 初始化管理员列表分页器
adminPaginator = createPaginator('admin', {
initialPage: 1,
initialPageSize: 20,
onPageChange: (page, pageSize) => {
this.loadAllQuestions();
},
onPageSizeChange: (pageSize) => {
this.loadAllQuestions();
}
});
},
initEventListeners: function() {
// 搜索
const adminSearchInput = container.querySelector('#adminSearchInput');
if (adminSearchInput) {
let searchTimeout;
adminSearchInput.addEventListener('input', (e) => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
this.loadAllQuestions();
}, 500);
});
}
// 管理类型和亚类
const manageTypesBtn = container.querySelector('#manageTypesBtn');
if (manageTypesBtn) {
manageTypesBtn.addEventListener('click', () => {
this.showManageTypesModal();
});
}
// 管理员刷新
const refreshAdminBtn = container.querySelector('#refreshAdminBtn');
if (refreshAdminBtn) {
refreshAdminBtn.addEventListener('click', () => {
this.loadAllQuestions();
});
}
// 管理员导出
const exportBtn = container.querySelector('#exportBtn');
if (exportBtn) {
exportBtn.addEventListener('click', () => {
this.exportQuestions();
});
}
},
loadAllQuestions: async function() {
if (!adminPaginator) return;
const tbody = container.querySelector('#adminTableBody');
if (!tbody) return;
try {
tbody.innerHTML = '
| 加载中... |
';
const skip = adminPaginator.getSkip();
const limit = adminPaginator.getLimit();
const search = container.querySelector('#adminSearchInput')?.value.trim() || null;
const params = new URLSearchParams({
skip: skip.toString(),
limit: limit.toString()
});
if (search) {
params.append('search', search);
}
const questions = await apiGet(`/seed-questions/admin/all?${params.toString()}`);
if (questions.length === 0) {
tbody.innerHTML = `📝 ${t('common.noData')} |
`;
const paginationContainer = container.querySelector('#adminPaginationContainer');
if (paginationContainer) paginationContainer.classList.add('hidden');
return;
}
tbody.innerHTML = questions.map(q => `
| ${q.id} |
${escapeHtml(q.question)} |
${escapeHtml(q.type)} |
${escapeHtml(q.subtype)} |
${escapeHtml(q.species_or_domain || '-')} |
${escapeHtml(q.model || '-')} |
${q.date ? this.formatDate(q.date) : '-'} |
${q.is_verified ? '✓' : '-'} |
${escapeHtml(q.creator_full_name || `用户ID:${q.creator_id}`)} |
${this.formatDateTime(q.created_at)} |
`).join('');
// 更新分页信息
const total = await this.getAllQuestionsCount(search);
adminPaginator.setTotalCount(total);
adminPaginator.render();
const paginationContainer = container.querySelector('#adminPaginationContainer');
if (paginationContainer) paginationContainer.classList.remove('hidden');
} catch (error) {
console.error('加载问题列表失败:', error);
tbody.innerHTML = '| 加载失败,请刷新重试 |
';
}
},
getAllQuestionsCount: async function(search) {
try {
const result = await apiGet(`/seed-questions/admin/all?skip=0&limit=1000${search ? '&search=' + encodeURIComponent(search) : ''}`);
return result.length;
} catch (error) {
return 0;
}
},
exportQuestions: async function() {
try {
const exportBtn = container.querySelector('#exportBtn');
const originalText = exportBtn ? exportBtn.textContent : '导出CSV';
if (exportBtn) {
exportBtn.disabled = true;
exportBtn.textContent = '导出中...';
}
const response = await fetch('/api/seed-questions/admin/export', {
method: 'GET',
headers: getAuthHeaders()
});
if (!response.ok) {
throw new Error('导出失败');
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `seed_questions_export_${new Date().toISOString().split('T')[0]}.csv`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
showSuccess('导出成功!');
} catch (error) {
console.error('导出失败:', error);
showError('导出失败,请重试');
} finally {
const exportBtn = container.querySelector('#exportBtn');
if (exportBtn) {
exportBtn.disabled = false;
exportBtn.textContent = '导出CSV';
}
}
},
formatDate: function(dateString) {
if (!dateString) return '-';
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN');
},
formatDateTime: function(dateString) {
if (!dateString) return '-';
const date = new Date(dateString);
return date.toLocaleString('zh-CN');
},
showManageTypesModal: async function() {
try {
// 加载所有类型和亚类
const types = await apiGet('/seed-questions/admin/types?limit=1000');
// 按类型分组
const grouped = {};
types.forEach(t => {
if (!grouped[t.type]) {
grouped[t.type] = [];
}
grouped[t.type].push(t);
});
// 构建内容
let content = `
类型和亚类列表
`;
// 按类型分组显示
const sortedTypes = Object.keys(grouped).sort();
if (sortedTypes.length === 0) {
content += '
暂无类型和亚类
';
} else {
sortedTypes.forEach(typeName => {
const subtypes = grouped[typeName].sort((a, b) => (a.order || 0) - (b.order || 0));
content += `
${escapeHtml(typeName)}
`;
subtypes.forEach(subtype => {
content += `
${escapeHtml(subtype.subtype)}
(ID: ${subtype.id}, 顺序: ${subtype.order || 0})
`;
});
content += `
`;
});
}
content += `
`;
openModal('管理类型和亚类', content, null, true);
// 添加按钮事件
const addTypeBtn = document.getElementById('addTypeBtn');
if (addTypeBtn) {
addTypeBtn.addEventListener('click', () => {
this.showAddTypeModal();
});
}
} catch (error) {
console.error('加载类型列表失败:', error);
showError('加载类型列表失败: ' + (error.message || '未知错误'));
}
},
showAddTypeModal: function() {
const title = '添加类型/亚类';
const content = `
`;
openModal(title, content, async () => {
await this.saveType();
});
},
saveType: async function() {
const typeName = document.getElementById('typeName').value.trim();
const subtypeName = document.getElementById('subtypeName').value.trim();
const order = parseInt(document.getElementById('typeOrder').value) || 0;
if (!typeName || !subtypeName) {
showError('类型名称和亚类名称不能为空');
return;
}
try {
await apiPost('/seed-questions/admin/types', {
type: typeName,
subtype: subtypeName,
order: order
});
showSuccess('类型/亚类添加成功');
closeModal();
// 重新打开管理模态框
this.showManageTypesModal();
} catch (error) {
console.error('添加类型失败:', error);
showError('添加类型失败: ' + (error.message || '未知错误'));
}
},
editType: async function(typeId) {
try {
const types = await apiGet('/seed-questions/admin/types?limit=1000');
const type = types.find(t => t.id === typeId);
if (!type) {
showError('类型不存在');
return;
}
const title = '编辑类型/亚类';
const content = `
`;
openModal(title, content, async () => {
await this.updateType(typeId);
});
} catch (error) {
console.error('加载类型信息失败:', error);
showError('加载类型信息失败: ' + (error.message || '未知错误'));
}
},
updateType: async function(typeId) {
const typeName = document.getElementById('editTypeName').value.trim();
const subtypeName = document.getElementById('editSubtypeName').value.trim();
const order = parseInt(document.getElementById('editTypeOrder').value) || 0;
if (!typeName || !subtypeName) {
showError('类型名称和亚类名称不能为空');
return;
}
try {
await apiPut(`/seed-questions/admin/types/${typeId}`, {
type: typeName,
subtype: subtypeName,
order: order
});
showSuccess('类型/亚类更新成功');
closeModal();
// 重新打开管理模态框
this.showManageTypesModal();
} catch (error) {
console.error('更新类型失败:', error);
showError('更新类型失败: ' + (error.message || '未知错误'));
}
},
deleteType: async function(typeId) {
if (!confirm('确定要删除这个类型/亚类吗?删除后无法恢复。')) {
return;
}
try {
await apiDelete(`/seed-questions/admin/types/${typeId}`);
showSuccess('类型/亚类删除成功');
// 重新打开管理模态框
this.showManageTypesModal();
} catch (error) {
console.error('删除类型失败:', error);
showError('删除类型失败: ' + (error.message || '未知错误'));
}
}
};
// 导出到全局
window.SeedQuestionManagement = SeedQuestionManagement;
})();