refactor: 收口 BangDream 卡牌详情区块拼装
This commit is contained in:
parent
5a02effd9d
commit
0da6d21d26
@ -347,6 +347,8 @@ export interface TsuguHook {
|
|||||||
- 已生成查曲、查活动和查谱面 smoke 图片,验证 theme/spec/manifest 第一段迁移后本地图片输出非空,谱面预览资源路径未断。
|
- 已生成查曲、查活动和查谱面 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 输出。
|
- 已新增 `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 配置,避免后续渲染单测重复卡在同类问题。
|
- 本地验证时发现 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 未绑定命令时误报“未匹配到命令”。
|
- 线上 `/qqbot/command/test` smoke 已固化为先按 `operationKey` 查询启用命令、传 `commandId`,并保留完整命令文本;避免默认 `preview` selfId 未绑定命令时误报“未匹配到命令”。
|
||||||
|
|
||||||
### Phase 6:策略 policy 和时间/档线规则
|
### Phase 6:策略 policy 和时间/档线规则
|
||||||
|
|||||||
@ -24,6 +24,7 @@ $LogName = [System.IO.Path]::GetFileNameWithoutExtension($ResolvedOutFile)
|
|||||||
$StdoutLog = Join-Path $LogDir "$LogName.out.log"
|
$StdoutLog = Join-Path $LogDir "$LogName.out.log"
|
||||||
$StderrLog = Join-Path $LogDir "$LogName.err.log"
|
$StderrLog = Join-Path $LogDir "$LogName.err.log"
|
||||||
Remove-Item -LiteralPath $StdoutLog,$StderrLog -Force -ErrorAction SilentlyContinue
|
Remove-Item -LiteralPath $StdoutLog,$StderrLog -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -LiteralPath $ResolvedOutFile -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
$Payload = @{
|
$Payload = @{
|
||||||
input = @{
|
input = @{
|
||||||
@ -80,7 +81,30 @@ $Process = Start-Process `
|
|||||||
-PassThru `
|
-PassThru `
|
||||||
-WindowStyle Hidden
|
-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
|
Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue
|
||||||
Write-Output "BangDream smoke timed out and process $($Process.Id) was killed."
|
Write-Output "BangDream smoke timed out and process $($Process.Id) was killed."
|
||||||
if (Test-Path $StdoutLog) { Get-Content $StdoutLog }
|
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 $StdoutLog) { Get-Content $StdoutLog }
|
||||||
if (Test-Path $StderrLog) { Get-Content $StderrLog }
|
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
|
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 { Skill } from '@/qqbot/plugins/bangDream/tsugu/models/skill';
|
||||||
import {
|
import {
|
||||||
drawList,
|
drawList,
|
||||||
line,
|
|
||||||
drawListByServerList,
|
drawListByServerList,
|
||||||
drawListMerge,
|
drawListMerge,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-frame';
|
} 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 { drawCardIllustration } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/card-art';
|
||||||
import { drawSkillInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-skill';
|
import { drawSkillInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-skill';
|
||||||
import { drawTimeInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-time';
|
import { drawTimeInList } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/list-time';
|
||||||
@ -26,17 +24,7 @@ import {
|
|||||||
globalDefaultServer,
|
globalDefaultServer,
|
||||||
serverNameFullList,
|
serverNameFullList,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
|
import { DetailBlockBuilder } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/detail-block-builder';
|
||||||
/**
|
|
||||||
* 在QQBot 图片视图层中推入区块。
|
|
||||||
*
|
|
||||||
* @param list - 待处理列表。
|
|
||||||
* @param section - 区块参数。
|
|
||||||
*/
|
|
||||||
function pushSection(list: Array<Image | Canvas>, section: Image | Canvas) {
|
|
||||||
list.push(section);
|
|
||||||
list.push(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中判断对象是否包含指定自有属性。
|
* 在QQBot 图片视图层中判断对象是否包含指定自有属性。
|
||||||
@ -52,22 +40,22 @@ function hasOwn(source: object, key: string): boolean {
|
|||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中追加卡牌Illustrations。
|
* 在QQBot 图片视图层中追加卡牌Illustrations。
|
||||||
*
|
*
|
||||||
* @param list - 待处理列表。
|
* @param builder - 详情区块构建器。
|
||||||
* @param card - 卡牌参数。
|
* @param card - 卡牌参数。
|
||||||
*/
|
*/
|
||||||
async function appendCardIllustrations(
|
async function appendCardIllustrations(
|
||||||
list: Array<Image | Canvas>,
|
builder: DetailBlockBuilder,
|
||||||
card: Card,
|
card: Card,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const trainingStatus of card.getTrainingStatusList()) {
|
for (const trainingStatus of card.getTrainingStatusList()) {
|
||||||
list.push(
|
builder.add(
|
||||||
await drawCardIllustration({
|
await drawCardIllustration({
|
||||||
card,
|
card,
|
||||||
trainingStatus,
|
trainingStatus,
|
||||||
isList: true,
|
isList: true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
list.push(new Canvas(800, 30));
|
builder.addSpacer(30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,20 +89,19 @@ function shouldShowGachaText(
|
|||||||
/**
|
/**
|
||||||
* 在QQBot 图片视图层中追加卡牌基础区块列表。
|
* 在QQBot 图片视图层中追加卡牌基础区块列表。
|
||||||
*
|
*
|
||||||
* @param list - 待处理列表。
|
* @param builder - 详情区块构建器。
|
||||||
* @param card - 卡牌参数。
|
* @param card - 卡牌参数。
|
||||||
* @param source - 输入来源对象或数据集合。
|
* @param source - 输入来源对象或数据集合。
|
||||||
* @param displayedServerList - 允许展示或下载资源的服务器优先级列表。
|
* @param displayedServerList - 允许展示或下载资源的服务器优先级列表。
|
||||||
*/
|
*/
|
||||||
async function appendCardBaseSections(
|
async function appendCardBaseSections(
|
||||||
list: Array<Image | Canvas>,
|
builder: DetailBlockBuilder,
|
||||||
card: Card,
|
card: Card,
|
||||||
source,
|
source,
|
||||||
displayedServerList: Server[],
|
displayedServerList: Server[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
//类型 / 卡牌ID
|
//类型 / 卡牌ID
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
drawListMerge([
|
drawListMerge([
|
||||||
drawList({ key: '类型', text: card.getTypeName() }),
|
drawList({ key: '类型', text: card.getTypeName() }),
|
||||||
drawList({ key: 'ID', text: card.cardId.toString() }),
|
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);
|
const skill = new Skill(card.skillId);
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
await drawSkillInList(
|
await drawSkillInList(
|
||||||
{ key: '技能', card: card, content: skill },
|
{ key: '技能', card: card, content: skill },
|
||||||
displayedServerList,
|
displayedServerList,
|
||||||
@ -135,22 +121,19 @@ async function appendCardBaseSections(
|
|||||||
);
|
);
|
||||||
|
|
||||||
//标题
|
//标题
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
await drawListByServerList(card.prefix, '标题', displayedServerList),
|
await drawListByServerList(card.prefix, '标题', displayedServerList),
|
||||||
);
|
);
|
||||||
|
|
||||||
//招募语
|
//招募语
|
||||||
if (shouldShowGachaText(card, source, displayedServerList)) {
|
if (shouldShowGachaText(card, source, displayedServerList)) {
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
await drawListByServerList(card.gachaText, '招募语', displayedServerList),
|
await drawListByServerList(card.gachaText, '招募语', displayedServerList),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//发售日期
|
//发售日期
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
await drawTimeInList(
|
await drawTimeInList(
|
||||||
{
|
{
|
||||||
key: '发布日期',
|
key: '发布日期',
|
||||||
@ -161,8 +144,7 @@ async function appendCardBaseSections(
|
|||||||
);
|
);
|
||||||
|
|
||||||
//缩略图
|
//缩略图
|
||||||
pushSection(
|
builder.addSection(
|
||||||
list,
|
|
||||||
await drawCardListInList({
|
await drawCardListInList({
|
||||||
key: '缩略图',
|
key: '缩略图',
|
||||||
cardList: [card],
|
cardList: [card],
|
||||||
@ -307,14 +289,15 @@ async function drawCardDetail(
|
|||||||
await card.initFull();
|
await card.initFull();
|
||||||
const source = card.source;
|
const source = card.source;
|
||||||
|
|
||||||
const list: Array<Image | Canvas> = [];
|
const builder = new DetailBlockBuilder();
|
||||||
|
|
||||||
//标题
|
//标题
|
||||||
list.push(await drawCardPrefixInList(card, displayedServerList));
|
builder
|
||||||
list.push(new Canvas(800, 30));
|
.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(await drawRarityInList({ rarity: card.rarity }))
|
||||||
list.push(line)
|
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 = [];
|
const all = [];
|
||||||
all.push(drawTitle('查询', '卡牌'));
|
all.push(drawTitle('查询', '卡牌'));
|
||||||
all.push(listImage);
|
all.push(listImage);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user