You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Balkan FamilyTreeJS结合Flask实现家谱数据自动存读问题求助

Flask + Balkan FamilyTree 实现家谱数据自动同步与去重加载

核心问题梳理

你当前的代码存在三个关键问题:

  1. 前端配置拼写错误,导致组件部分功能失效
  2. 浏览器安全限制无法直接写入服务器JSON文件,必须通过Flask后端处理
  3. 数据加载时的ID重置逻辑会破坏节点间的关联关系,去重逻辑不完善

一、修复前端配置拼写错误

先修正代码中的两处拼写错误,这是组件正常运行的基础:

var family = new FamilyTree(document.getElementById('tree'), {
    mouseScroll: FamilyTree.none, // 修正:mouseScrool → mouseScroll
    mode: 'dark',
    template: 'hugo',
    roots: [1],
    nodeMenu: {
        edit: { text: 'Edit' },
        details: { text: 'Details' },
    },
    nodeTreeMenu: true,
    nodeBindings: { // 修正:nodeBinding → nodeBindings
        field_0: 'name',
        field_1: 'born',
        img_0: 'photo'
    },
    // 其余配置保留不变
});

二、实现Flask后端读写接口

浏览器无法直接操作服务器文件,必须通过后端接口处理数据的读写:

1. Flask后端代码(app.py)

from flask import Flask, request, jsonify, render_template
import json
import os

app = Flask(__name__)
# 把数据文件放在static外,避免静态文件缓存问题
DATA_FILE = os.path.join(app.root_path, 'data', 'family_tree.json')

# 初始化数据目录和空文件
os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True)
if not os.path.exists(DATA_FILE):
    with open(DATA_FILE, 'w', encoding='utf-8') as f:
        json.dump([], f)

# 前端页面路由
@app.route('/')
def index():
    return render_template('index.html')

# 获取家谱数据
@app.route('/api/tree-data', methods=['GET'])
def get_tree_data():
    with open(DATA_FILE, 'r', encoding='utf-8') as f:
        data = json.load(f)
    return jsonify(data)

# 保存/更新家谱数据
@app.route('/api/tree-data', methods=['POST'])
def save_tree_data():
    try:
        update_data = request.get_json()
        # 读取现有数据
        with open(DATA_FILE, 'r', encoding='utf-8') as f:
            existing_data = json.load(f)
        
        # 处理不同操作类型
        if update_data.get('updateNodesData'):
            for node in update_data['updateNodesData']:
                # 按ID覆盖或添加节点
                idx = next((i for i, n in enumerate(existing_data) if n['id'] == node['id']), -1)
                if idx != -1:
                    existing_data[idx] = node
                else:
                    existing_data.append(node)
        elif update_data.get('addNodesData'):
            existing_data.extend(update_data['addNodesData'])
        elif update_data.get('removeNodeId'):
            existing_data = [n for n in existing_data if n['id'] != update_data['removeNodeId']]
        
        # 写入文件
        with open(DATA_FILE, 'w', encoding='utf-8') as f:
            json.dump(existing_data, f, indent=2, ensure_ascii=False)
        
        return jsonify({"status": "success", "data": existing_data})
    except Exception as e:
        return jsonify({"status": "error", "message": str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)

2. 前端修改请求逻辑

把原来的本地文件请求改成调用后端API:

// 替换原有的onUpdateNode逻辑
family.onUpdateNode((args) => {
    fetch('/api/tree-data', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(args)
    })
    .then(response => response.json())
    .then(data => {
        console.log('保存成功:', data);
        // 保存后重新加载数据确保同步
        loadTreeData();
    })
    .catch(error => console.error('保存失败:', error));
});

// 替换原有的数据加载逻辑
async function loadTreeData() {
  try {
    const response = await fetch('/api/tree-data');
    const data = await response.json();
    processData(data);
  } catch (error) {
    console.error("加载数据失败:", error);
  }
}

// 页面加载时初始化
window.addEventListener('DOMContentLoaded', loadTreeData);

三、修复数据加载的去重逻辑

原代码重置ID会破坏节点关联,改为按原ID去重,保留节点间的关系:

// 用原ID作为键去重,保留最新的节点数据
const nodesDictionary = {};

function processData(data) {
  data.forEach(node => {
    const requiredFields = [
      "born", "city", "country", "email",
      "gender", "name", "phone", "photo"
    ];
    // 检查必填字段,同时按ID去重
    const hasAllFields = requiredFields.every(field => node[field] !== undefined);
    if (hasAllFields && node.id) {
      nodesDictionary[node.id] = node;
    }
  });

  const nodesArray = Object.values(nodesDictionary);
  console.log('去重后的节点:', nodesArray);
  family.load(nodesArray);
}

关键注意事项

  • 生产环境建议改用数据库(如SQLite、PostgreSQL)存储数据,JSON文件仅适合小型测试场景
  • 不要随意修改节点ID,否则会丢失家谱中的父子/亲属关联关系
  • 若需要跨设备同步,确保Flask服务部署在公网可访问的服务器上

内容的提问来源于stack exchange,提问作者ThatOneGuyFromCanada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 01:38:11