二七王:修复出牌操作条/亮牌历史布局越界,补主牌统计条改名遗漏

- I1:Layers.js 群组 206 改名遗漏一处注释(亮牌信息条 → 主牌统计条),全仓复查确认无第二处
- I2:出牌操作条补「提示」项后 anchor:center 导致已有两项挤偏,改用 anchor:left 并反推
  anchorX=446,令「出牌」按钮回到参考图实测 x≈556(求解器验证:446/556/748)
- I3:HIST_FAN/MING_FAN 的 maxWidth 反推算错(旧注释「488」有误,实际总宽恒等于
  maxWidth=500),导致 RIGHT 座位整排超出画布 5px;收窄为 490 使三座位求解结果落在
  0-1280 内,订正注释与清单 §6.9c 对应文字
- M3:同步修正计划文档里遗留的旧名「亮牌信息条/亮牌条」
- M6:test_constants.js 补 items[].key 的三命名空间解析守卫(此前完全无守卫)
- M5/M7:订正 ACC_ROW_TEXT_GRID 与扣底按钮宽度的估值依据说明
- M1/M2:清单 §6.9 子节重新排序为 6.9a→6.9b→6.9c 并统一标题层级,修正脚注星号误渲染

client/tests/run.js 与 server/games/erqiwang/test/run.js 均全绿,精灵总数(380)/
布局节点数(83) 两个钉死断言未变。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 09:06:01 +08:00
co-authored by Claude Opus 5
parent 8f36b61620
commit 2b1dd0d947
7 changed files with 87 additions and 37 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
// 均落在框架保留段,与下列不冲突。
var EQW_Layers = EQW_Layers || {
TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、亮牌信息条、底栏(局数 + 功能钮)
TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、主牌统计条、底栏(局数 + 功能钮)
HAND: 102, // 自己手牌区(单排 / 埋牌双排)
TABLE_CARDS: 103, // 桌面牌:底牌区、三家已出牌区、埋牌底牌展示区
ACTION: 104, // 阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时
@@ -89,9 +89,23 @@ EQW_Layout.BURY_OPERATION_BAR = {
//埋牌条 items 首项(同一个提示按钮)也取 180,故沿用 180,待设计稿复核。
//⚠ 本条 itemHeight 为 55(对齐出牌按钮 BTN_PLAY 157×55),而 BTN_TIP 原生高 63——
// 求解结果里提示项的 height 会是 55,实际显示高度以精灵自身资源为准;此高度差同样待设计稿裁定
//
//2026-08-27 修订:补「提示」项后原先仍用 anchor:'center',导致整排重新居中、把已有的
//CD_SELF / PLAY_BTN_SUBMIT 两项相对原先(仅 2 项时)左移了 107.5px——「出牌」按钮的位置在
//参考图 `出牌.png` 是有实测依据的(556–711,宽约 156×57),不该因为插入第 3 项而漂移。
//改为 anchor:'left',把 anchorX 定成【首项 CD_SELF 的起点】,让先前已有的两项固定不动、只是
//在其后追加「提示」——与 FOOTER_FUNC_BUTTONS 用 anchor:'right' 固定住最右项「底牌」是同一思路
//(那边插入更早的项,这边追加更晚的项,对称地选左/右锚点)。
//反推 anchorX:_solveLineItems 在 anchor:'left' 下 start = anchorX,故
// PLAY_BTN_SUBMIT.x = anchorX + CD_SELF.width(75) + spacing(35) = anchorX + 110
//要 PLAY_BTN_SUBMIT.x ≈ 556(参考图实测),故 anchorX = 556 - 110 = 446。
//实际调用求解器验证(count=3,spacing=35):
// CD_SELF x=446 width=75 (参考图目测约 444,估值层面 2px 差可接受)
// PLAY_BTN_SUBMIT x=556 width=157 (与参考图 556–711 实测吻合)
// PLAY_BTN_TIP x=748 width=180
EQW_Layout.PLAY_OPERATION_BAR = {
kind: 'line', direction: 'horizontal', anchorX: 640, anchorY: 345,
itemHeight: 55, spacing: 35, anchor: 'center',
kind: 'line', direction: 'horizontal', anchorX: 446, anchorY: 345,
itemHeight: 55, spacing: 35, anchor: 'left',
items: [
{ key: 'CD_SELF', width: 75 },
{ key: 'PLAY_BTN_SUBMIT', width: 157 },
@@ -145,6 +145,9 @@ EQW_Layout.ACC_TPL_AVATAR = {
// 列4: 傍王分{n}
// 第 2 行只有前两列有文字,第 3/4 列留空(求解仍返回 8 个槽位,调用方按数据取前 6 个)。
// anchorX 相对容器(= 参考图列1 绝对 x272 − 容器 x80);anchorY 随所在行浮动 → 运行时注入
// 【估值精度说明】本节点用等距列模型(itemWidth:176 spacingX:0 → 相对容器 192/368/544/720),
// 而参考图「大局结算.png」目视实测的列 x 约为 272/455/634/800(列距 183/179/166,并不等距)——
// 与等距模型偏差约 10px,比本文件头部通用声明的「±5px」更大,待设计稿复核(本次未改数值,仅订正估值说明)
EQW_Layout.ACC_ROW_TEXT_GRID = {
kind: 'grid', anchorX: 192, cols: 4, rows: 2,
itemWidth: 176, itemHeight: 34, spacingX: 0, spacingY: 10,
@@ -181,9 +184,21 @@ EQW_Layout.ACC_FUNC_BUTTONS = {
// 三者【同一种版式】(半透黑遮罩 + 每家一排重叠大牌),参考图同为
// docs_dev/uiref/冲关牌型显示.png;故以下节点照 CHONGGUAN_FAN / CG_MASK 同构给出,
// 三家落点沿用清单 §6.7 的冲关牌锚点(LEFT 260,120 / RIGHT 1035,120 / SELF 640,400)。
// 与冲关牌的唯一差别是【张数上限】:出牌历史摊平后可达 28 张以上,420 的 maxWidth 装不下,
// 故放宽到 500、spacingMin 收到 -96(每张露 14px,28 张总宽 110+27×14=488 ≤ 500)。
// 这两个数是【估值,待设计稿复核】——清单未给本 View 的排布参数。
// 与冲关牌的唯一差别是【张数上限】:出牌历史摊平后可达 28 张以上,420 的 maxWidth 装不下。
// 2026-08-27 订正:原估值 maxWidth:500 是算错的——_solveFan 的间距公式是
// spacing = max(spacingMin, min(spacingMax, (maxWidth-itemWidth)/(count-1) - itemWidth))
// 代入 maxWidth 500 / itemWidth 110(CARD_SIZE.L.w)/ count 28:
// (500-110)/27 - 110 = -95.56,没有触到 spacingMin:-96 的下限,故实际 spacing 是 -95.56,
// 而 fan 的总宽恒等于 maxWidth(AlignmentUtils.distributeHorizontally 的 totalWidth 公式代入后
// 可化简为 maxWidth,只要 spacing 没被下限截断)——不是旧注释算的「488」。
// RIGHT 锚点 anchorX:1035、anchor:center 时,总宽 500 使整排右边缘落在 1035+250=1285,
// 超出 1280 设计画布 5px(LEFT/SELF 因锚点更靠左,仍在画布内,故此前没暴露)。
// 故收窄 maxWidth 500 → 490:总宽=490(同样未触及 spacingMin 下限,spacingMin 因此仍是【死参数】,
// 28 张时永远用不到 -96 这个下限,留着仅为将来张数/尺寸变化时兜底),RIGHT 边缘 1035+245=1280,
// 恰好落在画布内;每张仍露约 14px(itemWidth+spacing=110-95.93≈14.07),与旧估值视觉上接近。
// maxWidth:490 与 spacingMin:-96 仍是【估值,待设计稿复核】——清单未给本 View 的排布参数。
// 【已知限制,留给后来者】每张仅露约 14px、视觉偏窄,待设计稿复核是否改为分两排显示,
// 或改用 CARD_SIZE.M(更小的牌面)——这是本次估值阶段接受的限制,不是本次要解决的问题。
//
// 【牌用精灵复制】求解结果直接作为 SpriteCopyUtils.create 的 x/y(相对容器),
// 与 §5.6a 冲关牌同一用法:三个容器精灵摆在原点、尺寸铺满屏,故容器内坐标 = 屏幕坐标。
@@ -199,7 +214,7 @@ EQW_Layout.HIST_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 };
EQW_Layout.HIST_FAN = {
kind: 'fan', direction: 'horizontal', anchor: 'center',
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
maxWidth: 500, spacingMax: -40, spacingMin: -96,
maxWidth: 490, spacingMax: -40, spacingMin: -96,
bySeat: {
LEFT: { anchorX: 260, anchorY: 120 },
RIGHT: { anchorX: 1035, anchorY: 120 },
@@ -231,7 +246,7 @@ EQW_Layout.MING_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 };
EQW_Layout.MING_FAN = {
kind: 'fan', direction: 'horizontal', anchor: 'center',
itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h,
maxWidth: 500, spacingMax: -40, spacingMin: -96,
maxWidth: 490, spacingMax: -40, spacingMin: -96,
bySeat: {
LEFT: { anchorX: 260, anchorY: 120 },
RIGHT: { anchorX: 1035, anchorY: 120 }
@@ -51,8 +51,10 @@ EQW_Layout.FOOTER_ASET_TEXT = {
//底栏 · 功能钮组(明牌/已出牌/上一轮/扣底/底牌):逐项不等宽(清单 §6.1 T-25)。
//2026-08-27 补上「扣底」项(清单 §2.6 列的是 5 个按钮,此处原只排了 4 个)——
//排序按 §2.6 表:扣底紧邻底牌(两者分别看埋牌底牌 / 底牌,成对但不同批,勿写反)。
//【估值】扣底 78:清单未给该项宽度;同为两字按钮的「底牌」实测 78、「明牌」74,
//故取同类两字按钮的 78,待设计稿复核(其余四项 74/87/93/78 为清单 §6.5 实测值)
//【估值】扣底 78:清单未给该项宽度,参考图(等待叫分.png)底栏也只画出「底牌」一项
//(当时还没有「扣底」按钮,§2.6 后补)。依据取自【底牌】按钮实测的 78——不能笼统地说
//「两字按钮 = 78」:同为两字的「明牌」实测只有 74,两者并不相同,不可一概而论。
//故本项沿用「底牌」实测值 78,待设计稿复核(其余四项 74/87/93/78 为清单 §6.5 实测值)
EQW_Layout.FOOTER_FUNC_BUTTONS = {
kind: 'line', direction: 'horizontal', anchorX: 1250, anchorY: 672,
itemHeight: 30, spacing: 15, anchor: 'right',