更新日志
版本发布逐版本列出变更说明,站点公告按置顶与时间倒序排列,共 98 条记录;升级前请先阅读对应版本的变更说明与升级步骤。
-
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 系统根证书为 PEM Cert:\LocalMachine\Root+Cert:\CurrentUser\Root+CA四个存储 → 87 张根证书,151,635 B。同时兼容"杀软/公司代理做了 HTTPS 拦截"的情况(其拦截根证书正在系统存储里)2 data/cacert.pem(站点内副本)关键一步:宝塔给本站设了 open_basedir = D:/wwwroot/qdcms/;...,PHP 读不到 PHP 安装目录下的证书包 → 把证书包放进站点目录内即可稳定生效(无需重启 PHP)3 includes/AiClient.php新增 discoverCaBundle():优先站点内data/cacert.pem→ ini 配置 → PHP 目录 → 系统路径;证书类错误自动带 CA 重试一次;仍失败则输出中文排查指引(含已尝试路径与两条出路);新增ai_cainfo(显式证书路径)与ai_allow_insecure(允许自签名,默认关)4 admin/workbench.php/ajax-workbench.php面板新增「CA 根证书包路径」(留空=自动使用站点内证书包,实时显示实际路径)与「允许自签名证书(有风险)」开关;保存/状态接口同步支持 5 php.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) 三、安全边界(本次重点验证)
- 模型无法调用写操作 —— 写操作与只读工具(
OpsTools)严格分离:把clean_tmp_chunks交给只读注册表会返回"未知工具",智能体的工具清单里也不含任何写操作; - 必须二次确认 —— 前端
confirm+ 服务端confirm=1双重校验;未确认时拒绝执行且零副作用(已用测试夹具验证目录仍在); - 白名单 —— 不接受任意动作名、路径、命令、SQL;
- 审计日志 —— 每次执行写
data/.ops_actions.log(时间/操作者/动作/结果/IP),面板内可查最近 10 条;不含密钥等敏感信息; - 越权防护 —— 端点仅管理员(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 不可用)四、怎么用
- 后台左侧「工作面板」→ 页签①填 Base URL / API Key / 模型名 → 保存 → 测试连通;
- 页签②按需改系统提示词与步数;
- 页签③直接问"磁盘还剩多少?""最近有报错吗?""做一次站点体检",或点工具卡片上的运行;
- 未配置模型也能用:运维工具智能体会走关键词规则模式,体检报告照常生成。
-
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 停机页。一、本次新增
# 交付物 说明 1 qdcms-license-watch.ps1(新增,站点根目录 + 交付包)监控 data/.license_warnings计数,按 0~2 / 3~4 / 5~6 / 7 / ≥8 分级输出,退出码 0/1/2/3/4 便于接计划任务;只提醒不自动清除(保持授权策略不被削弱);-Clear可人工复位(先自动备份);日志写入data/.license_watch.log2 措辞与说明修正 明确"锁定只影响未授权域名访客;自有域名与内网/本机访问始终正常"" 二、实测结论(本次核验)
访问方式 结果 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 地址"。
一、改动
# 位置 改动 1 data/.license_allow(授权白名单)显式加入 192.168.0.100、192.168.0.(前缀,覆盖 192.168.0.1~254,应对 DHCP 变动)、127.0.0.1、localhost2 includes/LicenseManager.phpisLocalHost()支持 IP 前缀形式的白名单条目(如192.168.0.)。仅当整串确为合法 IPv4 时才做前缀匹配,因此192.168.0.100.evil.com这类主机不会被误放行3 nginx vhost 10123.xn--fiqs8s.confserver_name追加内网网段正则~^192\.168\.\d+\.\d+$、~^10\.…$、~^172\.(16-31)\.…$—— 否则换一台内网设备(如 192.168.0.101)时请求会落到宝塔默认站(只返回 612 B 页面)。nginx -t校验通过,需在宝塔点一次「重载配置」生效4 data/.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 解决,待重载配置后生效三、你需要做的
- 无需重启 PHP;授权白名单改动立即生效。
- 让「整个局域网网段」都能直接访问:宝塔 → 网站 → 设置 → 重载配置(或 Nginx 重载)。仅此一步需要你点。
-
v0.4.42
修复聊天发送视频后气泡消失 / 回显缓慢或看不到
随交付包发布现象:聊天里发送视频,上传成功后气泡消失,视频要过一会儿才回来(有时一直不出现)。
查看完整变更
现象:聊天里发送视频,上传成功后气泡消失,视频要过一会儿才回来(有时一直不出现)。
一、根因:接口响应没返回新消息 id
环节 问题 includes/fn-message.phpsendChatMessage()插入后只 return true,不返回自增 idajax-chat-send.php响应message{}只有 sender/content/media 等字段,没有 idassets/im-plugin/modules/chat.js发送回调需要 real.id才做"原地替换乐观气泡";缺 id 时走else分支 → 直接removeChild删除气泡,然后等 4 秒轮询把消息拉回来→ 于是出现:"上传 100% → 气泡消失 → 视频过几秒才回来(轮询错过就一直不回来)"。 实测服务端处理仅 0.65 秒,慢的完全是前端等轮询。
二、修复
# 文件 改动 1 includes/fn-message.phpsendChatMessage()改用db()->insert()并返回自增 id(拿不到时回退true,旧调用方不受影响)2 ajax-chat-send.php响应 message补id、is_read、file_size、sender_avatar(id 兜底再查LAST_INSERT_ID())3 assets/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当"时间/已读"那一行比视频宽时,气泡会被横向撑开(这就是"发送方视频气泡过宽"最直接的来源) 二、修复
# 文件 改动 1 assets/im-plugin/modules/chat.js消息结构:包裹层加 .msg-body;媒体消息(图片/视频,含流式地址与付费墙分支)气泡加.media类 → 内边距 4px;文案消息完全不受影响2 assets/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×1683 assets/js/tab-card.jsIM_BUILD递增(20261002-10 → 20261002-11)强制刷新插件资源缓存尺寸推算(修复后)
视频形态 修复前气泡宽 修复后气泡宽 竖屏 1080×1920 240 + 24 = 264px 146 + 8 = 154px 横屏 1920×1080 240 + 24 = 264px 200 + 8 = 208px 小屏(≤480px)竖屏 264px 132px(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 计数 = 0 504 来自链路更前面的网关/代理层 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 分片,每个请求都在几秒内完成 → 免疫任何网关超时。
二、本次改动
# 文件 改动 1 ajax-upload-chunk.php(新增)分片端点:登录 + CSRF 校验; upload_id(32hex)/index/total(1~500)/name/chunk(≤4MB);逐片落盘、到齐后流式合并为merged.bin并返回token;含 200MB 总量上限、2 小时过期自动清理(GC 以内部文件时间为准,兼容 Windows 目录 mtime 不可靠)2 post-video.php支持 upload_token发布:分片合并完成后只发表单字段(不再携带文件)→ 秒级返回;发布后自动清理分片目录3 includes/fn-upload.php新增 moveUploadedOrLocal():真实上传走move_uploaded_file,分片合并文件走rename/copy(仅允许uploads/tmp_chunks/内的文件,防止被当作任意文件搬运)4 includes/fn-moments.php改用该助手; finfo返回application/octet-stream等泛型类型时按扩展名判定(仍走同一白名单,安全不变)5 assets/js/upload-progress.js新增 QdUpload.uploadChunked():4MB 分片、串行上传、单片失败自动重试 2 次、逐片汇总进度6 post-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、仍正确引入进度脚本、内联 JSnode --check通过 ✓ C. 数据卫生:测试动态/媒体/分类/临时目录全部清理(moments17 条 = 用户真实发布 ✓)四、效果
- 手机经域名上传 → 每片几秒完成,不会再出现 504;进度条按分片推进(第 x/y 片);
- 分片失败自动重试 2 次;全部分片合并后才进入"服务器处理中(转码/截图)"阶段;
- 小文件(≤4MB)行为与之前完全一致,无额外请求。
五、附:可选的更彻底做法
若希望连"上传"这一步都完全不经过域名链路,可让手机在局域网直接访问
http://192.168.0.100/post-video.php(同 WiFi 时最快,且完全绕开前置网关)。
第 3 / 10 页 · 每页 10 条 · 共 98 条
升级前请确认
备份
备份站点目录与数据库,尤其是
uploads/与config/。阅读说明
在
docs/版本升级说明.md中找到对应版本,确认是否需要执行数据库迁移。执行升级
解压覆盖站点目录 → 执行 migration → 后台「系统 → 在线更新」复核版本状态。
复核功能
检查前台首页、播放、支付与后台工作面板等关键入口是否正常。
相关入口
- 文档中心查看随包技术文档(含版本升级说明、打包说明、安装配置说明)
- 插件市场查看插件版本与兼容性
- 授权续验升级后重新查询授权状态,确认未因换机失效
- 遇到问题在线留言,附上版本号与报错信息