/**
* 资源分类管理相关功能
*/
let categories = []; // 所有分类
let parentCategories = []; // 父分类选项
let categoryCurrentPage = 1;
let categoryPageSize = 10;
let categoryTotalPages = 0;
let categoryTotalCount = 0;
document.addEventListener('DOMContentLoaded', function () {
// 加载分类列表
loadCategories();
// 分类级别变更事件
document.getElementById('category-level').addEventListener('change', function () {
const level = parseInt(this.value);
const parentCategoryGroup = document.getElementById('parent-category-group');
const versionHelpText = document.getElementById('version-help-text');
if (level > 1) {
// 二级或三级分类,显示父分类选择框
parentCategoryGroup.style.display = 'block';
// 加载父分类选项
loadParentCategoryOptions(level);
if (level === 2) {
// 二级分类时禁用版本选择并显示父分类版本
setVersionCheckboxDisabled(true);
versionHelpText.textContent = '二级分类自动继承父分类的版本';
// 如果已经选择了父分类,立即显示父分类的版本
const parentId = document.getElementById('parent-category').value;
if (parentId) {
setVersionFromParent(parentId);
}
} else {
// 三级分类时启用版本选择
setVersionCheckboxDisabled(false);
versionHelpText.textContent = '选择要关联的版本';
}
} else {
// 一级分类,隐藏父分类选择框
parentCategoryGroup.style.display = 'none';
setVersionCheckboxDisabled(false);
versionHelpText.textContent = '选择要关联的版本';
}
});
// 保存分类按钮点击事件
document.getElementById('btn-save-category').addEventListener('click', saveCategory);
// 父分类变更事件
document.getElementById('parent-category').addEventListener('change', function() {
const level = parseInt(document.getElementById('category-level').value);
if (level === 2) {
// 二级分类时,根据父分类自动设置版本
const parentId = this.value;
if (parentId) {
setVersionFromParent(parentId);
}
}
});
});
/**
* 根据父分类设置版本(支持多版本)
* @param {number} parentId - 父分类ID
*/
async function setVersionFromParent(parentId) {
try {
const params = {
"token": localStorage.getItem('token')
};
// 获取父分类详情
const parentCategory = await Api.get(`/api/categories/${parentId}`, params);
// 先清空所有checkbox
const boxes = document.querySelectorAll('#category-versions-checkbox-group input[type=checkbox]');
boxes.forEach(cb => cb.checked = false);
// 设置父分类的版本
if (parentCategory && parentCategory.versionIds && Array.isArray(parentCategory.versionIds)) {
parentCategory.versionIds.forEach(id => {
const cb = document.getElementById('version-checkbox-' + id);
if (cb) cb.checked = true;
});
}
} catch (error) {
console.error('获取父分类版本失败:', error);
// 出错时清空所有checkbox
const boxes = document.querySelectorAll('#category-versions-checkbox-group input[type=checkbox]');
boxes.forEach(cb => cb.checked = false);
}
}
/**
* 加载分类列表
*/
async function loadCategories() {
try {
const params = {
"token": localStorage.getItem('token'),
page: categoryCurrentPage,
pageSize: categoryPageSize
};
const response = await Api.get('/api/categories', params);
categories = Array.isArray(response.items) ? response.items : (Array.isArray(response) ? response : []);
categoryTotalCount = response.total || categories.length;
categoryTotalPages = Math.ceil(categoryTotalCount / categoryPageSize);
renderCategoryList(categories);
renderCategoryPagination();
} catch (error) {
showToast(error.message, 'danger');
}
}
/**
* 渲染分类列表
* @param {Array} categories - 分类列表
*/
function renderCategoryList(categories) {
const categoryList = document.getElementById('category-list');
categoryList.innerHTML = '';
// 扁平化分类树
const flatCategories = flattenCategories(categories);
if (flatCategories.length === 0) {
categoryList.innerHTML = '
| 暂无数据 |
';
// 更新总数
const totalCountEl = document.getElementById('category-total-count');
if (totalCountEl) totalCountEl.textContent = categoryTotalCount;
return;
}
// 渲染分类列表
flatCategories.forEach(category => {
const tr = document.createElement('tr');
// 根据级别添加缩进
const namePrefix = ' '.repeat((category.level - 1) * 4);
const levelName = ['一级', '二级', '三级'][category.level - 1] || '';
// 显示所有版本名称
const versionInfo = (category.versionNames && category.versionNames.length > 0)
? category.versionNames.join(', ')
: '-';
tr.innerHTML = `
${category.id} |
${namePrefix}${category.name} |
${levelName}分类 |
${category.parentName || '-'} |
${versionInfo} |
${category.description || '-'} |
${formatDateTime(category.createTime)} |
|
`;
categoryList.appendChild(tr);
});
// 更新总数
const totalCountEl = document.getElementById('category-total-count');
if (totalCountEl) totalCountEl.textContent = categoryTotalCount;
}
/**
* 扁平化分类树,并添加父分类名称
* @param {Array} categories - 分类树
* @param {Object} parent - 父分类
* @returns {Array} - 扁平化的分类列表
*/
function flattenCategories(categories, parent = null) {
let result = [];
categories.forEach(category => {
// 添加父分类名称
const categoryWithParent = {
...category, parentName: parent ? parent.name : null
};
result.push(categoryWithParent);
// 递归处理子分类
if (category.children && category.children.length > 0) {
result = result.concat(flattenCategories(category.children, category));
}
});
return result;
}
/**
* 加载父分类选项
* @param {number} level - 当前分类级别
*/
function loadParentCategoryOptions(level) {
const parentCategorySelect = document.getElementById('parent-category');
parentCategorySelect.innerHTML = '';
// 获取可选的父分类(级别小于当前级别的分类)
parentCategories = [];
// 扁平化分类树
const flatCategories = flattenCategories(categories);
// 筛选可作为父分类的分类
parentCategories = flatCategories.filter(category => category.level < level);
// 渲染父分类选项
parentCategories.forEach(category => {
const option = document.createElement('option');
option.value = category.id;
// 根据级别添加缩进
const namePrefix = ' '.repeat(category.level - 1);
option.textContent = `${namePrefix}${category.name}`;
parentCategorySelect.appendChild(option);
});
}
/**
* 加载版本选项(渲染checkbox组)
*/
async function loadVersionOptions() {
try {
const params = {
"token": localStorage.getItem('token')
};
const response = await Api.get('/api/versions', params);
const group = document.getElementById('category-versions-checkbox-group');
group.innerHTML = '';
const versions = response.items || response;
versions.forEach(version => {
const div = document.createElement('div');
div.className = 'form-check form-check-inline';
div.innerHTML = `
`;
group.appendChild(div);
});
} catch (error) {
console.error('加载版本选项失败:', error);
}
}
/**
* 设置checkbox组禁用/启用
* @param {boolean} disabled - 是否禁用
*/
function setVersionCheckboxDisabled(disabled) {
const boxes = document.querySelectorAll('#category-versions-checkbox-group input[type=checkbox]');
boxes.forEach(cb => cb.disabled = disabled);
}
/**
* 打开新增分类模态框
*/
function openAddCategoryModal() {
// 重置表单
document.getElementById('category-form').reset();
document.getElementById('category-id').value = '';
document.getElementById('parent-category-group').style.display = 'none';
// 重置版本选择状态
setVersionCheckboxDisabled(false);
document.getElementById('version-help-text').textContent = '选择要关联的版本';
// 设置模态框标题
document.getElementById('categoryModalLabel').textContent = '新增分类';
// 加载版本选项
loadVersionOptions();
// 显示模态框
const categoryModal = new bootstrap.Modal(document.getElementById('categoryModal'));
categoryModal.show();
}
/**
* 编辑分类
* @param {number} id - 分类ID
*/
async function editCategory(id) {
try {
const params = {
"token": localStorage.getItem('token')
};
// 获取分类详情
const category = await Api.get(`/api/categories/${id}`, params);
// 填充表单
document.getElementById('category-id').value = category.id;
document.getElementById('category-name').value = category.name;
document.getElementById('category-level').value = category.level;
document.getElementById('category-description').value = category.description || '';
// 处理父分类
if (category.level > 1) {
document.getElementById('parent-category-group').style.display = 'block';
loadParentCategoryOptions(category.level);
if (category.parentId) {
document.getElementById('parent-category').value = category.parentId;
}
// 二级分类时显示父分类版本并禁用修改
if (category.level === 2) {
document.getElementById('version-help-text').textContent = '二级分类自动继承父分类的版本';
} else {
document.getElementById('version-help-text').textContent = '选择要关联的版本';
}
} else {
document.getElementById('parent-category-group').style.display = 'none';
document.getElementById('version-help-text').textContent = '选择要关联的版本';
}
// 先加载版本选项
await loadVersionOptions();
// 然后处理版本选择
if (category.level === 2) {
// 二级分类:显示父分类版本并禁用修改
if (category.parentId) {
await setVersionFromParent(category.parentId);
}
setVersionCheckboxDisabled(true);
} else {
// 非二级分类:显示当前版本
if (category.versionIds && Array.isArray(category.versionIds)) {
category.versionIds.forEach(id => {
const cb = document.getElementById('version-checkbox-' + id);
if (cb) cb.checked = true;
});
}
setVersionCheckboxDisabled(false);
}
// 设置模态框标题
document.getElementById('categoryModalLabel').textContent = '编辑分类';
// 显示模态框
const categoryModal = new bootstrap.Modal(document.getElementById('categoryModal'));
categoryModal.show();
} catch (error) {
showToast(error.message, 'danger');
}
}
async function debugResponse(response) {
try {
if (response.ok) {
console.log('debugResponse:', response.json());
} else {
const error = await response.text();
console.log('debugResponse:', error);
}
} catch (e) {
console.log('debugResponse:', e.message);
}
}
/**
* 保存分类
*/
async function saveCategory() {
try {
// 获取表单数据
const categoryData = {
name: document.getElementById('category-name').value.trim(),
level: parseInt(document.getElementById('category-level').value),
description: document.getElementById('category-description').value.trim(),
versionId: null // 新增字段
};
// 获取父分类ID
const parentCategory = document.getElementById('parent-category');
if (parentCategory.style.display !== 'none' && parentCategory.value) {
categoryData.parentId = parseInt(parentCategory.value);
}
// 获取多选版本ID(checkbox)
let selectedVersionIds = Array.from(document.querySelectorAll('#category-versions-checkbox-group input[type=checkbox]:checked')).map(cb => parseInt(cb.value));
// 二级分类时,如果禁用,则继承父级
if (categoryData.level === 2) {
const parentId = categoryData.parentId;
if (parentId) {
try {
const parentParams = {
"token": localStorage.getItem('token')
};
const parentCategory = await Api.get(`/api/categories/${parentId}`, parentParams);
if (parentCategory && parentCategory.versionIds && Array.isArray(parentCategory.versionIds)) {
selectedVersionIds = parentCategory.versionIds;
} else {
selectedVersionIds = [];
}
} catch (error) {
selectedVersionIds = [];
}
} else {
selectedVersionIds = [];
}
}
// 验证表单
if (!categoryData.name) {
showToast('请输入分类名称', 'danger');
return;
}
// 检查同级分类名称是否重复(排除当前编辑的分类)
const currentId = document.getElementById('category-id').value;
const sameLevelCategories = categories.filter(c => c.level === categoryData.level);
// const isNameDuplicate = sameLevelCategories.some(c =>
// c.name === categoryData.name &&
// c.id !== parseInt(currentId)
// );
// if (isNameDuplicate) {
// showToast('同级分类名称不能重复', 'danger');
// return;
// }
// 检查二级分类名称不能与一级分类重名
// if (categoryData.level === 2) {
// const isDuplicateWithLevel1 = categories.some(c => c.level === 1 && c.name === categoryData.name);
// if (isDuplicateWithLevel1) {
// showToast('二级分类名称不能与一级分类重名', 'danger');
// return;
// }
// }
// 构建请求数据
const data = {
name: categoryData.name,
level: categoryData.level,
description: categoryData.description || null,
versionIds: selectedVersionIds
};
// 如果是二级或三级分类,添加父分类ID
if (categoryData.level > 1) {
const parentId = categoryData.parentId;
if (!parentId) {
showToast('请选择父分类', 'danger');
return;
}
data.parentId = parentId;
}
// 发送请求
if (document.getElementById('category-id').value) {
// 更新分类
const response = await Api.put(`/api/categories/${document.getElementById('category-id').value}`, data);
debugResponse(response);
showToast('分类更新成功', 'success');
} else {
// 新增分类
const response = await Api.post('/api/categories', data);
debugResponse(response);
showToast('分类创建成功', 'success');
}
// 关闭模态框
const categoryModal = bootstrap.Modal.getInstance(document.getElementById('categoryModal'));
categoryModal.hide();
// 重新加载分类列表
loadCategories();
} catch (error) {
showToast(error.message, 'danger');
}
}
/**
* 删除分类
* @param {number} id - 分类ID
* @param {string} name - 分类名称
*/
function deleteCategory(id, name) {
// 设置确认删除模态框内容
document.getElementById('delete-type').textContent = `分类"${name}"`;
// 设置确认删除按钮点击事件
document.getElementById('btn-confirm-delete').onclick = async function () {
try {
// 发送删除请求
await Api.delete(`/api/categories/${id}`);
// 关闭确认删除模态框
const confirmDeleteModal = bootstrap.Modal.getInstance(document.getElementById('confirmDeleteModal'));
confirmDeleteModal.hide();
// 显示成功消息
showToast('分类删除成功', 'success');
// 重新加载分类列表
loadCategories();
} catch (error) {
showToast(error.message, 'danger');
}
};
// 显示确认删除模态框
const confirmDeleteModal = new bootstrap.Modal(document.getElementById('confirmDeleteModal'));
confirmDeleteModal.show();
}
/**
* 获取所有分类的扁平列表(用于资源管理中的分类选择)
* @returns {Array} - 分类列表
*/
function getAllCategories() {
return flattenCategories(categories);
}
function renderCategoryPagination() {
const pagination = document.getElementById('category-pagination');
if (!pagination) return;
pagination.innerHTML = '';
if (categoryTotalPages <= 1) return;
// 上一页
const prevLi = document.createElement('li');
prevLi.className = `page-item ${categoryCurrentPage === 1 ? 'disabled' : ''}`;
const prevLink = document.createElement('a');
prevLink.className = 'page-link';
prevLink.href = '#';
prevLink.setAttribute('aria-label', '上一页');
prevLink.innerHTML = '«';
if (categoryCurrentPage > 1) {
prevLink.addEventListener('click', function (event) {
event.preventDefault();
categoryCurrentPage--;
loadCategories();
});
}
prevLi.appendChild(prevLink);
pagination.appendChild(prevLi);
// 页码
const startPage = Math.max(1, categoryCurrentPage - 2);
const endPage = Math.min(categoryTotalPages, startPage + 4);
for (let i = startPage; i <= endPage; i++) {
const pageLi = document.createElement('li');
pageLi.className = `page-item ${i === categoryCurrentPage ? 'active' : ''}`;
const pageLink = document.createElement('a');
pageLink.className = 'page-link';
pageLink.href = '#';
pageLink.textContent = i;
if (i !== categoryCurrentPage) {
pageLink.addEventListener('click', function (event) {
event.preventDefault();
categoryCurrentPage = i;
loadCategories();
});
}
pageLi.appendChild(pageLink);
pagination.appendChild(pageLi);
}
// 下一页
const nextLi = document.createElement('li');
nextLi.className = `page-item ${categoryCurrentPage === categoryTotalPages ? 'disabled' : ''}`;
const nextLink = document.createElement('a');
nextLink.className = 'page-link';
nextLink.href = '#';
nextLink.setAttribute('aria-label', '下一页');
nextLink.innerHTML = '»';
if (categoryCurrentPage < categoryTotalPages) {
nextLink.addEventListener('click', function (event) {
event.preventDefault();
categoryCurrentPage++;
loadCategories();
});
}
nextLi.appendChild(nextLink);
pagination.appendChild(nextLi);
}