fix: 修正FF14查价字典树关系

This commit is contained in:
sunlei 2026-06-03 23:29:27 +08:00
parent 40180ee0b0
commit a9bc963442
6 changed files with 137 additions and 35 deletions

View File

@ -598,39 +598,39 @@ ON DUPLICATE KEY UPDATE
INSERT INTO `admin_dict` (`id`, `dict_code`, `label`, `value`, `children_code`, `sort`, `status`)
VALUES
(2041700000000301101, 'FF14_MARKET_REGION', '中国', '中国', NULL, 1, 1),
(2041700000000301201, 'FF14_MARKET_DATA_CENTER', '陆行鸟', '陆行鸟', '中国', 1, 1),
(2041700000000301202, 'FF14_MARKET_DATA_CENTER', '莫古力', '莫古力', '中国', 2, 1),
(2041700000000301203, 'FF14_MARKET_DATA_CENTER', '猫小胖', '猫小胖', '中国', 3, 1),
(2041700000000301204, 'FF14_MARKET_DATA_CENTER', '豆豆柴', '豆豆柴', '中国', 4, 1),
(2041700000000301301, 'FF14_MARKET_WORLD', '红玉海', '红玉海', '陆行鸟', 1, 1),
(2041700000000301302, 'FF14_MARKET_WORLD', '神意之地', '神意之地', '陆行鸟', 2, 1),
(2041700000000301303, 'FF14_MARKET_WORLD', '拉诺西亚', '拉诺西亚', '陆行鸟', 3, 1),
(2041700000000301304, 'FF14_MARKET_WORLD', '幻影群岛', '幻影群岛', '陆行鸟', 4, 1),
(2041700000000301305, 'FF14_MARKET_WORLD', '萌芽池', '萌芽池', '陆行鸟', 5, 1),
(2041700000000301306, 'FF14_MARKET_WORLD', '宇宙和音', '宇宙和音', '陆行鸟', 6, 1),
(2041700000000301307, 'FF14_MARKET_WORLD', '沃仙曦染', '沃仙曦染', '陆行鸟', 7, 1),
(2041700000000301308, 'FF14_MARKET_WORLD', '晨曦王座', '晨曦王座', '陆行鸟', 8, 1),
(2041700000000301309, 'FF14_MARKET_WORLD', '白银乡', '白银乡', '莫古力', 9, 1),
(2041700000000301310, 'FF14_MARKET_WORLD', '白金幻象', '白金幻象', '莫古力', 10, 1),
(2041700000000301311, 'FF14_MARKET_WORLD', '神拳痕', '神拳痕', '莫古力', 11, 1),
(2041700000000301312, 'FF14_MARKET_WORLD', '潮风亭', '潮风亭', '莫古力', 12, 1),
(2041700000000301313, 'FF14_MARKET_WORLD', '旅人栈桥', '旅人栈桥', '莫古力', 13, 1),
(2041700000000301314, 'FF14_MARKET_WORLD', '拂晓之间', '拂晓之间', '莫古力', 14, 1),
(2041700000000301315, 'FF14_MARKET_WORLD', '龙巢神殿', '龙巢神殿', '莫古力', 15, 1),
(2041700000000301316, 'FF14_MARKET_WORLD', '梦羽宝境', '梦羽宝境', '莫古力', 16, 1),
(2041700000000301317, 'FF14_MARKET_WORLD', '紫水栈桥', '紫水栈桥', '猫小胖', 17, 1),
(2041700000000301318, 'FF14_MARKET_WORLD', '延夏', '延夏', '猫小胖', 18, 1),
(2041700000000301319, 'FF14_MARKET_WORLD', '静语庄园', '静语庄园', '猫小胖', 19, 1),
(2041700000000301320, 'FF14_MARKET_WORLD', '摩杜纳', '摩杜纳', '猫小胖', 20, 1),
(2041700000000301321, 'FF14_MARKET_WORLD', '海猫茶屋', '海猫茶屋', '猫小胖', 21, 1),
(2041700000000301322, 'FF14_MARKET_WORLD', '柔风海湾', '柔风海湾', '猫小胖', 22, 1),
(2041700000000301323, 'FF14_MARKET_WORLD', '琥珀原', '琥珀原', '猫小胖', 23, 1),
(2041700000000301324, 'FF14_MARKET_WORLD', '水晶塔', '水晶塔', '豆豆柴', 24, 1),
(2041700000000301325, 'FF14_MARKET_WORLD', '银泪湖', '银泪湖', '豆豆柴', 25, 1),
(2041700000000301326, 'FF14_MARKET_WORLD', '太阳海岸', '太阳海岸', '豆豆柴', 26, 1),
(2041700000000301327, 'FF14_MARKET_WORLD', '伊修加德', '伊修加德', '豆豆柴', 27, 1),
(2041700000000301328, 'FF14_MARKET_WORLD', '红茶川', '红茶川', '豆豆柴', 28, 1)
(2041700000000301101, 'FF14_MARKET_REGION', '中国', '中国', 'FF14_MARKET_DATA_CENTER_CN', 1, 1),
(2041700000000301201, 'FF14_MARKET_DATA_CENTER_CN', '陆行鸟', '陆行鸟', 'FF14_MARKET_WORLD_CN_LUXINGNIAO', 1, 1),
(2041700000000301202, 'FF14_MARKET_DATA_CENTER_CN', '莫古力', '莫古力', 'FF14_MARKET_WORLD_CN_MOGULI', 2, 1),
(2041700000000301203, 'FF14_MARKET_DATA_CENTER_CN', '猫小胖', '猫小胖', 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', 3, 1),
(2041700000000301204, 'FF14_MARKET_DATA_CENTER_CN', '豆豆柴', '豆豆柴', 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', 4, 1),
(2041700000000301301, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '红玉海', '红玉海', NULL, 1, 1),
(2041700000000301302, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '神意之地', '神意之地', NULL, 2, 1),
(2041700000000301303, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '拉诺西亚', '拉诺西亚', NULL, 3, 1),
(2041700000000301304, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '幻影群岛', '幻影群岛', NULL, 4, 1),
(2041700000000301305, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '萌芽池', '萌芽池', NULL, 5, 1),
(2041700000000301306, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '宇宙和音', '宇宙和音', NULL, 6, 1),
(2041700000000301307, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '沃仙曦染', '沃仙曦染', NULL, 7, 1),
(2041700000000301308, 'FF14_MARKET_WORLD_CN_LUXINGNIAO', '晨曦王座', '晨曦王座', NULL, 8, 1),
(2041700000000301309, 'FF14_MARKET_WORLD_CN_MOGULI', '白银乡', '白银乡', NULL, 1, 1),
(2041700000000301310, 'FF14_MARKET_WORLD_CN_MOGULI', '白金幻象', '白金幻象', NULL, 2, 1),
(2041700000000301311, 'FF14_MARKET_WORLD_CN_MOGULI', '神拳痕', '神拳痕', NULL, 3, 1),
(2041700000000301312, 'FF14_MARKET_WORLD_CN_MOGULI', '潮风亭', '潮风亭', NULL, 4, 1),
(2041700000000301313, 'FF14_MARKET_WORLD_CN_MOGULI', '旅人栈桥', '旅人栈桥', NULL, 5, 1),
(2041700000000301314, 'FF14_MARKET_WORLD_CN_MOGULI', '拂晓之间', '拂晓之间', NULL, 6, 1),
(2041700000000301315, 'FF14_MARKET_WORLD_CN_MOGULI', '龙巢神殿', '龙巢神殿', NULL, 7, 1),
(2041700000000301316, 'FF14_MARKET_WORLD_CN_MOGULI', '梦羽宝境', '梦羽宝境', NULL, 8, 1),
(2041700000000301317, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '紫水栈桥', '紫水栈桥', NULL, 1, 1),
(2041700000000301318, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '延夏', '延夏', NULL, 2, 1),
(2041700000000301319, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '静语庄园', '静语庄园', NULL, 3, 1),
(2041700000000301320, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '摩杜纳', '摩杜纳', NULL, 4, 1),
(2041700000000301321, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '海猫茶屋', '海猫茶屋', NULL, 5, 1),
(2041700000000301322, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '柔风海湾', '柔风海湾', NULL, 6, 1),
(2041700000000301323, 'FF14_MARKET_WORLD_CN_MAOXIAOPANG', '琥珀原', '琥珀原', NULL, 7, 1),
(2041700000000301324, 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', '水晶塔', '水晶塔', NULL, 1, 1),
(2041700000000301325, 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', '银泪湖', '银泪湖', NULL, 2, 1),
(2041700000000301326, 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', '太阳海岸', '太阳海岸', NULL, 3, 1),
(2041700000000301327, 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', '伊修加德', '伊修加德', NULL, 4, 1),
(2041700000000301328, 'FF14_MARKET_WORLD_CN_DOUDOUCHAI', '红茶川', '红茶川', NULL, 5, 1)
ON DUPLICATE KEY UPDATE
`label` = VALUES(`label`),
`children_code` = VALUES(`children_code`),

View File

@ -29,7 +29,7 @@ type AdminDictSerialized = {
value: string;
};
type AdminDictTreeItem = AdminDictSerialized & {
export type AdminDictTreeItem = AdminDictSerialized & {
children?: AdminDictTreeItem[];
treeKey: string;
};

View File

@ -4,6 +4,7 @@ import type { QqbotCommand } from './qqbot-command.entity';
import type { QqbotNormalizedMessage } from '../qqbot.types';
import {
buildQqbotFf14MarketCatalog,
buildQqbotFf14MarketCatalogFromTree,
QQBOT_FF14_MARKET_DICT_CODES,
type QqbotFf14MarketCatalog,
isQqbotFf14DataCenterName,
@ -276,6 +277,13 @@ export class QqbotCommandParserService {
}
private async getFf14MarketCatalog() {
const treeCatalog = buildQqbotFf14MarketCatalogFromTree(
await this.dictService.tree({
dictCode: QQBOT_FF14_MARKET_DICT_CODES.region,
}),
);
if (treeCatalog.dataCenters.length > 0) return treeCatalog;
const [regions, dataCenters, worlds] = await Promise.all([
this.dictService.getDictItemsByKey(QQBOT_FF14_MARKET_DICT_CODES.region),
this.dictService.getDictItemsByKey(

View File

@ -5,6 +5,7 @@ import * as https from 'node:https';
import { DictService } from '../../../admin/dict/dict.service';
import {
buildQqbotFf14MarketCatalog,
buildQqbotFf14MarketCatalogFromTree,
QQBOT_FF14_MARKET_DICT_CODES,
resolveQqbotFf14MarketTarget,
} from './qqbot-ff14-worlds';
@ -290,6 +291,13 @@ export class QqbotFf14ClientService {
}
private async getFf14MarketCatalog() {
const treeCatalog = buildQqbotFf14MarketCatalogFromTree(
await this.dictService.tree({
dictCode: QQBOT_FF14_MARKET_DICT_CODES.region,
}),
);
if (treeCatalog.dataCenters.length > 0) return treeCatalog;
const [regions, dataCenters, worlds] = await Promise.all([
this.dictService.getDictItemsByKey(QQBOT_FF14_MARKET_DICT_CODES.region),
this.dictService.getDictItemsByKey(

View File

@ -1,5 +1,6 @@
import {
buildQqbotFf14MarketCatalog,
buildQqbotFf14MarketCatalogFromTree,
resolveQqbotFf14MarketTarget,
} from './qqbot-ff14-worlds';
@ -34,4 +35,52 @@ describe('qqbot ff14 market worlds', () => {
}),
).toThrow('服务器 琥珀原 不属于大区 陆行鸟');
});
it('builds catalog from dict tree relations', () => {
const treeCatalog = buildQqbotFf14MarketCatalogFromTree([
{
children: [
{
children: [
{
dictCode: 'FF14_MARKET_WORLD_CN_MAOXIAOPANG',
id: 'world-1',
label: '琥珀原',
sort: 1,
status: 1,
treeKey: 'region-1/dc-1/world-1',
value: '琥珀原',
},
],
childrenCode: 'FF14_MARKET_WORLD_CN_MAOXIAOPANG',
dictCode: 'FF14_MARKET_DATA_CENTER_CN',
id: 'dc-1',
label: '猫小胖',
sort: 1,
status: 1,
treeKey: 'region-1/dc-1',
value: '猫小胖',
},
],
childrenCode: 'FF14_MARKET_DATA_CENTER_CN',
dictCode: 'FF14_MARKET_REGION',
id: 'region-1',
label: '中国',
sort: 1,
status: 1,
treeKey: 'region-1',
value: '中国',
},
]);
expect(
resolveQqbotFf14MarketTarget(treeCatalog, { world: '琥珀原' }),
).toEqual({
dataCenter: '猫小胖',
label: '中国 / 猫小胖 / 琥珀原',
region: '中国',
target: '琥珀原',
world: '琥珀原',
});
});
});

View File

@ -1,4 +1,7 @@
import type { AdminDictItem } from '../../../admin/dict/dict.service';
import type {
AdminDictItem,
AdminDictTreeItem,
} from '../../../admin/dict/dict.service';
export type QqbotFf14DataCenter = {
name: string;
@ -56,6 +59,40 @@ export function buildQqbotFf14MarketCatalog(input: {
};
}
export function buildQqbotFf14MarketCatalogFromTree(
roots: AdminDictTreeItem[],
): QqbotFf14MarketCatalog {
const regionNodes = roots.filter(
(item) => item.dictCode === QQBOT_FF14_MARKET_DICT_CODES.region,
);
const regions = regionNodes.map(getDictDisplayValue).filter(Boolean);
const defaultRegion = regions[0];
const dataCenters = regionNodes.flatMap((regionNode) => {
const region = getDictDisplayValue(regionNode) || defaultRegion || '';
return (regionNode.children || [])
.map((dataCenterNode) => {
const name = getDictDisplayValue(dataCenterNode);
if (!name) return null;
return {
name,
region,
worlds: (dataCenterNode.children || [])
.map(getDictDisplayValue)
.filter(Boolean),
};
})
.filter((item): item is QqbotFf14DataCenter => !!item);
});
return {
dataCenters,
defaultRegion,
regions,
};
}
export function isQqbotFf14DataCenterName(
catalog: QqbotFf14MarketCatalog,
value?: string,