refactor: 收口 BangDream 卡牌详情区块拼装
This commit is contained in:
parent
5a02effd9d
commit
0da6d21d26
@ -347,6 +347,8 @@ export interface TsuguHook {
|
||||
- 已生成查曲、查活动和查谱面 smoke 图片,验证 theme/spec/manifest 第一段迁移后本地图片输出非空,谱面预览资源路径未断。
|
||||
- 已新增 `render-blocks/detail-block-builder.ts`,活动详情页先接入 `DetailBlockBuilder` 统一 section、spacer 和 data block 拼装,去掉局部 `pushSection` 和手动分割线维护;`detail-block-builder.spec.ts` 覆盖 section 分割线与 spacer/data block 输出。
|
||||
- 本地验证时发现 Jest 无法解析 `skia-canvas/lib/v6/index.node`,根因是 `moduleFileExtensions` 未包含 `node`;已把 `.node` 原生扩展解析固化进 Jest 配置,避免后续渲染单测重复卡在同类问题。
|
||||
- 卡牌详情页已接入 `DetailBlockBuilder`,卡牌标题、插画、基础字段、缩略图和演出缩略图不再手写数组与分割线;`/查卡 472` 本地 smoke 输出非空长图。
|
||||
- `scripts/bangdream-render-smoke.ps1` 已固化图片 smoke 完成判定:先删除旧目标图,轮询 stdout 成功 JSON 和新图片文件;如果 Tsugu 后台 handle 导致 Node 未自然退出,则在图片落盘后清理本次进程并返回成功,避免已成功出图仍卡到超时。
|
||||
- 线上 `/qqbot/command/test` smoke 已固化为先按 `operationKey` 查询启用命令、传 `commandId`,并保留完整命令文本;避免默认 `preview` selfId 未绑定命令时误报“未匹配到命令”。
|
||||
|
||||
### Phase 6:策略 policy 和时间/档线规则
|
||||
|
||||
@ -24,6 +24,7 @@ $LogName = [System.IO.Path]::GetFileNameWithoutExtension($ResolvedOutFile)
|
||||
$StdoutLog = Join-Path $LogDir "$LogName.out.log"
|
||||
$StderrLog = Join-Path $LogDir "$LogName.err.log"
|
||||
Remove-Item -LiteralPath $StdoutLog,$StderrLog -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $ResolvedOutFile -Force -ErrorAction SilentlyContinue
|
||||
|
||||
$Payload = @{
|
||||
input = @{
|
||||
@ -80,7 +81,30 @@ $Process = Start-Process `
|
||||
-PassThru `
|
||||
-WindowStyle Hidden
|
||||
|
||||
if (-not $Process.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
function Test-SmokeCompleted {
|
||||
if (-not (Test-Path -LiteralPath $ResolvedOutFile)) { return $false }
|
||||
if ((Get-Item -LiteralPath $ResolvedOutFile).Length -le 0) { return $false }
|
||||
if (-not (Test-Path -LiteralPath $StdoutLog)) { return $false }
|
||||
return [bool](Select-String -Path $StdoutLog -Pattern '"bytes"' -Quiet)
|
||||
}
|
||||
|
||||
$Deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
||||
$CompletedByOutput = $false
|
||||
while (-not $Process.HasExited) {
|
||||
if (Test-SmokeCompleted) {
|
||||
$CompletedByOutput = $true
|
||||
Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue
|
||||
$Process.WaitForExit(5000) | Out-Null
|
||||
break
|
||||
}
|
||||
if ((Get-Date) -ge $Deadline) {
|
||||
break
|
||||
}
|
||||
Start-Sleep -Milliseconds 500
|
||||
$Process.Refresh()
|
||||
}
|
||||
|
||||
if ((-not $Process.HasExited) -and (-not $CompletedByOutput)) {
|
||||
Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue
|
||||
Write-Output "BangDream smoke timed out and process $($Process.Id) was killed."
|
||||
if (Test-Path $StdoutLog) { Get-Content $StdoutLog }
|
||||
@ -90,4 +114,8 @@ if (-not $Process.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
|
||||
if (Test-Path $StdoutLog) { Get-Content $StdoutLog }
|
||||
if (Test-Path $StderrLog) { Get-Content $StderrLog }
|
||||
if ($CompletedByOutput) {
|
||||
Write-Output "BangDream smoke output completed; lingering process $($Process.Id) was cleaned up."
|
||||
exit 0
|
||||
}
|
||||
exit $Process.ExitCode
|
||||
|
||||
@ -2,11 +2,9 @@ import { Card } from '@/qqbot/plugins/bangDream/tsugu/models/card';
|
||||
import { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
||||
import {
|
||||
drawList,
|
||||
line,
|
||||
drawListByServerList,
|
||||
drawListMerge,
|
||||
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-frame';
|
||||
import { drawDataBlock } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/data-block';
|
||||
import { drawCardIllustration } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/card-art';
|
||||
import { drawSkillInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-skill';
|
||||
import { drawTimeInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-time';
|
||||
@ -26,17 +24,7 @@ import {
|
||||
globalDefaultServer,
|
||||
serverNameFullList,
|
||||
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||
|
||||
/**
|
||||
* 在QQBot 图片视图层中推入区块。
|
||||
*
|
||||
* @param list - 待处理列表。
|
||||
* @param section - 区块参数。
|
||||
*/
|
||||
function pushSection(list: Array<Image | Canvas>, section: Image | Canvas) {
|
||||
list.push(section);
|
||||
list.push(line);
|
||||
}
|
||||
import { DetailBlockBuilder } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/detail-block-builder';
|
||||
|
||||
/**
|
||||
* 在QQBot 图片视图层中判断对象是否包含指定自有属性。
|
||||
@ -52,22 +40,22 @@ function hasOwn(source: object, key: string): boolean {
|
||||
/**
|
||||
* 在QQBot 图片视图层中追加卡牌Illustrations。
|
||||
*
|
||||
* @param list - 待处理列表。
|
||||
* @param builder - 详情区块构建器。
|
||||
* @param card - 卡牌参数。
|
||||
*/
|
||||
async function appendCardIllustrations(
|
||||
list: Array<Image | Canvas>,
|
||||
builder: DetailBlockBuilder,
|
||||
card: Card,
|
||||
): Promise<void> {
|
||||
for (const trainingStatus of card.getTrainingStatusList()) {
|
||||
list.push(
|
||||
builder.add(
|
||||
await drawCardIllustration({
|
||||
card,
|
||||
trainingStatus,
|
||||
isList: true,
|
||||
}),
|
||||
);
|
||||
list.push(new Canvas(800, 30));
|
||||
builder.addSpacer(30);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,20 +89,19 @@ function shouldShowGachaText(
|
||||
/**
|
||||
* 在QQBot 图片视图层中追加卡牌基础区块列表。
|
||||
*
|
||||
* @param list - 待处理列表。
|
||||
* @param builder - 详情区块构建器。
|
||||
* @param card - 卡牌参数。
|
||||
* @param source - 输入来源对象或数据集合。
|
||||
* @param displayedServerList - 允许展示或下载资源的服务器优先级列表。
|
||||
*/
|
||||
async function appendCardBaseSections(
|
||||
list: Array<Image | Canvas>,
|
||||
builder: DetailBlockBuilder,
|
||||
card: Card,
|
||||
source,
|
||||
displayedServerList: Server[],
|
||||
): Promise<void> {
|
||||
//类型 / 卡牌ID
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
drawListMerge([
|
||||
drawList({ key: '类型', text: card.getTypeName() }),
|
||||
drawList({ key: 'ID', text: card.cardId.toString() }),
|
||||
@ -122,12 +109,11 @@ async function appendCardBaseSections(
|
||||
);
|
||||
|
||||
//综合力
|
||||
pushSection(list, await drawCardStatInList(card));
|
||||
builder.addSection(await drawCardStatInList(card));
|
||||
|
||||
//技能
|
||||
const skill = new Skill(card.skillId);
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
await drawSkillInList(
|
||||
{ key: '技能', card: card, content: skill },
|
||||
displayedServerList,
|
||||
@ -135,22 +121,19 @@ async function appendCardBaseSections(
|
||||
);
|
||||
|
||||
//标题
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
await drawListByServerList(card.prefix, '标题', displayedServerList),
|
||||
);
|
||||
|
||||
//招募语
|
||||
if (shouldShowGachaText(card, source, displayedServerList)) {
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
await drawListByServerList(card.gachaText, '招募语', displayedServerList),
|
||||
);
|
||||
}
|
||||
|
||||
//发售日期
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
await drawTimeInList(
|
||||
{
|
||||
key: '发布日期',
|
||||
@ -161,8 +144,7 @@ async function appendCardBaseSections(
|
||||
);
|
||||
|
||||
//缩略图
|
||||
pushSection(
|
||||
list,
|
||||
builder.addSection(
|
||||
await drawCardListInList({
|
||||
key: '缩略图',
|
||||
cardList: [card],
|
||||
@ -307,14 +289,15 @@ async function drawCardDetail(
|
||||
await card.initFull();
|
||||
const source = card.source;
|
||||
|
||||
const list: Array<Image | Canvas> = [];
|
||||
const builder = new DetailBlockBuilder();
|
||||
|
||||
//标题
|
||||
list.push(await drawCardPrefixInList(card, displayedServerList));
|
||||
list.push(new Canvas(800, 30));
|
||||
builder
|
||||
.add(await drawCardPrefixInList(card, displayedServerList))
|
||||
.addSpacer(30);
|
||||
|
||||
//插画
|
||||
await appendCardIllustrations(list, card);
|
||||
await appendCardIllustrations(builder, card);
|
||||
|
||||
/*
|
||||
//乐队
|
||||
@ -335,13 +318,13 @@ async function drawCardDetail(
|
||||
list.push(await drawRarityInList({ rarity: card.rarity }))
|
||||
list.push(line)
|
||||
*/
|
||||
await appendCardBaseSections(list, card, source, displayedServerList);
|
||||
await appendCardBaseSections(builder, card, source, displayedServerList);
|
||||
|
||||
//演出缩略图
|
||||
list.push(await drawSdCharacterInList(card));
|
||||
builder.add(await drawSdCharacterInList(card));
|
||||
|
||||
//创建最终输出数组
|
||||
const listImage = drawDataBlock({ list });
|
||||
const listImage = builder.toDataBlock();
|
||||
const all = [];
|
||||
all.push(drawTitle('查询', '卡牌'));
|
||||
all.push(listImage);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user