diff --git a/app/templates/goals.html b/app/templates/goals.html index 77a7e19..f29bde1 100644 --- a/app/templates/goals.html +++ b/app/templates/goals.html @@ -54,16 +54,27 @@ @@ -153,28 +164,98 @@ async function deleteGoal(id) { async function manageRelations(id) { document.getElementById('relation-goal-id').value = id; - const [parents, children] = await Promise.all([ - fetch(`${API_BASE}/${id}/parents`).then(r => r.json()), + // 获取当前目标信息和所有目标 + const [currentGoal, allGoals, children] = await Promise.all([ + fetch(`${API_BASE}/${id}`).then(r => r.json()), + fetch(API_BASE).then(r => r.json()), fetch(`${API_BASE}/${id}/children`).then(r => r.json()) ]); - document.getElementById('parent-goals').innerHTML = parents.map(g => - `${escapeHtml(g.name)} ` - ).join('') || ''; + // 显示当前目标名称 + document.getElementById('current-goal-name').textContent = currentGoal.name; - document.getElementById('child-goals').innerHTML = children.map(g => - `${escapeHtml(g.name)} ` - ).join('') || ''; + // 已关联的子目标 + const childIds = children.map(c => c.id); + renderChildrenList(children, id); + + // 可选的子目标(下拉列表中排除自己 和 已关联的) + const availableSelect = document.getElementById('available-goals-select'); + availableSelect.innerHTML = allGoals + .filter(g => g.id !== id && !childIds.includes(g.id)) + .map(g => ``) + .join(''); new bootstrap.Modal(document.getElementById('relationModal')).show(); } -async function removeRelation(parentId, childId, type) { - const url = type === 'parent' - ? `${API_BASE}/${childId}/children/${parentId}` - : `${API_BASE}/${parentId}/children/${childId}`; - await fetch(url, {method: 'DELETE'}); - manageRelations(parentId); +function renderChildrenList(children, parentId) { + const list = document.getElementById('child-goals-list'); + if (children.length === 0) { + list.innerHTML = '

暂无关联子目标

'; + return; + } + list.innerHTML = children.map(g => + `
+ ${escapeHtml(g.name)} + +
` + ).join(''); +} + +async function addSelectedChildren() { + const parentId = document.getElementById('relation-goal-id').value; + const select = document.getElementById('available-goals-select'); + const selectedOptions = Array.from(select.selectedOptions); + + if (selectedOptions.length === 0) { + alert('请先选择要添加的子目标'); + return; + } + + for (const option of selectedOptions) { + const childId = parseInt(option.value); + try { + const res = await fetch(`${API_BASE}/${parentId}/children`, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({child_goal_id: childId}) + }); + if (!res.ok) { + const err = await res.json(); + alert(err.error || '添加失败'); + } + } catch (e) { + console.error(e); + } + } + + // 刷新列表 + const children = await fetch(`${API_BASE}/${parentId}/children`).then(r => r.json()); + renderChildrenList(children, parentId); + + // 从下拉框移除已添加的 + selectedOptions.forEach(opt => opt.remove()); +} + +async function removeChildRelation(parentId, childId) { + if (!confirm('确定移除此关联?')) return; + await fetch(`${API_BASE}/${parentId}/children/${childId}`, {method: 'DELETE'}); + + // 刷新列表 + const children = await fetch(`${API_BASE}/${parentId}/children`).then(r => r.json()); + renderChildrenList(children, parentId); + + // 刷新下拉框 + const allGoals = await fetch(API_BASE).then(r => r.json()); + const childIds = children.map(c => c.id); + const select = document.getElementById('available-goals-select'); + const currentGoalId = parseInt(document.getElementById('relation-goal-id').value); + select.innerHTML = allGoals + .filter(g => g.id !== currentGoalId && !childIds.includes(g.id)) + .map(g => ``) + .join(''); } function escapeHtml(text) {