/**
* 资源管理相关功能
*/
let currentPage = 1;
let pageSize = 10;
let totalPages = 0;
let totalCount = 0;
let currentCategoryId = null;
let currentKeyword = null;
let resourceCurrentPage = 1;
let resourcePageSize = 10;
let resourceTotalPages = 0;
let resourceTotalCount = 0;
// 检查尺寸范围
const minWidth = 252;
const minHeight = 212;
const maxWidth = 1920;
const maxHeight = 1080;
document.addEventListener('DOMContentLoaded', function () {
// 加载资源列表
loadResources();
// 筛选表单提交事件
document.getElementById('resource-filter-form').addEventListener('submit', function (event) {
event.preventDefault();
// 获取筛选条件
currentCategoryId = document.getElementById('filter-category').value || null;
currentKeyword = document.getElementById('search-keyword').value.trim() || null;
currentPage = 1;
// 加载资源列表
loadResources();
});
// 保存资源按钮点击事件
document.getElementById('btn-save-resource').addEventListener('click', addResource);
// 保存资源按钮点击事件
document.getElementById('btn-save-resource-edit').addEventListener('click', saveResource);
// 添加资源条目按钮
document.getElementById('btn-add-resource-item').addEventListener('click', function () {
addResourceItem();
});
// 删除资源条目按钮(使用事件委托,因为删除按钮是动态添加的)
document.getElementById('resource-items-container').addEventListener('click', function (event) {
if (event.target.classList.contains('btn-delete-item') ||
event.target.parentElement.classList.contains('btn-delete-item')) {
const button = event.target.classList.contains('btn-delete-item') ?
event.target : event.target.parentElement;
const item = button.closest('.resource-item');
item.remove();
}
});
});
/**
* 加载资源列表
*/
async function loadResources() {
try {
// 构建查询参数
const params = {
page: resourceCurrentPage,
pageSize: resourcePageSize,
"token": localStorage.getItem('token')
};
if (currentCategoryId) {
params.categoryId = currentCategoryId;
}
if (currentKeyword) {
params.keyword = currentKeyword;
}
// 发送请求
const response = await Api.get('/api/resources', params);
// 更新分页信息
resourceTotalCount = response.total;
resourceTotalPages = Math.ceil(resourceTotalCount / resourcePageSize);
// 更新总数显示
const totalCountEl = document.getElementById('resource-total-count');
if (totalCountEl) totalCountEl.textContent = resourceTotalCount;
// 渲染资源列表
renderResourceList(response.items);
// 渲染分页
renderResourcePagination();
// 加载分类选项(用于筛选和上传)
loadCategoryOptions();
} catch (error) {
showToast(error.message, 'danger');
}
}
/**
* 渲染资源列表
* @param {Array} resources - 资源列表
*/
function renderResourceList(resources) {
const resourceList = document.getElementById('resource-list');
resourceList.innerHTML = '';
if (!resources || resources.length === 0) {
resourceList.innerHTML = '
| 暂无数据 |
';
// 更新总数
const totalCountEl = document.getElementById('resource-total-count');
if (totalCountEl) totalCountEl.textContent = resourceTotalCount;
return;
}
// 渲染资源列表
resources.forEach(resource => {
const tr = document.createElement('tr');
// 构建缩略图HTML
let thumbnailHtml = '';
if (resource.thumbnailPath) {
thumbnailHtml = `
`;
} else {
thumbnailHtml = `
`;
}
tr.innerHTML = `
${resource.id} |
${thumbnailHtml} |
${resource.name} |
${resource.categoryName} |
${formatFileSize(resource.fileSize)} |
${formatDateTime(resource.createTime)} |
|
`;
resourceList.appendChild(tr);
});
// 更新总数
const totalCountEl = document.getElementById('resource-total-count');
if (totalCountEl) totalCountEl.textContent = resourceTotalCount;
}
/**
* 渲染分页
*/
function renderResourcePagination() {
const pagination = document.getElementById('resource-pagination');
if (!pagination) return;
pagination.innerHTML = '';
if (resourceTotalPages <= 1) {
return;
}
// 上一页
const prevLi = document.createElement('li');
prevLi.className = `page-item ${resourceCurrentPage === 1 ? 'disabled' : ''}`;
const prevLink = document.createElement('a');
prevLink.className = 'page-link';
prevLink.href = '#';
prevLink.setAttribute('aria-label', '上一页');
prevLink.innerHTML = '«';
if (resourceCurrentPage > 1) {
prevLink.addEventListener('click', function (event) {
event.preventDefault();
resourceCurrentPage--;
loadResources();
});
}
prevLi.appendChild(prevLink);
pagination.appendChild(prevLi);
// 页码
const startPage = Math.max(1, resourceCurrentPage - 2);
const endPage = Math.min(resourceTotalPages, startPage + 4);
for (let i = startPage; i <= endPage; i++) {
const pageLi = document.createElement('li');
pageLi.className = `page-item ${i === resourceCurrentPage ? 'active' : ''}`;
const pageLink = document.createElement('a');
pageLink.className = 'page-link';
pageLink.href = '#';
pageLink.textContent = i;
if (i !== resourceCurrentPage) {
pageLink.addEventListener('click', function (event) {
event.preventDefault();
resourceCurrentPage = i;
loadResources();
});
}
pageLi.appendChild(pageLink);
pagination.appendChild(pageLi);
}
// 下一页
const nextLi = document.createElement('li');
nextLi.className = `page-item ${resourceCurrentPage === resourceTotalPages ? 'disabled' : ''}`;
const nextLink = document.createElement('a');
nextLink.className = 'page-link';
nextLink.href = '#';
nextLink.setAttribute('aria-label', '下一页');
nextLink.innerHTML = '»';
if (resourceCurrentPage < resourceTotalPages) {
nextLink.addEventListener('click', function (event) {
event.preventDefault();
resourceCurrentPage++;
loadResources();
});
}
nextLi.appendChild(nextLink);
pagination.appendChild(nextLi);
}
/**
* 加载分类选项
*/
function loadCategoryOptions() {
try {
// 新增:未登录直接提示,不再请求
if (!isLoggedIn()) {
showLoginModal()
showToast('未登录,请先登录', 'danger');
return;
}
// 获取所有分类
const allCategories = getAllCategories() || [];
// 如果分类列表为空,尝试加载一次
if (allCategories.length === 0) {
console.log('分类列表为空,尝试加载...');
// 异步加载分类
loadCategories().then(() => {
// 加载完成后不再递归调用,直接提示
const loadedCategories = getAllCategories() || [];
if (loadedCategories.length === 0) {
showToast('分类列表为空,请检查登录状态或网络', 'danger');
} else {
// 渲染分类选项
loadCategoryOptions();
}
}).catch(error => {
console.error('加载分类失败:', error);
showToast('加载分类失败,请检查登录状态或网络', 'danger');
});
return;
}
// 渲染筛选条件中的分类选项
const filterCategorySelect = document.getElementById('filter-category');
if (filterCategorySelect) {
filterCategorySelect.innerHTML = '';
}
// 渲染上传表单中的分类选项
const resourceCategorySelect = document.getElementById('resource-category');
if (resourceCategorySelect) {
resourceCategorySelect.innerHTML = '';
}
// 渲染上传表单中的分类选项(编辑模式)
const resourceCategorySelectEdit = document.getElementById('resource-category-edit');
if (resourceCategorySelectEdit) {
resourceCategorySelectEdit.innerHTML = '';
}
// 渲染分类选项
allCategories.forEach(category => {
// 筛选条件中的分类选项
if (filterCategorySelect) {
const filterOption = document.createElement('option');
filterOption.value = category.id;
// 根据级别添加缩进
const namePrefix = ' '.repeat(category.level - 1);
filterOption.textContent = `${namePrefix}${category.name}`;
if (category.id == currentCategoryId) {
filterOption.selected = true;
}
filterCategorySelect.appendChild(filterOption);
}
// 上传表单中的分类选项
if (resourceCategorySelect) {
const resourceOption = document.createElement('option');
resourceOption.value = category.id;
// 根据级别添加缩进
const namePrefix = ' '.repeat(category.level - 1);
resourceOption.textContent = `${namePrefix}${category.name}`;
resourceCategorySelect.appendChild(resourceOption);
}
// 编辑表单中的分类选项
if (resourceCategorySelectEdit) {
const editOption = document.createElement('option');
editOption.value = category.id;
// 根据级别添加缩进
const namePrefix = ' '.repeat(category.level - 1);
editOption.textContent = `${namePrefix}${category.name}`;
resourceCategorySelectEdit.appendChild(editOption);
}
});
console.log(`已加载 ${allCategories.length} 个分类选项`);
} catch (error) {
console.error('加载分类选项失败:', error);
}
}
// 判断是否已登录(仅本地token判断,token失效由api.js全局处理401/403)
function isLoggedIn() {
return !!localStorage.getItem('token');
}
/**
* 打开上传资源模态框
*/
function openAddResourceModal() {
// 重置表单
document.getElementById('resource-form').reset();
document.getElementById('resource-id').value = '';
// 清空资源条目容器,只保留第一个条目
const container = document.getElementById('resource-items-container');
const firstItem = container.querySelector('.resource-item');
container.innerHTML = '';
container.appendChild(firstItem);
// 清空第一个条目表单
const firstItemInputs = firstItem.querySelectorAll('input, textarea');
firstItemInputs.forEach(input => {
input.value = '';
});
// 更新模态框标题
document.getElementById('resourceModalLabel').textContent = '上传资源';
// 确保分类选项已加载
loadCategoryOptions();
// 显示模态框
const resourceModal = new bootstrap.Modal(document.getElementById('resourceModal'));
resourceModal.show();
}
/**
* 编辑资源
* @param {number} id - 资源ID
*/
async function editResource(id) {
try {
// 重置表单
document.getElementById('resource-form-edit').reset();
document.getElementById('resource-id-edit').value = '';
const params = {
"token": localStorage.getItem('token')
};
// 获取资源详情
const resource = await Api.get(`/api/resources/${id}`, params);
// 填充表单
document.getElementById('resource-id-edit').value = resource.id;
document.getElementById('resource-name').value = resource.name;
document.getElementById('resource-category-edit').value = resource.categoryId;
document.getElementById('resource-description').value = resource.description || '';
document.getElementById('resource-exepath').value = resource.exePath || '';
document.getElementById('resource-name-type').value = resource.inputType || '';
// 显示文件上传和缩略图字段(编辑时允许更改文件)
document.getElementById('resource-file').parentElement.style.display = 'block';
document.getElementById('resource-thumbnail').parentElement.style.display = 'block';
// 设置模态框标题
document.getElementById('resourceModalLabelEdit').textContent = '编辑资源';
// 显示模态框
const resourceModal = new bootstrap.Modal(document.getElementById('resourceModalEdit'));
resourceModal.show();
} catch (error) {
showToast(error.message, 'danger');
}
}
// 创建简单的loading框
const loadingModal = document.createElement('div');
loadingModal.className = 'modal fade';
loadingModal.id = 'uploadLoadingModal';
loadingModal.setAttribute('data-bs-backdrop', 'static');
loadingModal.setAttribute('data-bs-keyboard', 'false');
loadingModal.innerHTML = `
`;
document.body.appendChild(loadingModal);
// 显示loading框
const bsLoadingModal = new bootstrap.Modal(loadingModal);
/**
* 添加新的资源条目
*/
function addResourceItem() {
const template = document.getElementById('resource-item-template');
const container = document.getElementById('resource-items-container');
// 克隆模板内容
const clone = document.importNode(template.content, true);
// 添加到容器
container.appendChild(clone);
}
/**
* 保存资源
*/
async function addResource() {
try {
// 添加分类ID
const categoryId = document.getElementById('resource-category').value;
const category = await Api.get(`/api/categories/${categoryId}`);
if (category.level === 1) {
showToast('一级分类不支持资源上传,请选择二级', 'danger');
return;
}
// 获取所有资源条目
const resourceItems = document.querySelectorAll('.resource-item');
// 检查表单有效性
let isValid = true;
resourceItems.forEach(item => {
const requiredInputs = item.querySelectorAll('[required]');
requiredInputs.forEach(input => {
if (!input.value) {
isValid = false;
input.classList.add('is-invalid');
} else {
input.classList.remove('is-invalid');
}
});
});
if (!isValid) {
hideLoading();
showToast('请填写所有必填字段', 'danger');
return;
}
// 为每个资源条目创建一个FormData对象
const resources = [];
for (let i = 0; i < resourceItems.length; i++) {
const item = resourceItems[i];
const itemData = new FormData();
// 添加基本字段
itemData.append('categoryId', categoryId);
itemData.append('token', localStorage.getItem('token'));
// 添加资源名称
const nameInput = item.querySelector('.resource-name');
itemData.append('name', nameInput.value);
// 添加输入类型
const inputTypeInput = item.querySelector('.resource-inputtype');
if (inputTypeInput.value) {
itemData.append('inputType', inputTypeInput.value);
}
// 添加文件
const fileInput = item.querySelector('.resource-file');
if (fileInput.files.length > 0) {
itemData.append('file', fileInput.files[0]);
}
// 添加缩略图
const thumbnailInput = item.querySelector('.resource-thumbnail');
if (thumbnailInput.files.length > 0) {
const thumbnail = thumbnailInput.files[0];
// 检查图片分辨率
try {
await new Promise((resolve, reject) => {
// 检查文件类型
if (!thumbnail.type.includes('jpeg')) {
reject('缩略图必须是JPG格式');
return;
}
const img = new Image();
img.onload = function() {
const width = this.width;
const height = this.height;
if (width < minWidth || width > maxWidth ||
height < minHeight || height > maxHeight) {
reject(`缩略图尺寸必须在${minWidth}x${minHeight}到${maxWidth}x${maxHeight}之间`);
return;
}
itemData.append('thumbnail', thumbnail);
resolve();
};
img.onerror = function() {
reject('图片加载失败');
};
img.src = URL.createObjectURL(thumbnail);
});
} catch (error) {
showToast(error, 'danger');
return;
}
}
// 添加描述
const descriptionInput = item.querySelector('.resource-description');
if (descriptionInput.value) {
itemData.append('description', descriptionInput.value);
}
// 添加可执行文件路径
const exePathInput = item.querySelector('.resource-exepath');
if (exePathInput.value) {
itemData.append('exePath', exePathInput.value);
}
resources.push(itemData);
}
// 显示加载提示
showLoading();
// 逐个上传资源
try {
for (let i = 0; i < resources.length; i++) {
try {
const response = await Api.upload('/api/resources', resources[i]);
debugResponse(response);
} catch (error) {
showToast(`第 ${i + 1} 个资源上传失败:${error.message}`, 'danger');
throw error; // 抛出错误以中断整个上传过程
}
}
showToast('所有资源上传成功', 'success');
// 关闭模态框
const resourceModal = bootstrap.Modal.getInstance(document.getElementById('resourceModal'));
resourceModal.hide();
// 刷新资源列表
loadResources();
showToast('资源上传成功', 'success');
} catch (error) {
showToast(error.message, 'warning');
// 可以在这里添加其他错误处理逻辑
}
} catch (error) {
console.error('保存资源失败:', error);
showToast(error.message, 'danger');
} finally {
hideLoading();
}
}
/**
* 保存资源
*/
async function saveResource() {
try {
const resourceName = document.getElementById('resource-name').value;
// 验证表单
if (!resourceName) {
showToast('请输入资源名称', 'danger');
return;
}
// 检查分类级别
const categoryId = document.getElementById('resource-category-edit').value;
const category = await Api.get(`/api/categories/${categoryId}`);
if (category.level === 1) {
showToast('一级分类不支持资源上传,请选择二级', 'danger');
return;
}
// 编辑资源
const formData = new FormData();
formData.append('name', resourceName);
formData.append('categoryId', document.getElementById('resource-category-edit').value);
formData.append('description', document.getElementById('resource-description').value || '');
formData.append('exePath', document.getElementById('resource-exepath').value || '');
formData.append('inputType', document.getElementById('resource-name-type').value || '');
const id = document.getElementById('resource-id-edit').value;
// 添加缩略图
const thumbnailInput = document.getElementById('resource-thumbnail');
if (thumbnailInput.files.length > 0) {
const thumbnail = thumbnailInput.files[0];
// 检查图片分辨率
try {
await new Promise((resolve, reject) => {
// 检查文件类型
if (!thumbnail.type.includes('jpeg')) {
reject('缩略图必须是JPG格式');
return;
}
const img = new Image();
img.onload = function() {
const width = this.width;
const height = this.height;
if (width < minWidth || width > maxWidth ||
height < minHeight || height > maxHeight) {
reject(`缩略图尺寸必须在${minWidth}x${minHeight}到${maxWidth}x${maxHeight}之间`);
return;
}
formData.append('thumbnail', thumbnail);
resolve();
};
img.onerror = function() {
reject('图片加载失败');
};
img.src = URL.createObjectURL(thumbnail);
});
} catch (error) {
showToast(error, 'danger');
return;
}
}
// 添加文件
const fileInput = document.getElementById('resource-file');
if (fileInput.files.length > 0) {
formData.append('file', fileInput.files[0]);
}
// 显示加载提示
showLoading();
// 发送请求
const response = await Api.upload(`/api/resources/${id}`, formData);
debugResponse(response);
// 显示成功消息
showToast(response.message, 'success');
// 关闭模态框
const resourceModal = bootstrap.Modal.getInstance(document.getElementById('resourceModalEdit'));
resourceModal.hide();
// 重新加载资源列表
loadResources();
} catch (error) {
showToast(error.message, 'danger');
} finally {
hideLoading();
}
}
/**
* 查看资源详情
* @param {number} id - 资源ID
*/
async function viewResource(id) {
try {
const params = {
"token": localStorage.getItem('token')
};
// 获取资源详情
const resource = await Api.get(`/api/resources/${id}`, params);
// 填充详情
document.getElementById('detail-name').textContent = resource.name;
document.getElementById('detail-category').textContent = resource.categoryName;
document.getElementById('detail-size').textContent = formatFileSize(resource.fileSize);
document.getElementById('detail-type').textContent = resource.fileType || '-';
document.getElementById('detail-uploader').textContent = resource.uploaderName || '-';
document.getElementById('detail-time').textContent = formatDateTime(resource.createTime);
document.getElementById('detail-description').textContent = resource.description || '-';
// 设置下载链接
document.getElementById('detail-download').href = resource.filePath;
// 渲染预览
const previewContainer = document.getElementById('detail-preview');
previewContainer.innerHTML = '';
try {
// 图片预览
const img = document.createElement('img');
img.src = resource.thumbnailPath;
img.alt = resource.name;
img.className = 'img-fluid preview-thumbnail';
previewContainer.appendChild(img);
} catch (error) {
// 非图片文件,显示文件图标
previewContainer.innerHTML = `
`;
}
// 显示模态框
const resourceDetailModal = new bootstrap.Modal(document.getElementById('resourceDetailModal'));
resourceDetailModal.show();
} catch (error) {
showToast(error.message, 'danger');
}
}
/**
* 删除资源
* @param {number} id - 资源ID
* @param {string} name - 资源名称
*/
function deleteResource(id, name) {
// 设置确认删除模态框内容
document.getElementById('delete-type').textContent = `资源"${name}"`;
// 设置确认删除按钮点击事件
document.getElementById('btn-confirm-delete').onclick = async function () {
try {
// 发送删除请求
await Api.delete(`/api/resources/${id}`);
// 关闭确认删除模态框
const confirmDeleteModal = bootstrap.Modal.getInstance(document.getElementById('confirmDeleteModal'));
confirmDeleteModal.hide();
// 显示成功消息
showToast('资源删除成功', 'success');
// 重新加载资源列表
loadResources();
} catch (error) {
showToast(error.message, 'danger');
}
};
// 显示确认删除模态框
const confirmDeleteModal = new bootstrap.Modal(document.getElementById('confirmDeleteModal'));
confirmDeleteModal.show();
}
/**
* 显示加载提示
*/
function showLoading() {
const loadingModal = document.getElementById('loadingModal');
if (!loadingModal) {
// 创建加载提示模态框
const modal = document.createElement('div');
modal.className = 'modal fade';
modal.id = 'loadingModal';
modal.setAttribute('data-bs-backdrop', 'static');
modal.setAttribute('data-bs-keyboard', 'false');
modal.setAttribute('tabindex', '-1');
modal.setAttribute('aria-hidden', 'true');
const modalDialog = document.createElement('div');
modalDialog.className = 'modal-dialog modal-dialog-centered';
const modalContent = document.createElement('div');
modalContent.className = 'modal-content';
const modalBody = document.createElement('div');
modalBody.className = 'modal-body text-center';
const spinner = document.createElement('div');
spinner.className = 'spinner-border text-primary';
spinner.setAttribute('role', 'status');
const spinnerText = document.createElement('span');
spinnerText.className = 'visually-hidden';
spinnerText.textContent = '加载中...';
const loadingText = document.createElement('p');
loadingText.className = 'mt-2';
loadingText.textContent = '处理中,请稍候...';
spinner.appendChild(spinnerText);
modalBody.appendChild(spinner);
modalBody.appendChild(loadingText);
modalContent.appendChild(modalBody);
modalDialog.appendChild(modalContent);
modal.appendChild(modalDialog);
document.body.appendChild(modal);
const bsModal = new bootstrap.Modal(modal);
bsModal.show();
} else {
const bsModal = new bootstrap.Modal(loadingModal);
bsModal.show();
}
}
/**
* 隐藏加载提示
*/
function hideLoading() {
const loadingModal = document.getElementById('loadingModal');
if (loadingModal) {
const bsModal = bootstrap.Modal.getInstance(loadingModal);
if (bsModal) {
setTimeout(() => {
bsModal.hide();
}, 500);
}
}
}