XNSim/XNSimHtml/components/todo-component.js

1064 lines
38 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import TodoService from './todo/todo-service.js';
import TodoModal from './todo/todo-modal.js';
import TodoTree from './todo/todo-tree.js';
import TodoList from './todo/todo-list.js';
class TodoComponent extends HTMLElement {
static {
// 添加静态初始化标志
this.isInitializing = false;
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.todos = [];
this.selectedProject = null;
this.selectedSubproject = null;
this.expandedProjects = new Set();
this.users = [];
this.currentUser = null;
this.editingTodo = null;
this.isInitialized = false;
this.showCompleted = false;
}
// 初始化组件
async initialize() {
if (TodoComponent.isInitializing) {
return;
}
// 先清除所有数据
this.clearData();
TodoComponent.isInitializing = true;
try {
// 先获取当前用户信息
await this.getCurrentUser();
// 然后获取其他数据
await Promise.all([
this.fetchTodos(),
this.fetchUsers()
]);
this.isInitialized = true;
this.render();
} catch (error) {
console.error('初始化组件时发生错误:', error);
this.showError('初始化失败,请刷新页面重试');
} finally {
TodoComponent.isInitializing = false;
}
}
async fetchTodos() {
try {
this.todos = await TodoService.fetchTodos();
} catch (error) {
console.error('获取待办事项时发生错误:', error);
this.showError('获取待办事项失败,请稍后重试');
}
}
async fetchUsers() {
try {
this.users = await TodoService.fetchUsers();
} catch (error) {
console.error('获取用户数据时发生错误:', error);
this.showError('获取用户数据失败,请稍后重试');
}
}
async getCurrentUser() {
try {
const response = await fetch('/api/check-auth', {
credentials: 'include' // 重要允许跨域请求携带cookie
});
const result = await response.json();
if (result.success) {
this.currentUser = result.user;
} else {
console.log('未找到登录用户信息');
this.currentUser = null;
}
} catch (error) {
console.error('获取当前用户信息时发生错误:', error);
this.showError('获取用户信息失败');
this.currentUser = null;
}
}
showError(message) {
// 首先移除之前的错误消息
const existingErrorMessage = this.shadowRoot.querySelector('.error-message');
if (existingErrorMessage) {
existingErrorMessage.remove();
}
// 创建错误消息元素
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.textContent = message;
// 添加自动消失功能
errorDiv.style.position = 'fixed';
errorDiv.style.top = '20px';
errorDiv.style.left = '50%';
errorDiv.style.transform = 'translateX(-50%)';
errorDiv.style.zIndex = '1000';
errorDiv.style.padding = '10px';
errorDiv.style.backgroundColor = '#f8d7da';
errorDiv.style.color = '#721c24';
errorDiv.style.borderRadius = '4px';
errorDiv.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
// 将错误消息添加到文档主体而不是shadowRoot
document.body.appendChild(errorDiv);
// 3秒后自动消失
setTimeout(() => {
if (errorDiv.parentNode) {
errorDiv.parentNode.removeChild(errorDiv);
}
}, 3000);
}
// 显示编辑执行人对话框
showEditExecutorModal(todo) {
// 权限检查
const currentUserLevel = this.currentUser.level || 0;
if (currentUserLevel <= 2 && todo.adduser !== this.currentUser.username) {
this.showError('您没有权限编辑他人创建的待办事项');
return;
}
if (currentUserLevel === 3 && todo.adduser === 'admin') {
this.showError('您没有权限编辑管理员创建的待办事项');
return;
}
this.editingTodo = todo;
const { modal, style } = TodoModal.createModal('executor');
// 获取当前用户等级
const currentUserAccessLevel = this.currentUser.access_level || 0;
// 填充用户下拉列表
const executorSelect = modal.querySelector('#executor');
// 筛选符合条件的用户
const availableUsers = this.users.filter(user =>
user &&
user.access_level > 0 &&
user.access_level <= currentUserAccessLevel
);
// 添加用户选项
availableUsers.forEach(user => {
const option = document.createElement('option');
option.value = user.username;
option.textContent = `${user.username} (${user.full_name})`;
if (user.username === todo.exeuser) {
option.selected = true;
}
executorSelect.appendChild(option);
});
// 添加保存按钮事件
const saveButton = modal.querySelector('.save-button');
saveButton.addEventListener('click', async () => {
const executor = executorSelect.value;
if (executor && this.editingTodo) {
try {
await TodoService.updateTodo(this.editingTodo.id, {
...this.editingTodo,
exeuser: executor
});
// 更新本地数据
this.editingTodo.exeuser = executor;
this.render();
modal.remove();
style.remove();
} catch (error) {
console.error('更新执行人时发生错误:', error);
this.showError('更新执行人失败,请稍后重试');
}
}
});
document.body.appendChild(modal);
}
// 显示编辑计划时间对话框
showEditScheduleModal(todo) {
// 权限检查
const currentUserLevel = this.currentUser.level || 0;
if (currentUserLevel <= 2 && todo.adduser !== this.currentUser.username) {
this.showError('您没有权限编辑他人创建的待办事项');
return;
}
if (currentUserLevel === 3 && todo.adduser === 'admin') {
this.showError('您没有权限编辑管理员创建的待办事项');
return;
}
this.editingTodo = todo;
const { modal, style } = TodoModal.createModal('schedule');
// 设置日期时间选择器的初始值
const scheduleInput = modal.querySelector('#schedule');
const scheduleDate = new Date(todo.sche_time);
const year = scheduleDate.getFullYear();
const month = String(scheduleDate.getMonth() + 1).padStart(2, '0');
const day = String(scheduleDate.getDate()).padStart(2, '0');
const hours = String(scheduleDate.getHours()).padStart(2, '0');
const minutes = String(scheduleDate.getMinutes()).padStart(2, '0');
const seconds = String(scheduleDate.getSeconds()).padStart(2, '0');
scheduleInput.value = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
// 添加保存按钮事件
const saveButton = modal.querySelector('.save-button');
saveButton.addEventListener('click', async () => {
const scheduleTime = scheduleInput.value;
if (scheduleTime && this.editingTodo) {
try {
await TodoService.updateTodo(this.editingTodo.id, {
...this.editingTodo,
sche_time: scheduleTime
});
// 更新本地数据
this.editingTodo.sche_time = scheduleTime;
this.render();
modal.remove();
style.remove();
} catch (error) {
console.error('更新计划时间时发生错误:', error);
this.showError('更新计划时间失败,请稍后重试');
}
}
});
document.body.appendChild(modal);
}
// 显示新增待办对话框
showNewTodoModal() {
const { modal, style } = TodoModal.createModal('new-todo');
// 设置计划时间的默认值为当前本地时间
const scheduleInput = modal.querySelector('#schedule');
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
scheduleInput.value = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
// 获取当前用户等级
const currentUserLevel = this.currentUser.access_level || 0;
// 填充用户下拉列表
const executorSelect = modal.querySelector('#executor');
// 筛选符合条件的用户
const availableUsers = this.users.filter(user =>
user &&
user.access_level > 0 &&
user.access_level <= currentUserLevel
);
// 添加用户选项
availableUsers.forEach(user => {
const option = document.createElement('option');
option.value = user.username;
option.textContent = `${user.username} (${user.full_name})`;
executorSelect.appendChild(option);
});
// 获取所有项目和子项目
const projectTree = TodoTree.buildProjectTree(this.todos);
const projectInput = modal.querySelector('#project');
const subprojectInput = modal.querySelector('#subproject');
const projectOptions = modal.querySelector('#project-options');
const subprojectOptions = modal.querySelector('#subproject-options');
// 填充项目选项
Object.keys(projectTree).forEach(project => {
const option = document.createElement('div');
option.className = 'select-option';
option.textContent = project;
option.addEventListener('click', () => {
projectInput.value = project;
projectOptions.style.display = 'none';
// 更新子项目选项
updateSubprojectOptions(project);
});
projectOptions.appendChild(option);
});
// 更新子项目选项的函数
const updateSubprojectOptions = (selectedProject) => {
subprojectOptions.innerHTML = '';
const subprojects = projectTree[selectedProject]?.subprojects || {};
Object.keys(subprojects).forEach(subproject => {
const option = document.createElement('div');
option.className = 'select-option';
option.textContent = subproject;
option.addEventListener('click', () => {
subprojectInput.value = subproject;
subprojectOptions.style.display = 'none';
});
subprojectOptions.appendChild(option);
});
};
// 项目输入框事件处理
projectInput.addEventListener('focus', () => {
projectOptions.style.display = 'block';
subprojectOptions.style.display = 'none';
});
projectInput.addEventListener('input', () => {
const value = projectInput.value.toLowerCase();
const options = projectOptions.querySelectorAll('.select-option');
options.forEach(option => {
const text = option.textContent.toLowerCase();
option.style.display = text.includes(value) ? 'block' : 'none';
});
projectOptions.style.display = 'block';
});
// 子项目输入框事件处理
subprojectInput.addEventListener('focus', () => {
if (projectInput.value) {
subprojectOptions.style.display = 'block';
projectOptions.style.display = 'none';
}
});
subprojectInput.addEventListener('input', () => {
if (projectInput.value) {
const value = subprojectInput.value.toLowerCase();
const options = subprojectOptions.querySelectorAll('.select-option');
options.forEach(option => {
const text = option.textContent.toLowerCase();
option.style.display = text.includes(value) ? 'block' : 'none';
});
subprojectOptions.style.display = 'block';
}
});
// 点击外部关闭下拉列表
document.addEventListener('click', (e) => {
if (!e.target.closest('.custom-select')) {
projectOptions.style.display = 'none';
subprojectOptions.style.display = 'none';
}
});
// 添加保存按钮事件
const saveButton = modal.querySelector('.save-button');
saveButton.addEventListener('click', async () => {
const project = projectInput.value;
const subproject = subprojectInput.value;
const title = modal.querySelector('#title').value;
const text = modal.querySelector('#text').value;
const scheduleTime = modal.querySelector('#schedule').value;
const executor = modal.querySelector('#executor').value;
if (!project || !subproject || !scheduleTime || !executor || !title) {
this.showError('请填写必填项');
return;
}
try {
await TodoService.createTodo({
project,
subproject,
title,
text,
sche_time: scheduleTime,
exeuser: executor,
adduser: this.currentUser.username,
completed: false,
status: 'pending'
});
// 重新加载待办列表并渲染
await this.fetchTodos();
this.render();
modal.remove();
style.remove();
} catch (error) {
console.error('创建待办时发生错误:', error);
this.showError(error.message || '创建待办失败,请稍后重试');
}
});
document.body.appendChild(modal);
}
// 过滤待办事项
filterTodos() {
if (!this.currentUser) {
console.log('未获取到当前用户信息,无法进行筛选');
return [];
}
// 首先根据用户等级进行筛选
const userLevel = this.currentUser.level || 0;
let filteredTodos = this.todos;
// 等级4可以看到所有待办事项
if (userLevel !== 4) {
// 等级3不能看到创建人和执行人都是等级4的待办事项
if (userLevel === 3) {
filteredTodos = filteredTodos.filter(todo => {
const creator = this.users.find(u => u.username === todo.adduser);
const executor = this.users.find(u => u.username === todo.exeuser);
// 如果找不到用户信息,默认显示
if (!creator || !executor) return true;
// 只要创建人或执行人不是等级4就显示
return !(creator.level === 4 && executor.level === 4);
});
} else {
// 等级2或更低只能看到创建人或执行人是自己的待办事项
filteredTodos = filteredTodos.filter(todo => {
return todo.adduser === this.currentUser.username ||
todo.exeuser === this.currentUser.username;
});
}
}
// 然后根据项目/子项目筛选
if (this.selectedProject) {
filteredTodos = filteredTodos.filter(todo => {
const matchesProject = todo.project === this.selectedProject;
if (!this.selectedSubproject) {
return matchesProject;
}
return matchesProject && todo.subproject === this.selectedSubproject;
});
}
// 最后根据复选框状态筛选
if (!this.showCompleted) {
filteredTodos = filteredTodos.filter(todo => !todo.completed);
}
return filteredTodos;
}
render() {
if (!this.isInitialized) {
return;
}
// 清空现有内容
this.shadowRoot.innerHTML = '';
// 添加样式
const style = document.createElement('style');
style.textContent = `
.container {
display: flex;
height: calc(100vh - 120px);
font-family: Arial, sans-serif;
margin: 10px;
overflow: hidden;
}
.project-tree {
width: 250px;
background: #f8f9fa;
border-right: 1px solid #e9ecef;
padding: 15px;
display: flex;
flex-direction: column;
position: relative;
height: 100%;
box-sizing: border-box;
}
.tree-content {
flex: 1;
overflow-y: auto;
margin-bottom: 100px;
padding-right: 5px;
}
.todo-container {
flex: 1;
padding: 20px;
overflow-y: auto;
height: 100%;
box-sizing: border-box;
}
.bottom-controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 15px;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
box-sizing: border-box;
}
.tree-content::-webkit-scrollbar,
.todo-container::-webkit-scrollbar {
width: 6px;
}
.tree-content::-webkit-scrollbar-track,
.todo-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.tree-content::-webkit-scrollbar-thumb,
.todo-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 3px;
}
.tree-content::-webkit-scrollbar-thumb:hover,
.todo-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
.show-completed-container {
margin-bottom: 10px;
padding: 8px;
display: flex;
align-items: center;
gap: 8px;
background: #fff;
border-radius: 4px;
border: 1px solid #e9ecef;
}
.show-completed-container input[type="checkbox"] {
cursor: pointer;
width: 16px;
height: 16px;
}
.show-completed-container label {
cursor: pointer;
user-select: none;
color: #495057;
font-size: 14px;
}
.show-completed-container:hover {
background: #e9ecef;
}
.show-all-button {
width: 100%;
padding: 8px 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.show-all-button:hover {
background-color: #0056b3;
}
.show-all-button:active {
background-color: #004085;
}
.project-node {
margin-bottom: 10px;
}
.project-header {
padding: 8px;
background: #e9ecef;
border-radius: 4px;
cursor: pointer;
}
.project-header-content {
display: flex;
align-items: center;
gap: 8px;
}
.project-header:hover {
background: #dee2e6;
}
.expand-icon {
font-size: 12px;
transition: transform 0.2s;
color: #495057;
}
.expand-icon.expanded {
transform: rotate(90deg);
}
.subprojects-container {
margin-left: 20px;
margin-top: 5px;
}
.subproject-node {
padding: 6px 8px;
cursor: pointer;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.subproject-node:hover {
background: #e9ecef;
}
.todo-count {
font-size: 0.9em;
color: #6c757d;
}
.todo-item {
background: #fff;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 15px;
margin-bottom: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.todo-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e9ecef;
}
.todo-header h3 {
margin: 0;
color: #212529;
font-size: 1.1em;
}
.todo-content {
color: #495057;
}
.todo-info {
margin-bottom: 8px;
font-size: 0.9em;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.todo-info .label {
color: #6c757d;
}
.todo-info .value {
color: #212529;
}
.todo-description {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e9ecef;
color: #495057;
font-size: 0.95em;
}
.description-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.description-actions {
display: flex;
gap: 4px;
}
.description-content {
white-space: pre-wrap;
line-height: 1.5;
max-height: 100px;
overflow: hidden;
transition: max-height 0.3s ease-out;
position: relative;
text-indent: 0;
}
.description-content.expanded {
max-height: 2000px;
}
.description-content:not(.expanded) {
max-height: 1.5em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-indent: 0;
}
.description-content::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: linear-gradient(transparent, white);
pointer-events: none;
opacity: 1;
transition: opacity 0.3s ease-out;
}
.description-content.expanded::after {
opacity: 0;
}
.toggle-button {
background: none;
border: none;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-button:hover {
background-color: rgba(121, 134, 231, 0.1);
}
.toggle-icon {
transition: transform 0.3s ease;
width: 16px;
height: 16px;
display: inline-block;
}
.toggle-button.expanded .toggle-icon {
transform: rotate(180deg);
}
.status {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.9em;
}
.status.completed {
background: #d4edda;
color: #155724;
}
.status.pending {
background: #fff3cd;
color: #856404;
}
.error-message {
color: #721c24;
padding: 10px;
background: #f8d7da;
border-radius: 4px;
margin: 10px;
}
.selected {
background: #cfe2ff !important;
}
.executor-link {
color: #007bff;
text-decoration: none;
cursor: pointer;
}
.executor-link:hover {
text-decoration: underline;
}
.schedule-link {
color: #007bff;
text-decoration: none;
cursor: pointer;
}
.schedule-link:hover {
text-decoration: underline;
}
.add-todo-button {
margin-bottom: 15px;
padding: 8px 16px;
background-color: #7986E7;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
width: 100%;
}
.add-todo-button:hover {
background-color: #6875D6;
}
.add-todo-button:active {
background-color: #5A67D8;
}
.todo-actions {
display: flex;
align-items: center;
gap: 8px;
}
.edit-button, .delete-button, .complete-button {
background: none;
border: none;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.action-icon {
width: 16px;
height: 16px;
object-fit: contain;
}
.edit-button:hover {
background-color: rgba(121, 134, 231, 0.1);
}
.delete-button:hover {
background-color: rgba(220, 53, 69, 0.1);
}
.complete-button:hover {
background-color: rgba(40, 167, 69, 0.1);
}
`;
this.shadowRoot.appendChild(style);
// 创建主容器
const container = document.createElement('div');
container.className = 'container';
// 首先根据用户等级过滤待办事项
const userLevel = this.currentUser.level || 0;
let filteredTodos = this.todos;
// 等级4可以看到所有待办事项
if (userLevel !== 4) {
// 等级3不能看到创建人和执行人都是等级4的待办事项
if (userLevel === 3) {
filteredTodos = filteredTodos.filter(todo => {
const creator = this.users.find(u => u.username === todo.adduser);
const executor = this.users.find(u => u.username === todo.exeuser);
// 如果找不到用户信息,默认显示
if (!creator || !executor) return true;
// 只要创建人或执行人不是等级4就显示
return !(creator.level === 4 && executor.level === 4);
});
} else {
// 等级2或更低只能看到创建人或执行人是自己的待办事项
filteredTodos = filteredTodos.filter(todo => {
return todo.adduser === this.currentUser.username ||
todo.exeuser === this.currentUser.username;
});
}
}
// 构建并渲染项目树(使用过滤后的待办事项)
const tree = TodoTree.buildProjectTree(filteredTodos);
const treeContainer = TodoTree.renderProjectTree(tree, {
expandedProjects: this.expandedProjects,
selectedProject: this.selectedProject,
selectedSubproject: this.selectedSubproject,
showCompleted: this.showCompleted,
onProjectSelect: (project) => {
this.selectedProject = project;
this.selectedSubproject = null;
this.render();
},
onSubprojectSelect: (project, subproject) => {
this.selectedProject = project;
this.selectedSubproject = subproject;
this.render();
},
onExpandToggle: (project) => {
if (this.expandedProjects.has(project)) {
this.expandedProjects.delete(project);
} else {
this.expandedProjects.add(project);
}
this.render();
},
onShowCompletedChange: (show) => {
this.showCompleted = show;
this.render();
},
onShowAll: () => {
this.selectedProject = null;
this.selectedSubproject = null;
this.render();
},
onAddTodo: () => this.showNewTodoModal()
});
// 然后根据项目/子项目筛选
if (this.selectedProject) {
filteredTodos = filteredTodos.filter(todo => {
const matchesProject = todo.project === this.selectedProject;
if (!this.selectedSubproject) {
return matchesProject;
}
return matchesProject && todo.subproject === this.selectedSubproject;
});
}
// 最后根据复选框状态筛选
if (!this.showCompleted) {
filteredTodos = filteredTodos.filter(todo => !todo.completed);
}
// 渲染过滤后的待办事项
const todosContainer = TodoList.renderTodoList(filteredTodos, {
onEditExecutor: (todo) => this.showEditExecutorModal(todo),
onEditSchedule: (todo) => this.showEditScheduleModal(todo),
onEditTitle: (todo) => {
// 权限检查
const currentUserLevel = this.currentUser.level || 0;
if (currentUserLevel <= 2 && todo.adduser !== this.currentUser.username) {
this.showError('您没有权限编辑他人创建的待办事项');
return;
}
if (currentUserLevel === 3 && todo.adduser === 'admin') {
this.showError('您没有权限编辑管理员创建的待办事项');
return;
}
const { modal, style } = TodoModal.createModal('edit-title');
const titleInput = modal.querySelector('#title');
titleInput.value = todo.title;
const saveButton = modal.querySelector('.save-button');
saveButton.addEventListener('click', async () => {
const newTitle = titleInput.value;
if (!newTitle) {
this.showError('标题不能为空');
return;
}
try {
await TodoService.updateTodo(todo.id, {
...todo,
title: newTitle
});
await this.fetchTodos();
this.render();
modal.remove();
style.remove();
} catch (error) {
console.error('更新标题时发生错误:', error);
this.showError('更新标题失败,请稍后重试');
}
});
document.body.appendChild(modal);
},
onEditDescription: (todo) => {
// 权限检查
const currentUserLevel = this.currentUser.level || 0;
if (currentUserLevel <= 2 && todo.adduser !== this.currentUser.username) {
this.showError('您没有权限编辑他人创建的待办事项');
return;
}
if (currentUserLevel === 3 && todo.adduser === 'admin') {
this.showError('您没有权限编辑管理员创建的待办事项');
return;
}
const { modal, style } = TodoModal.createModal('edit-description');
const textInput = modal.querySelector('#text');
textInput.value = todo.text || '';
const saveButton = modal.querySelector('.save-button');
saveButton.addEventListener('click', async () => {
const newText = textInput.value;
try {
await TodoService.updateTodo(todo.id, {
...todo,
text: newText
});
await this.fetchTodos();
this.render();
modal.remove();
style.remove();
} catch (error) {
console.error('更新描述时发生错误:', error);
this.showError('更新描述失败,请稍后重试');
}
});
document.body.appendChild(modal);
},
onDelete: async (todo) => {
// 权限检查
const currentUserLevel = this.currentUser.level || 0;
if (currentUserLevel <= 2 && todo.adduser !== this.currentUser.username) {
this.showError('您没有权限删除他人创建的待办事项');
return;
}
if (currentUserLevel === 3 && todo.adduser === 'admin') {
this.showError('您没有权限删除管理员创建的待办事项');
return;
}
if (confirm('确定要删除这条待办事项吗?')) {
try {
await TodoService.deleteTodo(todo.id);
await this.fetchTodos();
this.render();
} catch (error) {
console.error('删除待办事项时发生错误:', error);
this.showError('删除待办事项失败,请稍后重试');
}
}
},
onComplete: async (todo) => {
const action = todo.completed ? '取消完成' : '标记完成';
if (confirm(`确定要${action}这条待办事项吗?`)) {
try {
await TodoService.updateTodo(todo.id, {
...todo,
completed: !todo.completed,
complete_time: !todo.completed ? new Date().toISOString() : null
});
await this.fetchTodos();
this.render();
} catch (error) {
console.error(`${action}待办事项时发生错误:`, error);
this.showError(`${action}待办事项失败,请稍后重试`);
}
}
},
onToggleDescription: (descriptionContent, toggleButton) => {
const isExpanded = descriptionContent.classList.contains('expanded');
if (isExpanded) {
descriptionContent.classList.remove('expanded');
toggleButton.classList.remove('expanded');
} else {
descriptionContent.classList.add('expanded');
toggleButton.classList.add('expanded');
}
}
});
container.appendChild(treeContainer);
container.appendChild(todosContainer);
this.shadowRoot.appendChild(container);
}
connectedCallback() {
this.initialize();
}
// 清除所有数据
clearData() {
this.todos = [];
this.selectedProject = null;
this.selectedSubproject = null;
this.expandedProjects = new Set();
this.users = [];
this.currentUser = null;
this.editingTodo = null;
this.isInitialized = false;
this.showCompleted = false;
}
}
customElements.define('todo-component', TodoComponent);