fix(v4.1.1): 待办事务功能优化
- 修复完成状态切换问题(可来回切换完成/未完成) - 添加全部/未完成/已完成过滤按钮 - 翻页时保持弹窗滚动位置
This commit is contained in:
@@ -2846,11 +2846,19 @@ async function deleteItem(id) {
|
|||||||
let currentDetailId = null;
|
let currentDetailId = null;
|
||||||
|
|
||||||
// 显示详情
|
// 显示详情
|
||||||
async function showDetail(id, todoPage = 1) {
|
async function showDetail(id, todoPage = 1, todoFilter = 'all') {
|
||||||
currentDetailId = id;
|
currentDetailId = id;
|
||||||
|
currentTodoPage = todoPage;
|
||||||
|
currentTodoFilter = todoFilter;
|
||||||
|
|
||||||
// 增加阅读数
|
// 记录当前弹窗滚动位置
|
||||||
await fetch(`${API_BASE}/items/${id}/view`, { method: 'POST' });
|
const detailContent = document.getElementById('detailContent');
|
||||||
|
const scrollTop = detailContent.scrollTop;
|
||||||
|
|
||||||
|
// 增加阅读数(首次加载时才增加)
|
||||||
|
if (todoPage === 1 && todoFilter === 'all') {
|
||||||
|
await fetch(`${API_BASE}/items/${id}/view`, { method: 'POST' });
|
||||||
|
}
|
||||||
|
|
||||||
const res = await fetch(`${API_BASE}/items/${id}`);
|
const res = await fetch(`${API_BASE}/items/${id}`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -2915,21 +2923,46 @@ async function showDetail(id, todoPage = 1) {
|
|||||||
// 文本类型显示待办事务
|
// 文本类型显示待办事务
|
||||||
if (item.type === 'text') {
|
if (item.type === 'text') {
|
||||||
const todoOffset = (todoPage - 1) * 10;
|
const todoOffset = (todoPage - 1) * 10;
|
||||||
const todoRes = await fetch(`${API_BASE}/items/${id}/todo-events?limit=10&offset=${todoOffset}`);
|
|
||||||
const todoData = await todoRes.json();
|
// 根据过滤状态获取数据
|
||||||
|
let todoRes = await fetch(`${API_BASE}/items/${id}/todo-events?limit=10&offset=${todoOffset}`);
|
||||||
|
let todoData = await todoRes.json();
|
||||||
|
|
||||||
|
// 客户端过滤(因为API返回全部数据)
|
||||||
|
let filteredEvents = todoData.data;
|
||||||
|
let totalTodo = todoData.total;
|
||||||
|
|
||||||
|
if (todoFilter === 'completed') {
|
||||||
|
filteredEvents = filteredEvents.filter(e => e.is_completed);
|
||||||
|
// 需要重新计算总数
|
||||||
|
const allRes = await fetch(`${API_BASE}/items/${id}/todo-events?limit=1000&offset=0`);
|
||||||
|
const allData = await allRes.json();
|
||||||
|
totalTodo = allData.data.filter(e => e.is_completed).length;
|
||||||
|
} else if (todoFilter === 'pending') {
|
||||||
|
filteredEvents = filteredEvents.filter(e => !e.is_completed);
|
||||||
|
const allRes = await fetch(`${API_BASE}/items/${id}/todo-events?limit=1000&offset=0`);
|
||||||
|
const allData = await allRes.json();
|
||||||
|
totalTodo = allData.data.filter(e => !e.is_completed).length;
|
||||||
|
}
|
||||||
|
|
||||||
html += `<hr><div class="mb-3">
|
html += `<hr><div class="mb-3">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<strong><i class="bi bi-list-check"></i> 待办事务</strong>
|
<strong><i class="bi bi-list-check"></i> 待办事务</strong>
|
||||||
<button class="btn btn-sm btn-outline-primary" onclick="showAddTodoEventModal(${item.id})">
|
<button class="btn btn-sm btn-outline-primary" onclick="showAddTodoEventModal(${item.id})">
|
||||||
<i class="bi bi-plus"></i> 添加事务
|
<i class="bi bi-plus"></i> 添加事务
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 过滤按钮 -->
|
||||||
|
<div class="btn-group btn-group-sm mb-2" role="group">
|
||||||
|
<button class="btn ${todoFilter === 'all' ? 'btn-primary' : 'btn-outline-secondary'}" onclick="showDetail(${id}, 1, 'all')">全部</button>
|
||||||
|
<button class="btn ${todoFilter === 'pending' ? 'btn-warning' : 'btn-outline-warning'}" onclick="showDetail(${id}, 1, 'pending')">未完成</button>
|
||||||
|
<button class="btn ${todoFilter === 'completed' ? 'btn-success' : 'btn-outline-success'}" onclick="showDetail(${id}, 1, 'completed')">已完成</button>
|
||||||
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
if (todoData.success && todoData.data.length > 0) {
|
if (filteredEvents.length > 0) {
|
||||||
html += `<div class="border rounded p-2 bg-light" id="todoEventsList">`;
|
html += `<div class="border rounded p-2 bg-light" id="todoEventsList">`;
|
||||||
todoData.data.forEach(event => {
|
filteredEvents.forEach(event => {
|
||||||
const completedClass = event.is_completed ? 'text-muted' : '';
|
const completedClass = event.is_completed ? 'text-muted' : '';
|
||||||
const checkIcon = event.is_completed ? '✅' : '⏳';
|
const checkIcon = event.is_completed ? '✅' : '⏳';
|
||||||
const remainingText = event.remaining_days > 0 ? `${event.remaining_days}天` : '已过期';
|
const remainingText = event.remaining_days > 0 ? `${event.remaining_days}天` : '已过期';
|
||||||
@@ -2938,7 +2971,7 @@ async function showDetail(id, todoPage = 1) {
|
|||||||
html += `<div class="d-flex justify-content-between align-items-start py-2 border-bottom todo-event-item ${completedClass}">
|
html += `<div class="d-flex justify-content-between align-items-start py-2 border-bottom todo-event-item ${completedClass}">
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<span onclick="toggleTodoEventComplete(${event.id}, ${item.id})" style="cursor:pointer;" title="点击切换完成状态">${checkIcon}</span>
|
<span onclick="toggleTodoEventComplete(${event.id}, ${item.id}, ${event.is_completed})" style="cursor:pointer;" title="点击切换完成状态">${checkIcon}</span>
|
||||||
<span class="${event.is_completed ? 'text-decoration-line-through' : ''}">${escapeHtml(event.content)}</span>
|
<span class="${event.is_completed ? 'text-decoration-line-through' : ''}">${escapeHtml(event.content)}</span>
|
||||||
<small class="${remainingClass}">(${remainingText})</small>
|
<small class="${remainingClass}">(${remainingText})</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -2959,26 +2992,25 @@ async function showDetail(id, todoPage = 1) {
|
|||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
|
|
||||||
// 分页
|
// 分页
|
||||||
const totalTodo = todoData.total;
|
|
||||||
const totalPagesTodo = Math.ceil(totalTodo / 10);
|
const totalPagesTodo = Math.ceil(totalTodo / 10);
|
||||||
if (totalPagesTodo > 1) {
|
if (totalPagesTodo > 1) {
|
||||||
html += `<div class="d-flex justify-content-center mt-2">
|
html += `<div class="d-flex justify-content-center mt-2">
|
||||||
<nav><ul class="pagination pagination-sm">`;
|
<nav><ul class="pagination pagination-sm">`;
|
||||||
for (let p = 1; p <= Math.min(totalPagesTodo, 5); p++) {
|
for (let p = 1; p <= Math.min(totalPagesTodo, 5); p++) {
|
||||||
html += `<li class="page-item ${p === todoPage ? 'active' : ''}">
|
html += `<li class="page-item ${p === todoPage ? 'active' : ''}">
|
||||||
<a class="page-link" href="#" onclick="showDetail(${id}, ${p}); return false;">${p}</a>
|
<a class="page-link" href="#" onclick="showDetail(${id}, ${p}, '${todoFilter}'); return false;">${p}</a>
|
||||||
</li>`;
|
</li>`;
|
||||||
}
|
}
|
||||||
if (totalPagesTodo > 5) {
|
if (totalPagesTodo > 5) {
|
||||||
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
||||||
html += `<li class="page-item"><a class="page-link" href="#" onclick="showDetail(${id}, ${totalPagesTodo}); return false;">${totalPagesTodo}</a></li>`;
|
html += `<li class="page-item"><a class="page-link" href="#" onclick="showDetail(${id}, ${totalPagesTodo}, '${todoFilter}'); return false;">${totalPagesTodo}</a></li>`;
|
||||||
}
|
}
|
||||||
html += `</ul></nav>
|
html += `</ul></nav>
|
||||||
<small class="text-muted ms-2">共 ${totalTodo} 条事务</small>
|
<small class="text-muted ms-2">共 ${totalTodo} 条事务</small>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html += `<div class="text-center text-muted py-3">暂无待办事务</div>`;
|
html += `<div class="text-center text-muted py-3">${todoFilter === 'all' ? '暂无待办事务' : (todoFilter === 'completed' ? '暂无已完成事务' : '暂无未完成事务')}</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3020,7 +3052,17 @@ async function showDetail(id, todoPage = 1) {
|
|||||||
|
|
||||||
document.getElementById('detailContent').innerHTML = html;
|
document.getElementById('detailContent').innerHTML = html;
|
||||||
|
|
||||||
new bootstrap.Modal(document.getElementById('detailModal')).show();
|
// 如果弹窗已经打开,保持滚动位置
|
||||||
|
const modal = bootstrap.Modal.getInstance(document.getElementById('detailModal'));
|
||||||
|
if (modal && modal._isShown) {
|
||||||
|
// 弹窗已打开,恢复滚动位置
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById('detailContent').scrollTop = scrollTop;
|
||||||
|
}, 10);
|
||||||
|
} else {
|
||||||
|
// 弹窗未打开,打开弹窗
|
||||||
|
new bootstrap.Modal(document.getElementById('detailModal')).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ 待办事务功能 ============
|
// ============ 待办事务功能 ============
|
||||||
@@ -3085,7 +3127,7 @@ async function saveTodoEvent() {
|
|||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
bootstrap.Modal.getInstance(document.getElementById('todoEventModal')).hide();
|
bootstrap.Modal.getInstance(document.getElementById('todoEventModal')).hide();
|
||||||
showDetail(itemId, 1); // 刷新详情,回到第一页
|
showDetail(itemId, currentTodoPage, currentTodoFilter); // 刷新详情,保持页面和过滤状态
|
||||||
} else {
|
} else {
|
||||||
alert('更新失败: ' + data.error);
|
alert('更新失败: ' + data.error);
|
||||||
}
|
}
|
||||||
@@ -3100,30 +3142,40 @@ async function saveTodoEvent() {
|
|||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
bootstrap.Modal.getInstance(document.getElementById('todoEventModal')).hide();
|
bootstrap.Modal.getInstance(document.getElementById('todoEventModal')).hide();
|
||||||
showDetail(itemId, 1); // 刷新详情,回到第一页
|
showDetail(itemId, 1, currentTodoFilter); // 创建新事务后回到第一页
|
||||||
} else {
|
} else {
|
||||||
alert('创建失败: ' + data.error);
|
alert('创建失败: ' + data.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换待办事务完成状态
|
// 切换待办事务完成状态(可切换为完成或未完成)
|
||||||
async function toggleTodoEventComplete(eventId, itemId) {
|
async function toggleTodoEventComplete(eventId, itemId, currentCompleted) {
|
||||||
// 离线检查
|
// 离线检查
|
||||||
if (!checkOnlineBeforeAction('切换完成状态')) return;
|
if (!checkOnlineBeforeAction('切换完成状态')) return;
|
||||||
|
|
||||||
const res = await fetch(`${API_BASE}/todo-events/${eventId}/complete`, {
|
// 切换状态:已完成->未完成,未完成->已完成
|
||||||
method: 'POST'
|
const newCompleted = !currentCompleted;
|
||||||
|
|
||||||
|
const res = await fetch(`${API_BASE}/todo-events/${eventId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ is_completed: newCompleted })
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
showDetail(itemId, 1); // 刷新详情
|
// 保持当前页面和过滤状态
|
||||||
|
showDetail(itemId, currentTodoPage, currentTodoFilter);
|
||||||
} else {
|
} else {
|
||||||
alert('操作失败: ' + data.error);
|
alert('操作失败: ' + data.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当前待办事务的页面和过滤状态
|
||||||
|
let currentTodoPage = 1;
|
||||||
|
let currentTodoFilter = 'all'; // all, completed, pending
|
||||||
|
|
||||||
// 删除待办事务
|
// 删除待办事务
|
||||||
async function deleteTodoEvent(eventId, itemId) {
|
async function deleteTodoEvent(eventId, itemId) {
|
||||||
// 离线检查
|
// 离线检查
|
||||||
@@ -3137,7 +3189,7 @@ async function deleteTodoEvent(eventId, itemId) {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
showDetail(itemId, 1); // 刷新详情
|
showDetail(itemId, currentTodoPage, currentTodoFilter); // 刷新详情,保持页面和过滤状态
|
||||||
} else {
|
} else {
|
||||||
alert('删除失败: ' + data.error);
|
alert('删除失败: ' + data.error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user