/** * 资源管理相关功能 */ 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 = `${resource.name}`; } 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); } } }