跳到主要内容
奇点CMS v0.4.72 · 官方网站 登录 / 注册 在线激活

更新日志

版本发布逐版本列出变更说明,站点公告按置顶与时间倒序排列,共 98 条记录;升级前请先阅读对应版本的变更说明与升级步骤。

版本发布 98 条 站点公告 0 条
  • v0.4.49

    云端模型配置成功后自动折叠配置区

    随交付包发布

    需求:"模型配置成功后折叠配置接口"。

    查看完整变更

    需求:"模型配置成功后折叠配置接口"。

    一、改动(admin/workbench.php)

    #内容
    1① 页签的配置卡片改为可折叠:标题右侧一行状态摘要(模型 · 接口地址 · 密钥掩码,若开了自签名会额外标注)+「展开修改 / 收起」按钮
    2已配置 → 默认折叠;未配置 → 始终展开(避免"看不到该填哪里"),并有 JS 守卫强制保证
    3保存成功后自动收起;测试连通成功后自动收起(同时更新徽章与摘要);失败时保持展开,方便直接改配置
    4手动展开/收起会记在本机(localStorage),下次打开按你的选择显示;未配置时仍强制展开
    5折叠态卡片用浅底色区分,摘要里实时显示 模型 · Base URL · 密钥掩码

    二、验证 → 22 / 22 通过

    A. 已配置(当前状态)
       卡片带 wb-cfg collapsed ✓  折叠容器 wb-cfg-body ✓  摘要含模型/地址/密钥掩码 ✓
       按钮为「展开修改」✓  折叠 CSS 规则存在 ✓  页面无 PHP 报错 ✓
    B. 未配置(用密钥快照→清空→渲染→还原,最终配置未被改动)
       卡片**不带** collapsed ✓  按钮为「收起」✓  摘要提示"尚未配置"✓  不显示密钥掩码 ✓  密钥已还原 ✓
    C. JS 行为契约
       setCfgCollapsed / refreshCfgSummary 存在 ✓  localStorage 记忆 ✓
       保存成功自动收起 ✓  连通成功自动收起(失败保持展开)✓  未配置强制展开守卫 ✓  按钮可手动切换并记忆 ✓
    D. 实时 HTTP 渲染:58,874 B,无报错 ✓

    三、效果

    配置好之后,① 页签只剩一行摘要(模型 · 接口 · 密钥 · 状态徽章),面板清爽不占地方; 需要改配置时点「展开修改」,改完保存(或测试连通成功)会再次自动收起。

  • v0.4.48

    修复云端模型接口 TLS 证书校验失败

    随交付包发布

    报错原文:网络错误: SSL certificate problem: self signed certificate in certificate chain(HTTP 0)

    查看完整变更

    报错原文:网络错误: SSL certificate problem: self signed certificate in certificate chain(HTTP 0)

    一、根因:本机 PHP 完全没有 CA 根证书包

    证据结果
    php -i 的 curl.cainfo / openssl.cafile均为空
    PHP 安装目录下 extras/ssl/cacert.pem、cacert.pem、系统 curl-ca-bundle.crt全部不存在
    直接请求 https://api.deepseek.com/v1/models(用无效密钥做 TLS 探测)ssl_verify_result=19 + SSL certificate problem: self signed certificate in certificate chain
    指定一份可用的 CA 包后重试ssl_verify_result=0、HTTP 401(TLS 已通,401 仅因探测密钥无效)

    → OpenSSL 没有信任库,任何 HTTPS 请求都会被判为"自签名证书链",与接口本身无关。

    二、修复

    #内容说明
    1导出 Windows 系统根证书为 PEMCert:\LocalMachine\Root + Cert:\CurrentUser\Root + CA 四个存储 → 87 张根证书,151,635 B。同时兼容"杀软/公司代理做了 HTTPS 拦截"的情况(其拦截根证书正在系统存储里)
    2data/cacert.pem(站点内副本)关键一步:宝塔给本站设了 open_basedir = D:/wwwroot/qdcms/;...,PHP 读不到 PHP 安装目录下的证书包 → 把证书包放进站点目录内即可稳定生效(无需重启 PHP)
    3includes/AiClient.php新增 discoverCaBundle():优先站点内 data/cacert.pem → ini 配置 → PHP 目录 → 系统路径;证书类错误自动带 CA 重试一次;仍失败则输出中文排查指引(含已尝试路径与两条出路);新增 ai_cainfo(显式证书路径)与 ai_allow_insecure(允许自签名,默认关)
    4admin/workbench.php / ajax-workbench.php面板新增「CA 根证书包路径」(留空=自动使用站点内证书包,实时显示实际路径)与「允许自签名证书(有风险)」开关;保存/状态接口同步支持
    5php.ini(站点外)curl.cainfo / openssl.cafile 指向证书包(原为注释状态);重启 PHP 后全局对所有 cURL 生效(面板不依赖它,已即时可用)

    三、验证 → 11 / 11 通过

    A. 自动发现:Web 语境(open_basedir 限制下)命中站点内 data/cacert.pem(87 张)✓  默认不关闭校验 ✓
    B. 证书错误 → 自动带 CA 重试成功 ✓  重试时校验仍开启(cainfo=站点内包, insecure=false)✓
    C. 无可用 CA 时输出中文排查指引(含两条出路)✓
    D. 面板端到端(真实调用你配置的 DeepSeek 接口):
       ★「测试连通」→ 连通正常(模型 deepseek-flash,799ms):ok   ← 你遇到的报错已消失
       ★ 对话试跑 → 正常
       status 返回站点内 CA 包路径 ✓

    四、说明与后续

    • 现在无需任何操作即可用(面板即时生效);
    • 若希望全站所有 HTTPS 调用(不止模型接口)都用上 CA 包:到宝塔面板重启一次 PHP,curl.cainfo 即全局生效;
    • 若将来接口用自签名证书:勾选「允许自签名证书(有风险)」即可,但会关闭服务器证书校验,仅在确知风险时使用。
  • v0.4.47

    工作面板对话框页增加可操作实用工具

    随交付包发布

    需求:"工作面板对话框页增加可操作实用工具"。

    查看完整变更

    需求:"工作面板对话框页增加可操作实用工具"。

    一、对话框页新增三组实用工具

    组位置内容
    快捷指令运维智能体对话框上方6 个一键提问按钮:做一次体检 / 磁盘空间 / 最近报错 / 授权状态 / Go 服务 / 上传活跃度(点击即发送)
    对话工具运维智能体 + Agent 两个对话框清空对话、复制最后回复、导出对话 .md(零依赖实现,兼容无 clipboard 的老内核)
    可执行实用工具运维智能体对话框下方6 个真正会改变站点状态的操作按钮(见下表),点击后二次确认 + 结果回显 + 审计记录

    二、6 个可执行操作(includes/OpsActions.php)

    操作作用安全设计
    清理临时分片目录删除 uploads/tmp_chunks 下超过 2 小时的分片残留活动时间取内部文件 mtime(兼容 Windows 目录 mtime 不可靠),进行中的上传不误删
    清理过期会话文件删除 PHP session 目录下超过 7 天的 sess_*只按年龄阈值删,活跃会话不动(实测保留 140 个活跃会话)
    优化数据表对 8 张核心表执行 OPTIMIZE TABLE只针对白名单表名,无任何前端传入的 SQL
    重置 OPcache清空字节码缓存,改完代码立即生效未启用 OPcache 时明确说明而非报错
    重置授权告警计数清除 data/.license_warnings,解除停机页锁定先备份再删;本次验证后已还原线上原值(保持"10123.vip 继续拦截")
    扫描孤儿上传(仅预览)列出 uploads 中未被数据库引用的文件只列不删;实测发现 5 个孤儿文件(57.7 KB)

    三、安全边界(本次重点验证)

    1. 模型无法调用写操作 —— 写操作与只读工具(OpsTools)严格分离:把 clean_tmp_chunks 交给只读注册表会返回"未知工具",智能体的工具清单里也不含任何写操作;
    2. 必须二次确认 —— 前端 confirm + 服务端 confirm=1 双重校验;未确认时拒绝执行且零副作用(已用测试夹具验证目录仍在);
    3. 白名单 —— 不接受任意动作名、路径、命令、SQL;
    4. 审计日志 —— 每次执行写 data/.ops_actions.log(时间/操作者/动作/结果/IP),面板内可查最近 10 条;不含密钥等敏感信息;
    5. 越权防护 —— 端点仅管理员(401/403)+ CSRF(419),普通用户执行写操作返回 403。

    四、验证 → 33 / 34 通过(唯一未过项为测试自身的计数口径:页面里 .wb-chip 出现 7 次=6 按钮 + 1 处 JS 选择器)

    A. 安全边界:白名单 6 项 / 未知操作被拒 / 未确认被拒且无副作用 / 模型不可调用写操作(3 项断言)✓
    B. 真实执行:临时分片"删过期 1 个、保留进行中 1 个"✓  会话"删过期 1 个、保留活跃 140 个"✓
                 优化 8 张表 ✓  OPcache 重置成功 ✓  孤儿扫描 5 个(只列不删)✓
                 授权告警重置(原 13/8)→ 校验删除与备份 → **已还原原值** ✓
    C. 审计:6 条记录、含操作者、无敏感字段 ✓
    D. 端点/页面:ops_actions 返回 6 操作+审计 ✓  无 confirm 拒绝 ✓  确认后执行 ✓  普通用户 403 ✓
                 页面含 6 个操作按钮、快捷指令、两处对话工具、审计区,且无 PHP 报错 ✓
    业务数据:核心表行数前后一致 ✓

    五、怎么用

    打开「工作面板 → ③ 网站运维工具智能体」:

    • 点 快捷指令 一键提问;点右侧 清空/复制/导出 管理对话;
    • 需要动手时点下方 可执行实用工具(悬停可看说明与预计耗时),确认后立即执行并回显结果;
    • 「最近操作审计」实时显示谁在什么时候做了什么。
  • v0.4.46

    后台新增「工作面板」:云端模型接口 + Agent 智能体 + 网站运维工具智能体

    随交付包发布

    需求:"在网站后台增加一个工作面板,内含云端模型调用接口以及 Agent 智能体,顺便写入网站运维工具智能体"。

    查看完整变更

    需求:"在网站后台增加一个工作面板,内含云端模型调用接口以及 Agent 智能体,顺便写入网站运维工具智能体"。

    一、入口

    后台左侧导航顶层新增「工作面板」(紧随「总览」,admin/workbench.php),三个页签:

    页签能力
    ① 云端模型调用接口配置 Base URL / API Key / 模型名 / 超时 / 温度;保存(密钥留空=不修改,页面只显示掩码)、测试连通(真实调用一次并给出结论)、对话试跑
    ② Agent 智能体编辑系统提示词(人设/规则)、工具调用最大步数;保存 + 对话试跑
    ③ 网站运维工具智能体10 个只读运维工具(可逐个运行)+ 自然语言问答 + 一键体检(Markdown 报告,可复制/下载)

    二、新增文件与实现要点

    文件说明
    includes/AiClient.phpOpenAI 兼容客户端:任何兼容端点(DeepSeek/通义/智谱/Moonshot/OpenRouter/自建 vLLM、Ollama)只填 base_url+key+model 即可;传输层可注入(便于离线单测);错误按 401/403/404/429/非 JSON/空内容分类给中文提示;密钥仅存服务端并掩码显示
    includes/OpsTools.php10 个只读运维工具:站点连通性、磁盘与上传占用、数据库统计、PHP 运行环境、错误日志、授权状态、Go 服务心跳、待处理积压、上传活跃度、安全体检。统一返回 {ok,level,title,summary,data,hints,ms};一键体检生成 Markdown 报告
    includes/OpsAgent.php运维工具智能体:模型模式(把工具清单交给模型,模型以 JSON 请求工具 → 服务端执行 → 回喂 → 收口,最多 N 步)+ 规则模式(无密钥也能用:关键词命中工具);模型失败自动降级;容忍模型输出的 markdown 代码块/杂字符
    admin/workbench.php三页签面板(原生 PHP + 内联 JS,无外部依赖)
    admin/ajax-workbench.php9 个动作:status / model_save / model_test / model_chat / agent_save / agent_chat / ops_run / ops_chat / ops_checkup;仅管理员(401/403)+ CSRF(419)
    admin/header.php顶层导航新增「工作面板」

    安全设计:运维工具全部只读(不写库、不删文件、不改配置);不接受任意 SQL/命令/路径;密钥不回传前端。

    三、验证 → A~C 57 项 + D/E/F 22 项,全绿

    A. AiClient(桩传输,不打真实网络)
       endpoint 拼接 / 已含路径不重复拼接 / 请求体(model,messages,stream=false,temperature) / Bearer 鉴权头
       响应解析(choices[0].message.content + usage) / 密钥掩码 / 未配置提示
       错误映射:401 密钥无效、404 地址或模型名不存在、429 限流、非 JSON 响应、空内容、传输异常被捕获
       消息规范化 / 连通性测试 / saveSettings 校验(非法地址拒绝、超时夹到 300、温度夹到 2) / 配置已还原
    B. OpsTools(真实数据、只读)
       10 个工具全部运行成功:磁盘使用 5.3%(118GB/剩余 111.78GB)、uploads 84.2MB、PHP 8.0.28 扩展齐备、
       授权告警 13/8、Go 服务心跳 3 秒前(端口 8080 HTTP 200)、最近 24h 上传 64 个文件、安全体检发现 2 项
       体检报告 Markdown 生成 / 未知工具被拒 / **核心表行数前后一致(只读性得到验证)**
    C. OpsAgent
       规则模式:磁盘→disk_usage、报错→recent_errors、授权→license_status、上传→uploads_recent 全部命中
       「做一次站点体检」→ 直接跑 7 项体检(跳过模型)
       模型模式:桩模型请求工具 → 执行 disk_usage → 回喂 → `{"final":...}` 收口(共 2 次模型调用)
       容错:非法 JSON 自动纠正重试;步数用尽优雅收口;模型失败自动降级规则模式
    D/E. 页面与端点
       管理员 200、三页签、10 个工具卡片、导航入口、页面无 PHP 报错;普通用户 302 跳登录
       端点:未登录 401 / 普通用户 403 / CSRF 错误 419 / 未知动作 404
       status 返回 10 个工具;ops_run 成功;ops_checkup 返回报告(level=error,正常 5 注意 1 异常 1);
       model_test 未配置时给出明确中文提示(不 500)
    F. 本轮修掉的真实缺陷
       ① go_service 曾显示"心跳 497677 小时前"——Go 服务写的是 epoch 字段,原代码读了 ISO 字符串 ts;
          已改为 epoch 优先 + 兼容毫秒/ISO/文件 mtime,现正确显示"心跳 3 秒前"
       ② recent_errors 的 5xx 统计曾在 CSRF token 里误匹配,**假阳性 243/300**;现只认状态码字段 → 0/512
       ③ 访问日志分支不再重复列出 *.error.log;磁盘信息增加 PowerShell 兜底(原账户下 disk_free_space 不可用)

    四、怎么用

    1. 后台左侧「工作面板」→ 页签①填 Base URL / API Key / 模型名 → 保存 → 测试连通;
    2. 页签②按需改系统提示词与步数;
    3. 页签③直接问"磁盘还剩多少?""最近有报错吗?""做一次站点体检",或点工具卡片上的运行;
    4. 未配置模型也能用:运维工具智能体会走关键词规则模式,体检报告照常生成。
  • v0.4.45

    PC 端个人主页增加「退出登录」按钮

    随交付包发布

    需求:"给 PC 端个人主页增加一个退出按钮"。

    查看完整变更

    需求:"给 PC 端个人主页增加一个退出按钮"。

    一、为什么之前 PC 端退不了

    全站唯一的「退出登录」入口在 includes/header.php 的移动端下拉菜单里 (<a href="logout.php" class="nav-link-dropdown">退出登录</a>,容器 .main-nav-dropdown 仅在窄屏显示) → PC 端打开个人主页时确实没有任何退出按钮。

    二、改动(仅 profile.php)

    #内容
    1顶部名片操作区新增按钮:编辑资料 → 管理后台(管理员)→ 退出登录,跳 logout.php(沿用原有退出逻辑,未新造接口)
    2新按钮加二次确认:确定要退出登录吗?,避免误点直接掉线
    3样式 .profile-logout-btn:危险色描边,默认透明底、悬停填充红色,与「编辑资料」明确区分;操作区本身已有 flex-wrap: wrap,窄屏自动换行不挤压

    三、验证 → 15 / 15 通过

    渲染检查(登录态真实请求 profile.php)
      HTTP 200 ✓  操作区存在 ✓  含「退出登录」→ logout.php ✓  带二次确认 ✓
      使用 profile-logout-btn 样式 ✓  原「编辑资料」保留 ✓  页面含样式规则 ✓
      顺序正确(编辑资料 → 管理后台 → 退出登录)✓  窄屏可换行 ✓
    退出流程(独立测试会话,不影响任何人登录态)
      logout.php → 302 → index.php ✓
      退出后再访问 profile.php → 302 → login.php(会话已失效)✓
      服务端会话数据已清空/销毁 ✓
    未登录访问个人主页 → 跳登录页 ✓

    四、效果

    • PC 端个人主页一眼可见「退出登录」,点一下(确认后)即退出并回到首页;
    • 移动端行为不变(下拉菜单入口仍可用);未登录用户看不到该按钮(个人主页会先跳登录页)。
  • v0.4.44

    授权告警看门狗:在"锁定"之前先提醒你

    随交付包发布

    背景:你选择保持拦截 10123.vip(不加入白名单)。该域名的访问会持续计入

    查看完整变更

    背景:你选择保持拦截 10123.vip(不加入白名单)。该域名的访问会持续计入 "5 天 8 次"计数,达到 8 次后用未授权域名访问的访客会看到 403 停机页。

    一、本次新增

    #交付物说明
    1qdcms-license-watch.ps1(新增,站点根目录 + 交付包)监控 data/.license_warnings 计数,按 0~2 / 3~4 / 5~6 / 7 / ≥8 分级输出,退出码 0/1/2/3/4 便于接计划任务;只提醒不自动清除(保持授权策略不被削弱);-Clear 可人工复位(先自动备份);日志写入 data/.license_watch.log
    2措辞与说明修正明确"锁定只影响未授权域名访客;自有域名与内网/本机访问始终正常""

    二、实测结论(本次核验)

    访问方式结果
    10123.vip(未授权域名,端口 65500)HTTP 403 + 停机维护页 ← 符合作者拦截意图
    10123.xn--fiqs8s(授权域名,端口 65500)HTTP 200 正常完整页面
    192.168.0.100(局域网 IP)HTTP 200 正常完整页面
    127.0.0.1(本机)HTTP 200 正常完整页面

    当前计数状态:9 / 8(窗口起始 2026-10-10 20:32:50,约 5 天后自动重置) → 未授权域名访客会看到停机页(你的选择),你自己的域名与内网访问不受任何影响。

    三、日常用法

    # 查看当前状态(退出码 0/1/2/3/4 分级)
    powershell -ExecutionPolicy Bypass -File qdcms-license-watch.ps1 -ListDomains
    
    # 确认是误访/爬虫后,人工复位计数(会自动备份原值)
    powershell -ExecutionPolicy Bypass -File qdcms-license-watch.ps1 -Clear
  • v0.4.43

    商业授权:增加本地局域网 IP

    随交付包发布

    需求:"给网站域名商业授权增加本地局域网 ip 地址"。

    查看完整变更

    需求:"给网站域名商业授权增加本地局域网 ip 地址"。

    一、改动

    #位置改动
    1data/.license_allow(授权白名单)显式加入 192.168.0.100、192.168.0.(前缀,覆盖 192.168.0.1~254,应对 DHCP 变动)、127.0.0.1、localhost
    2includes/LicenseManager.phpisLocalHost() 支持 IP 前缀形式的白名单条目(如 192.168.0.)。仅当整串确为合法 IPv4 时才做前缀匹配,因此 192.168.0.100.evil.com 这类主机不会被误放行
    3nginx vhost 10123.xn--fiqs8s.confserver_name 追加内网网段正则 ~^192\.168\.\d+\.\d+$、~^10\.…$、~^172\.(16-31)\.…$ —— 否则换一台内网设备(如 192.168.0.101)时请求会落到宝塔默认站(只返回 612 B 页面)。nginx -t 校验通过,需在宝塔点一次「重载配置」生效
    4data/.license_warnings(运维修复)原计数 268 / 8 且域名为 10123.vip。按现有守卫逻辑,count>=8 会对所有访客输出停机页 —— 属于"一次误访即全站锁死"的高危状态。已备份后重置为干净状态(备份:D:\BtSoft\backup\qdcms-license\license_warnings.bak)

    说明:授权状态本身未变 —— 绑定域名仍为 10123.xn--fiqs8s(10123.中国),本次只是扩充白名单。

    二、验证(真实 HTTP + 判定矩阵)→ 31 / 32 通过(唯一未过项见下)

    放行矩阵(14/14 通过):192.168.0.100、192.168.0.100:65500、192.168.0.1/254、192.168.5.9、
                            127.0.0.1、127.0.0.1:80、10.0.0.7、172.16.5.9、172.31.255.1、169.254.1.1、
                            localhost、localhost:65500、::1
    拦截矩阵(6/6 通过):10123.vip、evil.com、192.168.0.100.evil.com、192.16.0.100、11.0.0.1、172.32.0.1
    checkDomain:192.168.0.100 / 127.0.0.1 / localhost → 有效(本地或白名单访问)
                 10123.vip → 仍无效(**授权守卫未被削弱**)
    真实 HTTP:Host 192.168.0.100 / 192.168.0.100:65500 / 127.0.0.1 → 200 + 完整首页 38,722 B + 无告警
               **内网访问没有产生任何告警计数** ✓(关键验收)
               陌生域名(10123.vip:65500)→ 正常计数并弹窗(守卫仍生效),验证后已复位计数
    未过项:Host 192.168.5.9 在**改动前**的旧 vhost 下仍落到默认站(612 B)—— 本次已通过 nginx 正则
            server_name 解决,待重载配置后生效

    三、你需要做的

    1. 无需重启 PHP;授权白名单改动立即生效。
    2. 让「整个局域网网段」都能直接访问:宝塔 → 网站 → 设置 → 重载配置(或 Nginx 重载)。仅此一步需要你点。
  • v0.4.42

    修复聊天发送视频后气泡消失 / 回显缓慢或看不到

    随交付包发布

    现象:聊天里发送视频,上传成功后气泡消失,视频要过一会儿才回来(有时一直不出现)。

    查看完整变更

    现象:聊天里发送视频,上传成功后气泡消失,视频要过一会儿才回来(有时一直不出现)。

    一、根因:接口响应没返回新消息 id

    环节问题
    includes/fn-message.php sendChatMessage()插入后只 return true,不返回自增 id
    ajax-chat-send.php 响应 message{}只有 sender/content/media 等字段,没有 id
    assets/im-plugin/modules/chat.js 发送回调需要 real.id 才做"原地替换乐观气泡";缺 id 时走 else 分支 → 直接 removeChild 删除气泡,然后等 4 秒轮询把消息拉回来

    → 于是出现:"上传 100% → 气泡消失 → 视频过几秒才回来(轮询错过就一直不回来)"。 实测服务端处理仅 0.65 秒,慢的完全是前端等轮询。

    二、修复

    #文件改动
    1includes/fn-message.phpsendChatMessage() 改用 db()->insert() 并返回自增 id(拿不到时回退 true,旧调用方不受影响)
    2ajax-chat-send.php响应 message 补 id、is_read、file_size、sender_avatar(id 兜底再查 LAST_INSERT_ID())
    3assets/im-plugin/modules/chat.js兜底不再删气泡:响应缺 id 时保留乐观气泡并显示"已发送,正在同步…",同时重置加载锁并主动 _loadMessages() 拉回真实消息

    三、验证

    A. 真实发送聊天视频(真实 HTTP + FFmpeg 视频)→ 全通过

    发送耗时 0.65s,响应带 "id":287 ✓
    数据库存在该消息 ✓  media_type=video ✓  收发方正确 ✓
    库中 media_url 与响应一致 ✓   视频文件落盘且 HTTP 可访问 ✓   封面存在 ✓
    测试消息与文件已清理 ✓

    B. 前端分支(Node + DOM/XHR 桩,跑真实 chat.js)→ 12 / 12 通过

    带 id:气泡被**原地替换**(outerHTML)✓  未删除气泡 ✓  替换内容含真实地址与 data-msg-id=287 ✓
            不触发多余的整体拉取 ✓
    缺 id:**不删气泡** ✓  气泡仍在消息区 ✓  显示"已发送,正在同步…" ✓  主动拉回真实消息 ✓
    失败响应:气泡保留(可重试)✓

    四、效果

    • 发送视频/图片成功后,气泡当场变成真实消息(含真实地址与 data-msg-id),无需等 4 秒轮询;
    • 即使接口异常缺 id,气泡也不再消失,而是自动补拉真实消息;
    • 顺带修正:data-msg-id 之前是 undefined(缺 id 导致),现在正确 → 媒体缓存/播放进度记录恢复正常。
  • v0.4.41

    优化聊天插件"发送方视频气泡过宽"

    随交付包发布

    需求:"优化聊天插件发送方视频气泡显示过宽的问题"。

    查看完整变更

    需求:"优化聊天插件发送方视频气泡显示过宽的问题"。

    一、根因(三点叠加)

    #问题后果
    1视频只约束 max-width: 240px / max-height: 180px,其余交给 <video> 的固有尺寸竖屏手机视频(如 1080×1920)在聊天里仍占很大一块;配合 12px 文字内边距,绿气泡比视频还宽一圈
    2媒体气泡沿用文字内边距 padding: 8px 12px气泡四周多出 24px 空白,观感"过宽"
    3气泡是普通 block、包裹层没有 min-width: 0当"时间/已读"那一行比视频宽时,气泡会被横向撑开(这就是"发送方视频气泡过宽"最直接的来源)

    二、修复

    #文件改动
    1assets/im-plugin/modules/chat.js消息结构:包裹层加 .msg-body;媒体消息(图片/视频,含流式地址与付费墙分支)气泡加 .media 类 → 内边距 4px;文案消息完全不受影响
    2assets/im-plugin/styles/im-modules.css① .msg-body { min-width: 0 }(允许收缩,不再撑破 80% 上限);② .msg-bubble { width: fit-content }(气泡紧贴内容,不再被时间行撑宽);③ .msg-bubble.media { padding: 4px; line-height: 0 };④ 视频尺寸改为 max-width: 200px; max-height: 260px(横屏 200×112、竖屏 146×260、方形 200×200);⑤ 图片同步为 200×200;⑥ 新增 @media (max-width: 480px):视频 168×220、图片 168×168
    3assets/js/tab-card.jsIM_BUILD 递增(20261002-10 → 20261002-11)强制刷新插件资源缓存

    尺寸推算(修复后)

    视频形态修复前气泡宽修复后气泡宽
    竖屏 1080×1920240 + 24 = 264px146 + 8 = 154px
    横屏 1920×1080240 + 24 = 264px200 + 8 = 208px
    小屏(≤480px)竖屏264px132px(124 + 8)

    三、验证(Node + DOM 桩,真实渲染函数 + 真实 CSS)→ 30 / 30 通过

    发送方视频:气泡带 .media、包裹层带 .msg-body、video 无内联 width:100%  ✓
    接收方视频 / 流式地址分支 / 付费墙分支:同样带 .media,已读回执与付费按钮保留 ✓
    图片消息:带 .media ✓     文案消息:不带 .media(内边距不变)✓
    CSS:media 内边距 4px ✓  msg-body min-width:0 ✓  fit-content ✓  视频 200×260 ✓
         旧 240px 规则已移除 ✓  图片 200×200 ✓  小屏 168×220 / 168×168 ✓  花括号配平 ✓
    尺寸推算:竖屏 146×260 ✓  横屏 200×112 ✓  方形 200×200 ✓  小屏竖屏 124×220 ✓

    四、效果

    • 发送方(也含接收方)视频气泡只比视频大 8px,不再有 24px 空白;
    • 竖屏视频宽度约为屏幕的 40%(旧实现约 73%),聊天区观感与微信一致;
    • 小屏再自动收一档;文案消息、已读回执、付费按钮、播放进度缓存等行为全部不变。
  • v0.4.40

    新增视频分片上传:彻底规避 504 网关超时

    随交付包发布

    现象:手机经域名上传短视频时报 服务器返回异常(HTTP 504)。

    查看完整变更

    现象:手机经域名上传短视频时报 服务器返回异常(HTTP 504)。

    一、定位:504 不是本机 nginx 打的

    证据结论
    本机 nginx 访问日志 504 计数 = 0504 来自链路更前面的网关/代理层
    18:43:04 那次上传在本机被记为 499(客户端主动断开)前面那层先超时并向浏览器返回 504,然后断开与本站的连接 —— 两边现象完全吻合
    本站 fastcgi_read_timeout = 900s(上传走 FastCGI)、proxy_read_timeout 60s 只作用于 SSE 反代本机不是瓶颈;域名前置那层超时值我无法从本站修改
    该次上传最终成功(18:43:08 发布 id=21,日志 已转换为 MP4:video/quicktime(remux))服务端处理仅约 23 秒 → 拖垮请求的是单请求上传时长(手机弱网上传几分钟)

    根因:单请求上传大文件要持续几十秒到数分钟,链路上任意一层网关超时都会 504。 治本方案:把大文件切成 ≤4MB 分片,每个请求都在几秒内完成 → 免疫任何网关超时。

    二、本次改动

    #文件改动
    1ajax-upload-chunk.php(新增)分片端点:登录 + CSRF 校验;upload_id(32hex)/index/total(1~500)/name/chunk(≤4MB);逐片落盘、到齐后流式合并为 merged.bin 并返回 token;含 200MB 总量上限、2 小时过期自动清理(GC 以内部文件时间为准,兼容 Windows 目录 mtime 不可靠)
    2post-video.php支持 upload_token 发布:分片合并完成后只发表单字段(不再携带文件)→ 秒级返回;发布后自动清理分片目录
    3includes/fn-upload.php新增 moveUploadedOrLocal():真实上传走 move_uploaded_file,分片合并文件走 rename/copy(仅允许 uploads/tmp_chunks/ 内的文件,防止被当作任意文件搬运)
    4includes/fn-moments.php改用该助手;finfo 返回 application/octet-stream 等泛型类型时按扩展名判定(仍走同一白名单,安全不变)
    5assets/js/upload-progress.js新增 QdUpload.uploadChunked():4MB 分片、串行上传、单片失败自动重试 2 次、逐片汇总进度
    6post-video.php 内联脚本>4MB 自动走分片(进度条显示"分片 x/y"),≤4MB 仍走原来的单请求;分片失败时保留可重试状态

    三、验证

    A. 分片端点端到端(真实 HTTP + 真实 FFmpeg 视频) → 全通过:

    3 片逐片上传 → received 1/2/3 → done:true + token
    合并文件 sha256 与源文件**完全一致** ✓   分片文件已自动清理 ✓
    凭 upload_token 发布 → {"success":true,"moment_id":"22"} ✓
    落盘 uploads/moments/2026/10/moment_v_*.mp4(大小与源一致)✓   临时目录已清理 ✓
    边界:非法 upload_id / CSRF 错误 / 越界 index / 单片 >4MB  → 全部正确拒绝 ✓
    GC:把过期目录的内部文件时间设为 3 小时前 → 下一次请求自动清除 ✓

    B. 渲染与语法:页面含分片分支与 upload_token、仍正确引入进度脚本、内联 JS node --check 通过 ✓ C. 数据卫生:测试动态/媒体/分类/临时目录全部清理(moments 17 条 = 用户真实发布 ✓)

    四、效果

    • 手机经域名上传 → 每片几秒完成,不会再出现 504;进度条按分片推进(第 x/y 片);
    • 分片失败自动重试 2 次;全部分片合并后才进入"服务器处理中(转码/截图)"阶段;
    • 小文件(≤4MB)行为与之前完全一致,无额外请求。

    五、附:可选的更彻底做法

    若希望连"上传"这一步都完全不经过域名链路,可让手机在局域网直接访问 http://192.168.0.100/post-video.php(同 WiFi 时最快,且完全绕开前置网关)。

第 3 / 10 页 · 每页 10 条 · 共 98 条

升级前请确认

  1. 备份

    备份站点目录与数据库,尤其是 uploads/ 与 config/。

  2. 阅读说明

    在 docs/版本升级说明.md 中找到对应版本,确认是否需要执行数据库迁移。

  3. 执行升级

    解压覆盖站点目录 → 执行 migration → 后台「系统 → 在线更新」复核版本状态。

  4. 复核功能

    检查前台首页、播放、支付与后台工作面板等关键入口是否正常。

相关入口

站点公告 官网试运行中,如需购买或试用请通过「联系我们」留言。