kate522
3bec2a5777
fix(icons): 图标类名统一为 FA5 语法并修正一处失效图标名
...
主题打包的是 Font Awesome 5,solid 字形必须带样式类 fas。全站有 18 处仍写成
FA4 的裸 fa fa-*,FA5 下并不存在对应字形,表现为图标位置空白;而 FA5-only
契约此前只扫描部分运行时文件,没有覆盖模板与渲染器,这些写法一直没被拦下。
同时发现一处真实的失效图标名:profile-level.php 用的是 fa-line-chart。这是
FA4 名称,FA5 把该系列重命名为 chart-*,正确写法是 fa-chart-line。
- 18 处 "fa fa-*" 补上 fas:首页模板、组件标记、评论表单、用户等级页、菜单
装饰、SchemaPayment 促销标签默认值、VIP 服务弹窗、ContentRenderer /
GeneralRenderer、后台卡片样式校验、pay-vip.js
- profile-level.php 的 fa-line-chart 修正为 fa-chart-line
- 三处注释里的示例值同步为合法形态("fa fas fa-star"),避免被当成正确写法
抄走;credits.css 注释中直接写出旧字体族名的一处改为描述性表述,否则会被
FA5-only 契约当作违规命中
- legacy-navigation-contract:FA 资产断言改为跟随 aksrt_enqueue_fontawesome()
这一间接层(注册点已从脚本文件移到 inc/helpers/aksrt-icons.php),并把
fa-zibsvg-<key> 识别为项目自有 SVG sprite 族,而非 Font Awesome 字形
- vip-points-exchange-modal 契约同步断言 fa fas fa-angle-right
验证:改动前在干净 HEAD 上跑 node --test(已追踪用例)为 327 项 / 325 通过 /
2 失败,两项失败正是本次修复的失效图标名断言与 FA 版本号断言;改动后 333 项 /
333 通过(含 5 个本地专用用例共 370 项全部通过)。php -l 全部改动的 PHP 文件
通过。
2026-09-18 23:17:05 +08:00
kate522
aad83072a8
refactor(pay): 统一流水号,移除订单/流水/提现三类号码前缀
...
订单号、资金流水号、提现单号此前各自带前缀配置,同一笔业务在不同界面会
呈现多个号码口径,对账与客诉排查都要先做一次前缀换算。现收敛为单一流水号
分配器,不再按业务类型区分号码形态。
- 删除 payment_order_prefix / payment_flow_prefix /
payment_withdrawal_prefix 三项配置项及其生成、校验链路
- BusinessNumber::allocate() 成为唯一入口,输出 {YmdHis}{6 位随机},
共 20 位无前缀,满足 VARCHAR(32) 与网关 out_trade_no ≤ 32 的限制
- 订单、资金流水、提现、卡密渠道交易号四处生成点全部改走该分配器
- 后台支付中心表头「订单号 / 提现单号」统一为「流水号」
- 前台用户中心与订单卡片文案同步统一;前台订单详情合并为单行流水号,
账本流水号不再下发到前台,避免同一单据出现两个对外号码
- 同步更新 financial-flow / pay-card / card-pass-order-numbers 契约测试
与 BusinessNumberTest 断言
按用户要求不做双路逻辑与数据迁移,直接替换为统一方案,历史行不做转换。
验证:node --test tests/**/*.test.cjs 362/364 通过,新增 37 项契约;失败的
2 项在改动前的干净 HEAD 基线上同样失败(基线 327 项 / 失败 2 项),分别命中
遗留的 fa fa- 标记与 FA 版本号断言,与本次改动无关。phpunit 44 项 / 103
断言全部通过;php -l 全部改动的 PHP 文件通过。
2026-09-18 22:14:27 +08:00
kate522
8b999444b2
fix(icons): 图标卡片支持内置 SVG 与自定义 SVG,修复前端图标不显示
...
顶部多功能组件的图标卡片只能显示 FA5 图标。后台「选择图标 → 内置 SVG」
页签写入的是 zibsvg-{key},但渲染器把它拼成了
<i class="fa fas fa-zibsvg-hot">,浏览器没有这个名字的字形,前端图标位置
空白。
根因:aksrt_icon_cover_card() 与 aksrt_icon_card() 只实现了 FA 类名一条
路径,未走全站统一渲染器 aksrt_icon_markup();函数内那条用于跳过前缀拼接的
判断用的是 aksrtsvg-(任何选择器都不会产生的废弃前缀),形同虚设。
- 新增 aksrt_card_icon_inner() 统一解析器,横版 / 竖版卡片均委派给它,
FA5 类名、zibsvg- 内置图标、customsvg- 内联 SVG 三种格式统一渲染
- aksrt_icon_card() 的 icon 值改用 aksrt_sanitize_icon_value(),
原 sanitize_text_field 会把 customsvg-<svg> 的标签整段剥成裸前缀
- SchemaProvider::sanitize_field_value() 补 type === 'icon' 分支:
分组 / 重复器内的图标子字段原先落到 sanitize_text_field,
header_slider_card_option.cards[].icon 的 customsvg- 在保存时即被剥空
- PageConfigMetaBox::sanitize_card_options() 同步改用图标净化
- aksrt_svg_kses_tags() 补齐 circle / ellipse / rect / polygon / line,
与选择器端 cleanSvg() 的接受范围对齐;原先粘贴以 <circle> 为主的图标
会在 kses 阶段被静默剥离形状
- icon-card-contract 新增 3 项契约
内置 SVG 的 sprite 由 svg-icon.js 每页注入 body,无需额外入队。
未写数据迁移;已存量的 zibsvg- / FA 值无需转换,customsvg- 存量值本就被
旧净化逻辑破坏,不在此次范围内。
验证:node --test tests/widget-system/*.test.cjs 311 项全部通过(原 308 +
新增 3);php -l 4 个改动文件通过;隔离 PHP 探针覆盖 9 种取值并走完整
「保存净化 → 前端渲染」链路,修复前 / 后输出逐项对比。
2026-09-18 20:05:14 +08:00
kate522
95ff0761b7
fix(vip): 积分兑换弹窗改服务端渲染并与 Zibll 1:1 对齐
...
/user/vip/ 的积分兑换会员弹窗原先是前端自行拼装的,结构与层级都与参考主题
Zibll 不一致:Zibll 走 zibpay_get_vip_points_exchange_modal() 服务端渲染静态
壳,前端只按需开合。改为同一模型,前端不再拼 HTML。
- VipServiceModal 新增 get_points_exchange_modal_html():门控(未登录/未开启
返回空串)、vip-card 套餐选择、积分不足提示与提交表单;wp_footer 挂载输出
- pay-vip.js 移除 renderPointsModal / pointsPackage / exchangeFromModal /
vipPointsPay,改为自包含开合(.in + 内联 display:flex + 独立遮罩 +
body.modal-open + ESC),保留 aksrt-vip-points-toast 的 load/success/danger 契约
- 移除 /user/vip/ 页面底部独立积分兑换入口及其样式(uc-vip-points-link)
- credits.js 清理依赖全站不存在选择器的死代码 initVipPointsExchange()
- vip-modal.css 删除 71 行自实现样式,改为 .modal[data-aksrt-vip-points-modal]
显隐契约;层级 100050 < 遮罩 100055 < 弹窗 100060 < notyf 10000000
- 新增 vip-points-exchange-modal 契约测试(7 项),toast-contract 同步
静止态必须显式 display:none,否则 .flex{display:flex} 会覆盖 .modal{display:none}
形成隐形遮罩拦截整页点击。
未写数据迁移。
验证:node --test tests/widget-system/*.test.cjs 308 项全部通过;php -l 全部
改动文件通过;隔离渲染桩确认积分充足 / 积分不足 / 功能关闭 / 未登录四种情形
的 HTML 产物正确。
2026-09-18 20:05:05 +08:00
kate522
d2447f8aa6
fix(pay): 修复后台收款接口显示顺序不可用并接入收银台排序
...
后台「收款接口 → 收款接口显示顺序」有三处缺陷叠加:
1) sortable 渲染组件读取 item.label,而 schema 写的是 title,导致 6 行
只剩上下箭头;
2) SchemaProvider 的 sortable 分支遍历 items 定义重建数组,而该字段的
键顺序本身就是配置值,用户排序被静默改回 schema 静态顺序;
3) 真正构建收银台支付方式列表的 aksrt_list_cash_payment_methods() 使用
硬编码顺序,Gateway::get_available()/apply_sdk_order() 那套排序逻辑
无任何调用方,配置对前台毫无影响。
改为:schema 项统一使用 label(JS 与 PHP 两处对齐);sortable 持久化按
提交键顺序重建,items 定义仅作白名单;新增唯一排序实现
aksrt_sort_payment_methods()(语义对齐参考主题 zibpay_get_payment_methods
+ pay_sdk_order 键顺序),并接入内容收银台、余额充值、购买积分与会员
购买四个入口。卡密输入盒改为按渠道存在与否判断,不再假定卡密固定在末位。
清理死代码:无调用方的 Gateway::get_available/apply_sdk_order/
get_status_summary、VipServicePackages 中不可达的支付方式列表回退分支、
零引用的 settings-defaults 模块及 schema/index.js 未使用的导出、支付
sortable 的 fields 死元数据、无拖拽实现却声明的 cursor:move。
未配置 pay_sdk_order 时顺序保持不变;未写数据迁移。
验证:php -l 8 个改动文件全部通过;新增 pay-sdk-order-contract 契约测试
(6 项);node --test tests/widget-system/*.test.cjs 301 项全部通过;
后台 SPA 已重新构建。
2026-09-18 19:01:19 +08:00
kate522
03871f0342
fix(pay): 渠道名称禁折行,消除三字渠道名的零余量换行
...
实测(bootstrap+main 真实加载组合):芯片文本行可用宽度 46px 对
三字渠道名「支付宝」(雅黑 14px×3=42px)近乎零余量,站点字体渲染
的细微差异(字距/亚像素舍入)即触发 CJK 逐字换行,参考主题实测为
恒单行。
- .payment-method-radio > div 增加 white-space:nowrap,锁定与参考
主题同等的单行表现(渠道名集合均为 2-3 字短名,无溢出风险)
- main.min.css 重建,契约测试锁定(323 项全部通过)
2026-09-18 18:38:07 +08:00
kate522
89801236eb
fix(pay): 方法行还原 Zibll 原样(不换行),项目收缩成芯片一行排满
...
上一轮给方法行加的 hh(flex-wrap:wrap)方向错误:行级换行使项目保持
「图标左+文字右」的宽形态直接断行(3+2 布局),永远不会收缩成参考
主题的芯片形态。Zibll 的真实机制是行不换行、项目经 flex 收缩后由项
内 hh 将文字折到图标下方,形成「图标上/文字下」窄芯片一行排满。
- 三处方法行还原为 flex mb10(与参考主题逐字一致):充值/积分模板
与会员 pay-vip.js
- 图标不变形由既有防护保障(flex:none + width:auto + max-width:none
抵消 bootstrap 全局 img 钳制)
- 无头 Chrome 实测(bootstrap+main 真实加载组合,400px 弹窗):5 渠
道一行 5 个芯片(62-73px、图标 35px),6 渠道一行 6 个(53-62px、
stripe 宽形 84px),与 Zibll 同 fixture 形态一致
- 契约测试同步:行标记锁定无 hh、img 四属性防变形断言保留(322 项
全部通过)
2026-09-18 18:26:50 +08:00
kate522
be07db3409
fix(pay): 抵消 bootstrap 全局 img max-width 对支付图标的钳制
...
AKSRT 的 bootstrap.min.css 将 BS3 .img-responsive 选择器组误并入了裸
img(img{display:block;max-width:100%;height:auto};Zibll 的裸 img 不
在该组),导致 flex 压缩场景下 max-width:100% 把支付方式图标钳制到被
压窄的项宽——上一轮的 flex:none 防不住 max-width,5 渠道时图标仍可
被压成细条。
- .payment-method-radio img 显式还原 width:auto + max-width:none
(连同上一轮 flex:none,图标在任何压缩场景恒为固有比例宽)
- 契约测试改为提取规则块逐属性断言(原正则被规则内注释的右花括号
截断)
- 无头 Chrome 真实加载组合(bootstrap+main)实测:5 渠道 400px 弹窗
图标 35x35、项宽 112-183px,无任何挤压
2026-09-18 18:18:31 +08:00
kate522
e9dd928859
fix(pay): 多渠道时支付方式图标不再被 flex 压缩变形
...
用户配置 5-6 个收款渠道时(400px modal-mini 内 6 项),方法行项目
被 flex 压缩导致图标变形:方形 logo 被压至 31px/22px,宽形 stripe
logo(2468:1024)被压成 35px 方形。经无头 Chrome 几何实证,参考主题
同场景存在完全相同的缺陷(两主题 main.css 该组件逐条一致),属 Zibll
组件固有问题而非复刻偏差;按用户要求修复且不改变正常场景视觉:
- main.css:.payment-method-radio img 增加 flex:none(图标恒为固
有比例宽,高 35px 不变);main.min.css 经 build-public-assets 重建
- 三个弹窗方法行加 hh(.flex.hh{flex-wrap:wrap}):空间不足时整行
换行而非压缩图标——充值/积分(服务端模板)与会员(pay-vip.js)
三处同步
- 契约测试锁定 img flex:none 与三处行标记(322 项全部通过)
- 验证:无头 Chrome 实测 6 渠道 370/360/330/300px 容器下全部图标
恒定固有比例宽度,行自动换行
2026-09-18 18:13:58 +08:00
kate522
6075028520
fix(pay): 支付方式字样与按钮 UI 三弹窗统一对齐 Zibll
...
渠道展示名与按钮 UI 与参考主题 zibpay_get_payment_method_args /
zibpay_get_initiate_pay_input 对齐:
- 渠道名:aksrt_list_cash_payment_methods 增加 Zibll 基准展示名映射
(余额/支付宝/微信/PayPal/Stripe),充值与会员弹窗不再显示网关
内部名「站内余额」「微信支付」;积分弹窗手写「余额/卡密」与之同源
- 会员按钮字样:cta_label(立即开通/立即续费)→ Zibll 会员弹窗
initiate_pay_input(4) 默认「立即支付」,与充值/积分弹窗一致
- 无可用支付方式:禁用按钮+自实现文案 → Zibll 同款
<span class="badg px12 c-yellow-2">暂时无法支付,请与客服联系</span>
- 清理:按钮残留类 aksrt-vip-submit 与对应 CSS,加载/禁用态统一挂
.initiate-pay(三弹窗按钮共用);renderMethods 空数组重复提示与
不可达 reason 映射删除
- 契约测试同步锁定(无 cta_label/aksrt-vip-submit、立即支付字样、
badg 提示、渠道名映射)
弹窗宽度差异(充值/积分 400px modal-mini、会员 600px)为 Zibll
原生设计,已在壳几何对齐时确认一致。
2026-09-18 17:48:54 +08:00
kate522
ec1107c65a
fix(vip): 会员弹窗壳几何 1:1 对齐 Zibll(600px/整屏高度阈值/8px 圆角)
...
滚动条与尺寸偏差根因是 aksrt-modal-runtime 壳覆盖偏离参考主题
modal_pay_uservip 的几何:
- 宽度 min(560px,100%) → min(600px, calc(100vw - 20px)):对齐
bootstrap3 ≥768px .modal-dialog 600px + .modal.flex .modal-dialog
的 max-width calc(100% - 20px)
- 高度 min(90vh,760px) → calc(100vh - 20px):760px 阈值过低是侧边
滚动条根因;对齐 .modal.flex .modal-content 的整屏阈值
- overflow auto → hidden + overflow-y auto + touch 滚动:对齐
.modal.flex .modal-content,正常桌面内容不再出现滚动条
- 圆角 12px → var(--main-radius, 8px):对齐 .modal-content
- 移除 .payvip-modal 本地 padding(18/16px),内边距回归 .box-body
15px(参考主题无 .payvip-modal 专属 padding)
- 契约测试同步锁定桌面壳几何、无本地 padding 与移动端 bottom 圆角
2026-09-18 17:34:00 +08:00
kate522
db0d63b99f
fix(pay): 会员卡密单密码默认关闭,卡密盒与其他弹窗一致显示卡号+密码
...
会员购买/续费弹窗卡密盒此前仅显示卡密输入,与其他两个弹窗(卡号+密码)
不一致。根因是 pay_vip_pass_charge_only_password 的默认值偏离参考主题:
- PaymentRuntime:vip 类型 only_password 由「未设置即视为开启」改为
!empty(),与其他两类型同构(参考主题 default false)
- ChargeCard:get_public_options 的 vip 回退值 only_password true→false
- SchemaPayment + recharge.js:会员卡密单密码模式开关 default true→false
- 契约测试同步锁定默认关闭与无 isset 回退
- admin SPA 重新构建
已保存过设置且该键被持久化为开启的站点,需在后台「余额充值 → 卡密
兑换 → 会员卡密单密码模式」手动关闭一次。
2026-09-18 17:26:50 +08:00
kate522
721fa29b8d
fix(vip): 会员弹窗支付方式渠道对齐 Zibll initiate_pay_input 组件
...
支付方式 UI 不再自实现(uc-vip-shop__method 文本 radio),改为与其他
两个弹窗(充值/积分)完全同源的 Zibll zibpay_get_initiate_pay_input
组件结构:
- 支付方式行:.payment-method-radio.hollow-radio + logo 图 +
data-for/data-value 选中模型(多渠道时展示「请选择支付方式」)
- 我的余额盒:data-controller == balance 条件显隐,展示货币符号与余额
(视图模型透传 wallet_balance / currency_mark)
- 卡密盒:Zibll password_box 同构(mb10 padding-h10 padding-w6 +
desc muted-box + form-control 卡号/卡密输入)
- hidden payment_method + initiate-pay 按钮类(mt6 but jb-red
btn-block radius)
- 服务端 payment_method_logo_url() 统一映射 pay-*-logo.svg
- 显隐统一走 data-controller(==/!=)通用匹配,卡密选中隐藏 .charge-box
- 清理 uc-vip-shop__method* 死样式与旧 change 监听;契约测试同步锁定
(.gitignore 白名单补 card-pass-modal-redeem.test.cjs)
2026-09-18 12:44:38 +08:00
kate522
e72d0710e6
fix(frontend): 购买积分弹窗壳静止态隐藏,修复整页不可点击回归
...
根因与 2026-09-17 充值弹窗故障同构:新增的购买积分弹窗壳同为服务端
静态输出(.modal.flex.jc.fade),credits.css 仅对充值壳做了静止态
display:none 压制,积分壳被 main.css 的 .flex{display:flex} 拉起永久
铺满全屏,叠加 .fade 的 opacity:0 形成隐形遮罩拦截整页点击。
修复:credits.css 追加 .modal[data-aksrt-points-pay-modal]{display:none}
与 .in{display:flex};打开态由 initPointsPay 的内联 display:flex 驱动,
关闭撤除内联样式后即回到隐藏规则。balance-charge-modal 契约测试同步
纳入积分壳护栏,防同类回归。
2026-09-18 12:31:38 +08:00
kate522
b88eab0bfe
feat(pay): 卡密兑换入口收敛到三个购买弹窗并对齐参考主题
...
- 移除余额卡片独立「卡密兑换」通用弹窗,兑换入口分布到充值/积分/会员三个弹窗的支付方式中
- 充值弹窗补齐卡密 logo 与仅卡密时的金额选择隐藏逻辑
- 积分购买弹窗 1:1 复刻参考主题 points-pay modal(商品档位/自定义/支付方式/立即支付),REST 改为 product+custom 契约
- 会员弹窗注入卡密渠道:视图模型透传 card_pass,前端渲染卡密盒并直兑 /pay/card-pass/redeem type=vip
- 后台卡密兑换拆分为余额/积分/会员三个独立开关,VIP 段旧会员卡密组清理
- REST type 改为必填(balance/vip/credits),三类型独立闸门
- 测试重写为 card-pass-modal-redeem 契约,321 项全部通过
2026-09-18 12:25:18 +08:00
kate522
a6b7d09706
fix(frontend): 充值弹窗打开态改为 flex,修正对话框定位
...
无头 Chrome 对 Zibll 真实 CSS 的几何实证:bootstrap modal('show') 的
内联 display:block 下,.modal.flex .modal-dialog{margin:0} 使对话框
顶在左上角(l=0,t=0);Zibll 生产环境打开态实为 CSS 的 display:flex
(壳的 .flex.jc 双轴居中,jQuery .show() 对 computed≠none 的壳是空
操作,内联 display 从未写入)。AKSRT 上一版把打开态定为 display:block,
导致对话框定位错误。
修复:credits.css 的 .modal[data-aksrt-charge-modal].in 改为
display:flex;credits.js openChargeModal 内联 display 同步改 flex。
静止态 display:none 规则不变。
几何复测(AKSRT 真实 CSS):打开态中心与视口中心、与 Zibll 参考
逐像素一致(dlgCenter=vpCenter=379,213);静止态 display:none。
契约 29/29 通过(新增 flex 断言与 block 禁令)。
2026-09-17 22:25:37 +08:00
kate522
95289829ee
fix(frontend): 修复充值弹窗壳全屏隐形遮罩导致整页不可点击
...
根因:弹窗壳为服务端静态输出(Zibll 由 refresh_modal JS 按需创建,且其
CSS 无 bootstrap .modal 基础规则,故无此问题)。AKSRT 中 bootstrap.min.css
的 .modal{position:fixed;z-index:1050;display:none} 先加载,main.css 的
.flex{display:flex}(弹窗壳对齐 Zibll 所需的工具类)后加载且同特异性
后者胜 → 弹窗壳永久 display:flex 铺满全屏,叠加 .fade 无 .in 时的
opacity:0,形成隐形遮罩拦截整页点击。
修复:credits.css 以 (0,2,0) 特异性压制——
.modal[data-aksrt-charge-modal]{display:none}(静止态隐藏)+
.modal[data-aksrt-charge-modal].in{display:block}(展示态)。
credits.js 开关维持第 20 轮的自包含实现(内联 display:block 驱动),
关闭撤除内联样式后即回到隐藏规则,无 JS 改动。
新增契约 tests/widget-system/balance-charge-modal.test.cjs(3 例):
壳结构与 data 钩子、静止态隐藏规则(防 .flex 覆盖回潮)、开关自包含
(禁止回退 jQuery modal 运行时)。相关契约 29/29 通过。
2026-09-17 22:03:02 +08:00
kate522
1889c9f048
fix(frontend): 卡密兑换通知接入全局 notyf Toast 固定 id 流
...
- credits.js initCardPass 从 setTip 内联提示迁移为固定 id 三态 notyf 流
(aksrt-card-pass-toast:load → success/danger 原位更新),
成功后延迟 800ms 刷新以保证成功 Toast 可见,对齐其余资产操作。
- credits-wallet.php 删除 data-aksrt-card-tip 死元素;credits.css 删除
.uc-card-pass__tip 死样式。
- 契约:toast-contract 将卡密兑换纳入固定 id 流清单并禁止 tip 回潮;
card-pass-universal-redeem 新增 Toast 流断言(27/27 通过)。
- 验证:容器内真实抓取 /user/balance/ 确认弹窗正常渲染且无 tip 残留。
2026-09-17 19:28:47 +08:00
kate522
64ed47165d
fix(payment): 卡密兑换开关收敛为唯一总开关
...
- 问题:积分卡密兑换报「积分卡密兑换未开启」,因 asset_points_card_enabled
与总开关并存为双重闸门;会员卡同样存在隐藏的第二开关 pay_vip_pass_charge_s。
- 修复:ChargeCard 类型闸门统一只消费后台「余额充值 → 卡密兑换」总开关;
积分卡仅额外要求积分系统可用(系统级依赖,非独立开关)。
- 死代码清理:PaymentRuntime 删除 benefit.pass_charge/pass_charge_desc 映射;
后台 schema 删除「卡密兑换会员」独立开关组与「启用积分卡密兑换」开关(双源同步);
vip options 收敛为仅 only_password 展示配置。
- 验证:php -l 4 文件无错;契约测试 59/59 通过;容器内探针实测
credits 类型闸门放行;SPA 已重建并同步运行副本。
2026-09-17 19:18:54 +08:00
kate522
3481620ed0
feat(payment): 通用卡密兑换弹窗并修正核销订单实付与订单名称
...
- /user/balance/ 余额卡片入口改为通用「卡密兑换」弹窗:请求不带类型,
后端按卡密自动识别余额/会员/积分;卡号输入恒展示且选填
- 后台「余额充值 → 卡密充值」语义更新为「卡密兑换」,开关更名
「启用卡密兑换功能」(设置键不变),双源 schema 同步并重建 SPA
- 删除死代码:credits-vip.php 死文件、credits-balance.php 内联积分
兑换块、/pay/card-pass/options 路由与 rest_options、labels 数组、
asset_points_card_description/password_only 死字段及内联块专属 CSS
- 卡密核销订单实付恒 0:create_redeem_order 源头写 0,UserOrders
对 card_pass 订单视图层归零覆盖历史行(不迁移数据)
- 订单名称按 note.meta 生成:卡密兑换-余额充值X / 卡密兑换-积分充值X /
购入[会员档位名]X天(永久)
- 新增契约 card-pass-universal-redeem.test.cjs,收紧 user-assets-layout
契约(禁 .uc-card-pass 根类回潮)
2026-09-17 19:04:47 +08:00
kate522
ba8d4b1b90
卡密充值与兑换接入统一订单号与支付流水号
...
此前卡密核销虽已建订单,但订单号硬编码 CARD{卡ID}、渠道交易号硬编码
card_pass_{卡ID},均不受后台前缀控制;且核销产生的资金流水没有挂到
订单上(order_number 为 NULL),订单详情页的「支付流水号」恒为「—」。
ChargeCard:
- 新增 allocate_redeem_order_number():走 OrderRepository 统一分配器,
消费后台「订单前缀」(payment_order_prefix)。
- 新增 card_pass_transaction_number():BusinessNumber::candidate(flow_prefix),
消费后台「流水号前缀」(payment_flow_prefix)。
- 两条兑换路径(redeem_asset_card / redeem_vip_card)替换硬编码取号;
create_redeem_order 接收调用方传入的交易号。
- 账本重放(replayed)时回取已落库订单号,不再把本次新分配的号回给前端。
FinancialFlowService:
- record_card_pass_payment():会员卡(0 元、无账本参与)直接落一条
与订单关联、零分录的 order_payment 流水;record() 新增
allow_empty_entries 通道(prepare_entries 拒绝 delta=0,占位分录不可行)。
- record_order_event() 新增凭证结算模式:豁免「金额必须 > 0」与
「资产类订单不得记现金流水」两条门槛(卡密核销既无第三方现金流入,
订单还可能为 0 元或以积分计价)。
- attach_order_to_ledger_flow():账本提交后把流水补挂到订单上,
event_type 归一为 order_payment,使「支付流水号」可反查。
- is_successful_order_payment() 认可 card_pass 凭证结算;
is_external_recharge() 把 card_pass 与 balance/points 一并列为平台内部
结算方式,不再为卡密充值伪造现金出账分录(现金在售卡时已确认)。
关键取舍:随机订单号不得进入 LedgerCommand 的 metadata —— payload_hash
覆盖 metadata,会破坏账本幂等重放(实测撞 uniq_operation_key 后报
aksrt_ledger_idempotency_conflict),因此订单关联改在账本提交后补挂。
测试:新增 tests/admin/card-pass-order-numbers.test.cjs 钉住上述约束;
容器内三类卡密实测通过(订单号/渠道交易号/支付流水号三项均带后台前缀,
流水行分别携带 balance:in / points:in / 零分录),重放幂等恢复正常。
2026-09-17 14:15:55 +08:00
kate522
c1c21faf7e
fix(payment): 生成数量限定为 1-1000 整数并移除 spinner 死属性
...
生成数量不再受 step 网格约束,只要求「正整数且不超过 1000」即 (0, 1000]。
- 删除 spinner() 产出的 data-min / data-max / data-step:这三个属性在本
项目全仓**没有任何消费方**(逐文件检索确认),属死代码;原生 min/max/step
又会让条件显隐行触发 HTML5 校验并静默阻止提交(上一轮已定案)。参数随之
收敛:spinner(string $name, int $value, string $unit),3 处调用点同步。
- 保留 step="any":省掉它 type="number" 会退回默认 step=1 的整数网格,把
非整数输入判为非法,同样触发隐藏行的静默拒绝。
- 生成数量的范围收敛为 handle_add() 里的单一区间判定
`$auto_num < 1 || $auto_num > 1000`,一次覆盖 非数字 / 0 / 负数 / 超上限,
不再依赖下层静默夹取,也不另设分支;字段说明补上「1 - 1000 的整数」。
验证:
- 容器内真实 HTTP 边界:0 / -5 / 1001 / abc 全部拒绝,1000 / 1 / 3.9 通过
(3.9 按整数截断)。其中 1000 这个上边界用「type=vip + 空时长」探到 ——
数量校验通过后即报「请填写兑换会员参数」,零副作用,未真的生成 1000 张。
正向生成 3 张后已清理,表回到原始 10 条。
- 渲染出的表单内原生约束属性 0 个、data-* 0 个;4 个 number 输入全部 step="any"。
- 契约测试:把「spinner 输出 data-*」的断言反转为「不得出现」,新增签名与
调用点实参断言、(0,1000] 区间断言、字段说明断言;整文件属性扫描前先剥
PHP 注释,否则文档注释里的 type="number" 字面量会污染计数。
- 负向对照:重新加回 data-min / 退回 !$auto_num / 签名加回 step 参数,
三例均精确落到对应用例(各 5 pass / 1 fail),还原后字节一致、6/6 通过。
- tests/admin 四套件 24 pass / 0 fail;php -l 通过;两副本 SHA256 一致。
2026-09-17 13:38:40 +08:00
kate522
481f40378a
fix(payment): 修复添加卡密页「确认提交」按钮静默失效
...
数字输入(auto_num / auto_price / auto_rand_number_limit /
auto_rand_password_limit)此前被平铺成原生 HTML5 约束属性
(min/max/step),叠加两个问题后表现为按钮点了毫无反应:
1) 数值彼此不自洽:参考主题 CSF spinner 的 default=20 / min=1 /
step=10 合法格点是 1,11,21…,默认值 20 当场就非法;
auto_rand_number_limit 同理(默认 20、格点 1,6,11…)。
2) 这些行是条件显隐的(field_row 输出 <tr data-dep>,不满足依赖时
display:none)。提交时浏览器仍会校验隐藏控件,而隐藏控件无法聚焦
去弹提示气泡,于是 Chrome 只往控制台丢一句
"An invalid form control ... is not focusable" 便静默拒绝提交——
不跳转、不报错、无 notice,用户看到的就是按钮坏了。
处置:数字输入改用 data-min/data-max/data-step + step="any"
(与参考主题 CSF_Field_spinner::render() 语义一致),不再写任何原生
约束属性;auto_price 一并去掉 min="0",面额下限改由服务端夹取兜底
(max(0.0, ...)),避免「去掉客户端下限」变成放行负面额。
验证:
- 无头 Chrome 探针:btn.click() 触发的 submit 事件 0 → 1,
参与校验控件 23 个、无效 3 个 → 0 个;
- 服务端扫描页面 25 个 input:带原生约束的 0 个;
- 服务端面额夹取:-5 拒绝、0.001 拒绝、12.5 正常生成 1 张;
- 新增 tests/admin/charge-cards-form-constraints.test.cjs(4 例),
并做负向对照(重引入 min/step 后 2 pass / 2 fail);
- tests/admin 四个套件合计 22 pass / 0 fail。
2026-09-17 13:19:05 +08:00
kate522
52d790c654
fix(payment): 卡密管理每页默认 20 条,撤掉工具栏「每页显示」控件
...
- DEFAULT_PER_PAGE 由 30 改为 20。
- 删除 per_page_selector() 及其表单样式(.aksrt-perpage-form / .order-header-right),
工具栏恢复为「过滤链接 + 搜索表单」两段式。
ice_perpage 仍作为 URL 参数被尊重,只是不再提供界面入口。
- 保留上一提交的分页健壮性修复:页码夹取到 [1, total_pages]、翻页链接用显式基准 URL、
越界页码回退并重查、禁用按钮 pointer-events:none。
- 契约测试同步改写:断言默认值为 20,并显式禁止「每页显示」控件回归。
验证:默认态渲染为「每页 20 共10」,页面内不存在 aksrt-perpage-form;
ice_perpage=5 仍能翻到第 2 页且链接携带该参数;paged=2 越界仍回退到第 1 页的 10 行;
node --test 三套 18/18;php -l 通过;无头 Chrome 截图确认工具栏无多余控件。
2026-09-17 13:03:05 +08:00
kate522
0e7b888277
fix(payment): 修复卡密管理分页:页码夹取、显式基准 URL、补齐每页条数入口
...
- render_pagenavi():页码先夹到 [1, total_pages],禁用状态由 $on_first / $on_last
一次导出。旧写法是一串 if/elseif,页码越界时三个分支一个都不命中,
上一页与下一页同时停在 '#':既不打 disabled 也点不动。
- 翻页链接改用显式基准 URL(page_url + 当前筛选参数),不再依赖
add_query_arg() 默认取 $_SERVER['REQUEST_URI'] 的行为;
status / type / other / s / orderby / desc / ice_perpage 随链接带走。
- render_list():页码越界(手改 URL、或筛选后总数变小)时回退到最后一页重查,
消除「空白表格 + 一个分页控件都没有」的死胡同。
- 新增「每页显示」选择器(ice_perpage)。该参数此前只有服务端读取、界面上没有
任何入口能改,条数小于默认每页条数时永远只有一页,分页条恒为 disabled。
- 禁用按钮加 pointer-events:none,避免点空还滚回页首。
- 新增 tests/admin/charge-cards-pagination.test.cjs(6 条契约)。
验证:容器内真实渲染 7 组 URL(默认 / 每页 5 / 第 2 页 / paged=2 越界 /
paged=99 越界 / 带 status 筛选 / 非预设每页 7),无头 Chrome 截图核对版式;
node --test 三套 18/18 通过;负向对照(还原旧写法)按要求失败 2 条;php -l 通过。
2026-09-17 12:45:22 +08:00
kate522
1e5286d36b
fix(payment): 导入提示的条目列表改用 <ul> 承载,圆点不再越出文字边界
...
四条导入提示里的 <li> 原先裸挂在 <div class="aksrt-submsg"> 下,没有列表容器:
list-style-position 默认 outside,圆点画在内容盒左侧的 padding 区里,而 <li>
自身没有 padding,于是圆点溢出到提示块的文字边界之外(真实后台 CSS 下实测 −8px,
视觉上紧贴提示块左侧色条)。
改动:
- 四条提示的 <li> 各用一个 <ul class="aksrt-submsg-list"> 包起来(同时修掉
<li> 缺少列表父元素的非法标记)。
- .aksrt-submsg-list 显式声明 margin / padding-left / list-style,不依赖 UA
或后台对 ul 的默认值,避免别处的重置再次把圆点挤出去。
- 新增契约用例:提示内的 <li> 必须在 <ul class="aksrt-submsg-list"> 中、标签成对、
每条提示只有一个列表容器,且该类的 CSS 必须带 padding-left 与 list-style。
实测(真实 Chrome + 真实后台 common/forms/list-tables CSS):圆点左缘由
「文字边界 −8px(溢出)」变为「文字边界 +12px(界内)」,条目文字缩进 20px。
2026-09-17 12:28:09 +08:00
kate522
d787f3ff97
fix(payment): 导入提示不再使用 WP notice 类,避免被 common.js 搬到页面顶部
...
真因:wp-admin/js/common.js 在 DOM 就绪时执行
$('div.updated, div.error, div.notice').not('.inline, .below-h2').insertAfter($headerEnd)
它会把页面上所有「非 inline」的 notice 搬到 .wp-header-end(不存在时取 .wrap 内首个
h1/h2)之后。提示块原先输出 class="aksrt-submsg notice notice-warning",被判定为
notice,于是在求值之后被整块搬到页头:既脱离「添加方式—卡密数据」之间的字段区,
又因为搬迁发生在 evalDeps 之后,行内显隐逻辑无从纠正。
这也是同一现象反复出现的真因:四条提示都可见时会被整体搬到页面最上方;给提示块
补上初始隐藏后看起来像「提示不见了」;改为全文档求值后则表现为「提示显示在页面
最顶部」。此前的 foster-parenting 判断有误——服务端输出的表格结构始终合法。
改动:
- submessage_row() 只输出自有类名 aksrt-submsg,不再复用 .notice / .notice-warning。
- 外观(底色 #fef8ee + 左侧 4px #f0b849 色条)改由 .aksrt-submsg 自带,与参考主题
CSF content 字段的做法一致;元素内联样式只保留初始隐藏状态。
- 新增契约用例:提示块不得带 notice;.aksrt-submsg 必须自带 background 与 border-left;
并确认页面级错误通知仍正常使用 notice(不误伤其它通知输出)。
2026-09-17 12:19:25 +08:00
kate522
45c7a4a59c
fix(payment): 添加卡密页导入提示移至卡密数据上方并修正脱离表单后不显示
...
- 四条导入提示与「单密码模式」开关收拢到「卡密数据」行正上方:切换卡密类型/
添加方式时,命中的那一条紧邻示例数据与输入框,便于对照填写。原先单密码模式
开关夹在两条提示之间、提示又落在自动生成字段之后的位置不再使用。
- evalDeps() 与 change 监听不再限定在 .aksrt-cardpass-form 子树内,改为全文档
查找 [data-dep]。提示块一旦被移出表单子树,限域查找会漏过它,其内联
display:none 无人清除,表现为「切换到导入卡密后提示不显示」。
- 契约测试同步收紧:断言必须为全文档选择器,并显式禁止回退为限域写法。
2026-09-17 12:03:13 +08:00
kate522
670e271ff6
fix(payment): 添加卡密页提示块自带依赖状态,脱离所在行也不再铺开
...
用户复报「四条导入提示仍然全部铺开」。其 DevTools 实测给出关键判据:
同一页面上 formClass=1 / submsg=4 / depRows=17 与线上一致,但四条提示的
父级 <tr> 为 null、computed display 为 block —— 也就是说提示块虽在 DOM 中,
却不在任何表格行内。此时依赖状态只挂在 <tr> 上,隐藏与切换都无处落地,
于是四条提示永久可见、切换卡密类型/添加方式也没有反应。
修复:把 data-dep 与初始隐藏状态同时挂到内层提示块上,求值器改为
「谁带 data-dep 就管谁」,行与提示块各自落自己的 display。
变更(src/Admin/Native/PayChargeCards.php):
- submessage_row():<tr> 与内层 <div class="aksrt-submsg"> 共用同一份
data-dep;初始隐藏状态合并进提示块原有的 margin/padding 内联样式,
不产生重复的 style 属性。原「只给 <tr> 加 style」的写法保留给行本身。
- evalDeps():选择器由 '.aksrt-cardpass-form tr[data-dep]' 放宽为
'.aksrt-cardpass-form [data-dep]',并改用 el.style.display 落值。
测试(tests/admin/charge-cards-dependency.test.cjs):
- DOM 桩按真实结构为每条提示建「行 + 提示块」两个元素,新增用例
「提示块与所在行同层落 display」断言两层始终同状态(默认 8 个元素全隐藏、
命中依赖时仅该提示的两层可见、切回默认两层同时收起)。
- 契约用例新增三条静态断言:提示块必须自带 data-dep、必须自带初始隐藏状态、
求值选择器必须同时覆盖行与提示块。
- 负向验证:把提示块的 data-dep 去掉后跑测试 → pass 5 / fail 1,护栏生效。
验证:
- node --test 两个 admin 契约测试 10/10 通过;php -l 无语法错误;
- 线上抓取:tr_total=19 / tr_with_dep=17 / div_with_dep=4 / display_none=18;
四条提示的 div 均带 data-dep="…" 与 display:none。
- 真实浏览器模拟「提示块被搬出所在行」(foster-parent 到 <table> 之前)后:
默认态四条全部 none;切到「会员兑换 + 导入卡密」时,只有已脱离行的
「导入会员兑换卡密」变为可见(ownStyle 中的 display:none 被移除),
其余三条维持 none;切回默认四条全部收 none。
2026-09-17 11:41:05 +08:00
kate522
5243bbf0d4
fix(payment): 添加卡密页清理依赖求值死代码并锁定显隐契约
...
render_add_form() 渲染 19 行表单,其中 17 行带 data-dep;4 条导入提示
(导入卡密 / 导入会员兑换卡密 / 自定义卡密导入 / 自定义卡密导入-单密码模式)
的显隐依赖已由服务端预隐藏与服务端默认值修正落地,本次仅做收尾。
变更:
- 删除行内脚本 IIFE 末尾的 evalDeps() 死调用。该调用位于表单之前的
解析期(脚本在表单前输出),此刻 document 中尚无任何 tr[data-dep],
属于必然空操作;初始求值统一交由 DOMContentLoaded 分支处理。
- 补充注释说明「脚本在表单前输出 → 解析期取不到行 → 必须等 DOM 就绪」,
避免后人误加回解析期调用。
- .gitignore 追加 /tests/admin/charge-cards-dependency.test.cjs 白名单。
新增契约测试 tests/admin/charge-cards-dependency.test.cjs(5 用例,全过):
从源码抽取 field_row/submessage_row 的 data-dep,用 Node vm 加载真实行内
脚本并以最小 DOM 桩驱动,断言:
1) 依赖键须在 is_known_dep_key 与 default_form_value 成对登记;
2) 服务端预判与前端求值使用同一组操作符且覆盖表单实际用到的全部操作符;
3) 两类行渲染均接入服务端预隐藏,避免首帧铺开;
4) 行内脚本不再保留解析期空操作求值;
5) 导入提示跟随「卡密类型 × 添加方式」切换(balance/credits/vip/custom
及单密码模式矩阵),且不同时铺开、切回 auto 全部收起。
负向验证:将 balance,credits 篡改为 balance,credits,vip 后测试转为
pass 4 / fail 1,护栏确实生效。
验证:node --test 两个 admin 契约测试 9/9 通过;php -l 无语法错误;
dev 与运行副本内容一致(行尾归一后逐字节相同)。
2026-09-17 11:03:34 +08:00
kate522
1cbc0c6ed8
fix(payment): 排序箭头改为基线锚定,修正表头箭头相对文字偏下
...
.orderby-but 从「无尺寸 inline 宿主 + 依赖绝对定位静态位置 + 固定
translateY(-3px)/6px」改为「零尺寸 inline-block 宿主 + bottom 锚定 + translateY(50%)」。
原理:空 inline-block 的基线即其下边缘,会与同行文字基线对齐,于是箭头盒可用 bottom
精确锚定到「基线以上 N em」;translateY(50%) 抵消箭头自身高度,使盒中心恒等于 bottom 值,
与 dashicons 盒高无关。两枚箭头中心分别落在基线以上 .725em / .075em,对称于文字视觉中心。
旧写法的问题:绝对定位元素未指定 top/bottom 时,其位置来自静态位置(容器内容盒顶部),
该值与表头字体/行高联动;在真实后台 CJK 字体度量下整体偏下。
量测(无头 Chrome + 真实 wp-admin common.css/list-tables.css + 真实表头标记):
- 旧写法:箭头簇中心相对文字中心 +2.0px(复现用户反馈的「偏下一点」)
- 新写法:-0.09px;两箭头相对文字中心 -4.64 / +4.46,居中对称
- 表头行高两版均为 36.59px,无行高副作用
契约测试同步收紧:断言 bottom 锚定写法,并禁止回归到无 bottom 的固定像素位移。
2026-09-17 10:28:17 +08:00
kate522
9fffe7b590
fix(payment): 卡密管理页标题按钮单点输出并修正排序箭头下沉
...
- 标题右侧按钮原在页面头部与列表渲染函数各输出一次(实际渲染 3 个
page-title-action,「添加卡密」重复出现),改为只在页面头部的 tab switch 中
拼一次;render_list() 收为 render_list(string $s),只渲染过滤链接与表格,
搜索词在页面头部单次解析后传入,搜索提示仍按参考主题跟在按钮之后。
- .orderby-but 恢复参考主题写法(position: relative,不设 display)。
箭头是绝对定位元素且不写 top/left,位置取自容器的静态位置;容器一旦变成零
高度 inline-block,基线会退化为自身下边缘并与文字基线对齐,整组箭头下沉一
个字高。同时补回参考主题的 padding-right: 1em,并加注释锁定该约束。
- 清理死代码:行循环中 custom 分支的 $type_html 赋值总被下方类型链覆盖,已删除。
- 新增 tests/admin/charge-cards-page-contract.test.cjs(4 例)作为回归护栏,
并按 .gitignore 既有白名单惯例放开该文件。
2026-09-17 10:14:19 +08:00
kate522
a48007a44d
feat(payment): 支付&付费菜单按参考主题重构并新增提现策略页
...
- 子菜单重组为知识付费/余额充值/VIP会员/创作分成/推广返佣/收款接口/提现策略
- 收款接口页 1:1 复刻 Zibll 双下拉结构,仅保留支付宝/微信/PayPal/Stripe/易支付
- 订单前缀/流水号前缀/提现单号前缀配置保留并移入收款接口页
- 知识付费/推广返佣按参考主题全字段复刻,余额充值并入充值卡配置
- 新增 tabbed/between_number/page_select 表单控件及后端 pages 搜索源
- 清理旧 SPA 组件、无消费者 REST 端点与废弃配置键(不写双路兼容)
- 更新存量契约测试至新 schema 文件
2026-09-16 19:18:28 +08:00
kate522
098df7f921
fix(user-center): 去除余额金额显示前¥符号
2026-09-16 17:39:40 +08:00
kate522
175d32f01e
fix(tests): 修复存量合约测试失败
2026-09-16 17:24:22 +08:00
kate522
56d1b2a417
fix(user-center): 防止大额资产金额断行
2026-09-16 17:23:56 +08:00
kate522
e7ffb44b45
fix(admin): 兼容提现金额历史配置
2026-09-16 14:12:40 +08:00
kate522
2c4bd3eb2a
fix(user-center): 调整提现记录金额展示
2026-09-16 13:00:27 +08:00
kate522
6bbb79213b
fix(user-center): 优化提现记录弹窗分页
2026-09-16 12:53:38 +08:00
kate522
27f54c8e35
修复资产卡片底部对齐
2026-09-15 22:24:49 +08:00
kate522
7efbbeed3f
修复余额页顶部资产卡片高度
2026-09-15 20:50:21 +08:00
kate522
0a4448dd70
收紧顶部卡片与下方主卡片的间距
2026-09-14 12:53:20 +08:00
kate522
632a7d15ba
fix(user): replicate level center page
2026-09-13 21:28:10 +08:00
kate522
129eb25078
fix(email): lock templates to built-in catalog
2026-09-13 20:02:56 +08:00
kate522
3f02048bc5
test(admin): read the picker css before asserting the hidden guard
2026-09-06 16:38:42 +08:00
kate522
abf3a4ae31
fix(admin): re-assert [hidden] inside the icon modal so tabs and search switch
2026-09-06 16:37:11 +08:00
kate522
af04fcfd3c
fix(admin): bind FaIconPicker with v-model so icon clicks update the value
2026-09-06 16:10:28 +08:00
kate522
2e25894eb5
fix(navigation): stop mangling zibsvg/customsvg menu icons
...
aksrt_render_menu_icon() prefixed any value without an fa substring
with fa fas fa-, turning picker values like zibsvg-hot into
fa fas fa-zibsvg-hot — blank icons in the frontend nav. Sprite and
inline SVG values now flow through aksrt_icon_markup with the
menu-item-icon classes attached; FA values keep the legacy padding.
2026-09-06 14:27:49 +08:00
kate522
7ab5f29f87
fix(icons): render brand icons under the fa fab double prefix and drop an empty sprite key
...
FA5's own single-class declarations lose the cascade to the later
.fa,.far,.fas family rule, so zibll-legacy values like "fa fab fa-weixin"
rendered with the Free font and came up blank — visible in the picker's
brand tab (500px…zhihu) and on every brand icon in the SPA and frontend
social links. Re-assert .fa.fab (and .fa.far weight) in the three
stylesheets that load FA5. Also remove the empty aksrt_svgs['qqww']
sprite entry, which surfaced as a blank built-in SVG item.
2026-09-06 13:31:24 +08:00
kate522
2e9650d15f
test(widgets): contract-lock the universal icon picker
...
Assert the generated FA5 catalog, the REST route + sprite single
source, picker field wiring in widgets and nav menus, SVG-aware icon
sanitization on both save paths, the single aksrt-font-awesome handle
with FA5 class names, and the consolidated assets/icons layout.
2026-09-06 13:00:13 +08:00