300 积分悬赏:JS 代码读取数据库,弹出窗口(已经实现一半)

需求:

  1. 选择指定数据库 ID
  2. 选择数据库指定视图
  3. 只提取该视图,筛选后的内容
  4. 按照该视图的排序方式,弹出弹窗表格进行排序(就是视图怎么筛选、怎么排的,弹出表格就是什么样)
  5. 弹出指定时间段列,根据:现在时间、文字时间、间隔时间 20 分钟,进行计算时间段(主要想要这个)
    比如:现在时间 8:00
    1. 测试 1,文字时间 30,时间段 8:00-8:30
    2. 测试 2,文字时间 15,时间段:8:50-9:05(加上了间隔时间 20、测试 1 文字时间 30)
    3. 测试 3,文字时间 20,时间段:9:25-9:45(加上了间隔时间 20、测试 2 文字时间 15)
    4. ......

我现在已经实现大部分功能,可以读取弹出,但总是列与列对不上

由于是读取整个数据库的内容,再进行排序,出错问题很大

本意是直接想要读取,数据库本身的排序、筛选

下面是我用 AI 跑的,有问题,请参考

image.png

/*
【注意事项】
- 排序为【字符串排序】,不是数字排序
- 仅读取:主键列 / 文本列 / 单选列
- 不读取多选列
- 时间段:第一行不加20分钟,其余行才加
- 双击表格任意位置关闭
*/

