表格和数据库联动

表格和数据库联动

see https://ld246.com/article/1741622377103

//!js

// 数据库块id
const avBlockId = '20250311063435-9066xpv';

// 表格块id
const tableBlockId = '20250311063452-p03kxva';

// 数据库变更后自动更新延迟,单位是毫秒,默认是1秒,0则不自动更新
// 注意:更新该参数后需要刷新页面才能生效
const autoFreshDelay = 1000;

// 监听数据库变化
observeAvChange();

return query(
    "select * from ?",
    [fromAv(avBlockId), item],
    '',
    ({ rawData, updateTable, renderSuccess }) => {
        let tableData = transformData(rawData);
        tableData = toMarkdownTable(tableData);
        updateTable(tableBlockId, tableData);
        return renderSuccess('更新完成', item);
    }
);

function toMarkdownTable(data) {
    // 提取所有列名(包括空列 "")
    const columns = Array.from(
        data.reduce((set, row) => {
            Object.keys(row).forEach(key => set.add(key));
            return set;
        }, new Set())
    ).sort((a, b) => (a === "" ? -1 : a.localeCompare(b))); // 确保空列 "" 在最前面

    // 构造表头行
    const headerRow = `| ${columns.map(col => (col === "" ? "" : col)).join(" | ")} |`;

    // 构造分隔符行
    const separatorRow = `| ${columns.map(() => "---").join(" | ")} |`;

    // 构造数据行
    const dataRows = data.map(row => {
        return `| ${columns.map(col => row[col] || "").join(" | ")} |`;
    });

    // 拼接所有部分
    return [headerRow, separatorRow, ...dataRows].join("\n");
}

function transformData(input) {
    // 创建一个 Map 来按横坐标分组
    const groupedData = new Map();

    // 遍历输入数组,按横坐标分组
    input.forEach(item => {
        const { 主键, 横坐标, 纵坐标 } = item;

        // 如果横坐标不存在于 Map 中,则初始化
        if (!groupedData.has(横坐标)) {
            groupedData.set(横坐标, { "": 横坐标 });
        }

        // 将纵坐标和主键添加到对应的横坐标分组中
        groupedData.get(横坐标)[纵坐标] = 主键;
    });

    // 将 Map 转换为数组并返回
    return Array.from(groupedData.values());
}

function observeAvChange() {
    // 监听av变化,当数据库块被修改时,重新获取数据
    if(autoFreshDelay > 0 && !window['__table_observe__' + avBlockId]) {
        window['__table_observe__' + avBlockId] = observeDOMChanges(document.querySelector('div[data-node-id="'+avBlockId+'"]'), ()=>{
            setTimeout(() => {
                item.querySelector('.protyle-action__reload').click();
            }, 100);
        }, autoFreshDelay, {attributes: false});
    }
}

// 监听dom变化
function observeDOMChanges(targetNode, callback, debounceTime = 1000, options = {}) {
    // 默认配置
    const defaultOptions = {
      attributes: true,
      childList: true,
      subtree: true,
    };

    // 合并默认配置与传入的配置
    const config = Object.assign({}, defaultOptions, options);

    // 创建一个观察器实例
    const observer = new MutationObserver((mutationsList) => {
        // 使用防抖函数确保单位时间内最多只调用一次回调
        if(window['__table_observeTimer__' + avBlockId]) {
            clearTimeout(window['__table_observeTimer__' + avBlockId]);
        }
        window['__table_observeTimer__' + avBlockId] = setTimeout(() => {
            // 处理变化
            callback(mutationsList);
        }, debounceTime);
    });

    // 开始观察目标节点
    observer.observe(targetNode, config);

    // 返回一个函数,以便在不需要时能够停止观察
    return () => {
      observer.disconnect();
    };
}

image

image.png

留下你的脚步
推荐阅读