setTimeout(() => {
  if (typeof openAny === 'undefined' || !openAny?.invoke) {
    console.error('openAny API 未找到,确保在正确环境下运行');
    return;
  }

  openAny.invoke(({ onProtyleLoad }) => {
    onProtyleLoad(protyle => {
      if (protyle?.querySelector('[data-type="StressThreshold"]')) return;

      const anchor = protyle.querySelector('.protyle-breadcrumb [data-type="exit-focus"]');
      if (!anchor) return;

      anchor.insertAdjacentHTML(
        'afterend',
        `<button data-type="StressThreshold"
          class="block__icon fn__flex-center"
          style="font-size:18px; user-select:none;">✅</button>`
      );

      const btn = protyle.querySelector('[data-type="StressThreshold"]');
      if (!btn) return;

      /* ================= 配置区 ================= */
      const config = {
        blockId: '20251214023356-0f1cxwc', // 数据库块ID
        sortByColumn: '排序',              // 主键列(字符串排序)
        sortOrder: 'desc',                 // asc / desc
        maxRows: 6,                       // 最多显示行数
        startTimeStr: 'now',              // now 或 H:M
        extraMinutes: 20,                 // 行间额外分钟(第一行不加)
        headers: ['排序', 'DO', '预计分钟', '时间段']
      };
      /* ========================================== */

      let clickTimer = null;
      const CLICK_DELAY = 260;

      btn.addEventListener('click', () => {
        if (clickTimer) return; // 防止连续点击乱触发
        clickTimer = setTimeout(() => {
          showPopup(config).catch(e => {
            console.error('显示弹窗出错:', e);
          });
          clickTimer = null;
        }, CLICK_DELAY);
      });

      btn.addEventListener('dblclick', () => {
        if (clickTimer) {
          clearTimeout(clickTimer);
          clickTimer = null;
        }
        try {
          openAny.press && openAny.press('Alt+3');
        } catch (e) {
          console.warn('openAny.press 调用失败:', e);
        }
        try {
          openAny.click && openAny.click('[data-id="20251109153938-zrdgcag"]');
        } catch (e) {
          console.warn('openAny.click 调用失败:', e);
        }
      });

      async function showPopup(config) {
        const isMobile = window.innerWidth <= 768;

        function toMinutes(t) {
          if (t === 'now') {
            const d = new Date();
            return d.getHours() * 60 + d.getMinutes();
          }
          const [h, m] = t.split(':').map(Number);
          return h * 60 + m;
        }

        function toHM(m) {
          return `${Math.floor(m / 60)}:${String(m % 60).padStart(2, '0')}`;
        }

        async function loadDB(id) {
          try {
            const r = await fetch('/api/query/sql', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ stmt: `SELECT markdown FROM blocks WHERE id='${id}'` })
            });
            const j = await r.json();
            if (!j.data || j.data.length === 0) return null;
            const markdown = j.data[0]?.markdown || '';
            const avId = markdown.match(/data-av-id="([^"]+)"/)?.[1];
            if (!avId) return null;

            const r2 = await fetch('/api/file/getFile', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ path: `/data/storage/av/${avId}.json` })
            });
            return await r2.json();
          } catch (e) {
            console.error('loadDB 异常:', e);
            return null;
          }
        }

        const parseVal = v => {
          if (!v) return '';
          if (v.block?.content) return String(v.block.content);
          if (v.text?.content) return String(v.text.content);
          if (v.mSelect?.[0]) return String(v.mSelect[0].content);
          return '';
        };

        const buildRows = av => {
          if (!av || !av.keyValues || !Array.isArray(av.keyValues)) return [];
          const allCols = av.keyValues.map(k => k.key?.name || '');
          const len = av.keyValues[0]?.values?.length || 0;

          const fullRows = [];
          for (let i = 0; i < len; i++) {
            const row = {};
            allCols.forEach((col, idx) => {
              row[col] = parseVal(av.keyValues[idx]?.values?.[i]);
            });
            fullRows.push(row);
          }

          return fullRows.map(r => {
            const filtered = {};
            config.headers.forEach(h => {
              filtered[h] = r[h] || '';
            });
            return filtered;
          });
        };

        function process(rows) {
          rows.sort((a, b) => {
            const x = a[config.sortByColumn] || '';
            const y = b[config.sortByColumn] || '';
            return config.sortOrder === 'asc' ? x.localeCompare(y) : y.localeCompare(x);
          });

          let currentStart = toMinutes(config.startTimeStr);

          return rows.slice(0, config.maxRows).map((row, index) => {
            if (index > 0) currentStart += config.extraMinutes;

            const duration = Number(row['预计分钟']) || 0;
            const start = currentStart;
            const end = start + duration;

            row['时间段'] = `${toHM(start)}-${toHM(end)}`;
            currentStart = end;

            return row;
          });
        }

        function render(data) {
          const box = document.createElement('div');
          box.style.cssText = `
            position:fixed;top:50%;left:50%;
            transform:translate(-50%,-50%);
            background:#fff;z-index:999999;
            border-radius:${isMobile ? 10 : 12}px;
            padding:${isMobile ? 12 : 18}px;
            max-height:80vh;overflow:auto;
            width:${isMobile ? '90vw' : '620px'};
            box-shadow:0 6px 20px rgba(0,0,0,.25);
          `;

          box.ondblclick = () => box.remove();

          const table = document.createElement('table');
          table.style.width = '100%';
          table.style.borderCollapse = 'collapse';

          table.innerHTML = `
            <thead>
              <tr>${config.headers.map(h =>
                `<th style="border-bottom:2px solid #ddd;padding:8px">${h}</th>`).join('')}
              </tr>
            </thead>
            <tbody>
              ${data.map(r =>
                `<tr>${config.headers.map(h =>
                  `<td style="border-bottom:1px solid #eee;padding:6px">${r[h] || ''}</td>`).join('')}
                </tr>`).join('')}
            </tbody>
          `;

          box.appendChild(table);
          document.body.appendChild(box);
        }

        const av = await loadDB(config.blockId);
        if (!av) {
          console.error('数据库数据为空或加载失败');
          return;
        }

        render(process(buildRows(av)));
      }
    });
  });
}, 1400);

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    28446 引用 • 119783 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    11155 引用 • 50664 回帖 • 52 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    215 引用 • 358 回帖
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4602 回帖 • 731 关注
  • 电影

    这是一个不能说的秘密。

    125 引用 • 610 回帖
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    695 引用 • 538 回帖 • 1 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 2 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 693 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 633 关注
  • Sillot

    Insights(注意当前设置 master 为默认分支)

    汐洛彖夲肜矩阵(Sillot T☳Converbenk Matrix),致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点。其中汐洛绞架(Sillot-Gibbet)基于自思源笔记(siyuan-note),前身是思源笔记汐洛版(更早是思源笔记汐洛分支),是智慧新录乄终端(多端融合,移动端优先)。

    主仓库地址:Hi-Windom/Sillot

    文档地址:sillot.db.sc.cn

    注意事项:

    1. ⚠️ 汐洛仍在早期开发阶段,尚不稳定
    2. ⚠️ 汐洛并非面向普通用户设计,使用前请了解风险
    3. ⚠️ 汐洛绞架基于思源笔记,开发者尽最大努力与思源笔记保持兼容,但无法实现 100% 兼容
    29 引用 • 25 回帖 • 152 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 443 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 702 关注
  • 千千插件

    千千块(自定义块 css 和 js)
    可以用 ai 提示词来无限创作思源笔记

    32 引用 • 69 回帖
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 646 关注
  • 博客

    记录并分享人生的经历。

    274 引用 • 2393 回帖 • 1 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 494 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 436 关注
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    99 引用 • 367 回帖 • 1 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 577 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 46 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 838 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 3 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    950 引用 • 1460 回帖 • 2 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 768 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    40 引用 • 157 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    5 引用 • 16 回帖 • 3 关注