From fc159ce11f3634c52f4c9ae72a6679e2774457c7 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 11 Oct 2026 15:57:14 +0800 Subject: [PATCH] feat(09-10): apply R-2/R-3/R-4/R-5/R-6/R-7 review fixes to equipbox, toolbox & shop - R-2: render descriptions via TextContent (equipbox/toolbox/shop) - R-3: add jsDoc to top-level definitions - R-4: add JSX section comments - R-5: un-export IHeroAttrItem and IShopItemEntry - R-6: isNil for literals, ! for objects (no === null / undefined) - R-7: move top-level openShop call into onMounted --- .../client-modules/src/ui/equipbox.tsx | 39 +++++++----- packages-user/client-modules/src/ui/shop.tsx | 59 +++++++++++-------- .../client-modules/src/ui/toolbox.tsx | 23 +++++--- 3 files changed, 77 insertions(+), 44 deletions(-) diff --git a/packages-user/client-modules/src/ui/equipbox.tsx b/packages-user/client-modules/src/ui/equipbox.tsx index 3187ee7..9dc348c 100644 --- a/packages-user/client-modules/src/ui/equipbox.tsx +++ b/packages-user/client-modules/src/ui/equipbox.tsx @@ -1,13 +1,14 @@ import { GameUI, SetupComponentOptions } from '@motajs/system'; import { computed, defineComponent, ref } from 'vue'; +import { isNil } from 'lodash-es'; import { Font } from '@motajs/render'; -import { Scroll } from '@user/client-base'; +import { Scroll, TextContent } from '@user/client-base'; import { EquipStatus, IHeroState } from '@user/data-base'; import { IHeroAttr } from '@user/data-common'; import { FULL_LOC, MAIN_HEIGHT, MAIN_WIDTH } from '../shared'; import { IUIPropsBase } from './types'; -export interface IHeroAttrItem { +interface IHeroAttrItem { /** 勇士属性的键名 */ readonly id: keyof IHeroAttr; /** 该属性在状态区域显示的中文名 */ @@ -21,6 +22,7 @@ export interface EquipBoxProps extends IUIPropsBase { attributes: readonly IHeroAttrItem[]; } +/** 装备界面组件的 props 声明 */ const equipBoxProps = { props: ['controller', 'instance', 'state', 'heroState', 'attributes'] } satisfies SetupComponentOptions; @@ -67,7 +69,9 @@ const titleFont = Font.defaults({ size: 15, weight: 700 }); /** 属性名与描述文本字体 */ const labelFont = Font.defaults({ size: 13 }); +/** 装备界面组件 */ export const EquipBox = defineComponent(props => { + /** 勇士状态对象 */ const hero = props.heroState; /** 当前选中的装备实例 uid,-1 表示未选中 */ @@ -112,7 +116,7 @@ export const EquipBox = defineComponent(props => { const equippedList = computed(() => { return hero.equip.slots.map((_, i) => { const uid = hero.equip.getEquipped(i); - if (uid === undefined) return null; + if (isNil(uid)) return null; return hero.items.equipment.get(uid); }); }); @@ -142,7 +146,7 @@ export const EquipBox = defineComponent(props => { const target = getTargetSlot(selected.value); if (target < 0) return null; const existing = hero.equip.getEquipped(target); - const another = existing === undefined ? -1 : existing; + const another = isNil(existing) ? -1 : existing; return hero.equip.compareEquip(selected.value, another, target); }); @@ -150,7 +154,7 @@ export const EquipBox = defineComponent(props => { const dragNum = computed(() => { if (dragUid.value < 0) return -1; const equip = hero.items.equipment.get(dragUid.value); - return equip === null ? -1 : equip.item.num; + return equip ? equip.item.num : -1; }); /** @@ -237,6 +241,7 @@ export const EquipBox = defineComponent(props => { onMove={ev => movePress(ev.absoluteX, ev.absoluteY)} onUp={endPress} > + {/* 状态区 */} (props => { })} + {/* 描述区 */} - {equip === null && ( + {!equip && ( (props => { fillStyle="#888888" /> )} - {equip !== null && ( + {equip && ( (props => { fillStyle="gold" /> )} - {equip !== null && ( + {equip && ( (props => { fillStyle="#bbbbbb" /> )} - {equip !== null && ( + {equip && ( - @@ -351,6 +357,7 @@ export const EquipBox = defineComponent(props => { )} + {/* 装备槽区 */} @@ -362,7 +369,7 @@ export const EquipBox = defineComponent(props => { {hero.equip.slots.map((name, i) => { const slotEquip = equippedList.value[i]; const isSelected = - slotEquip !== null && + !!slotEquip && slotEquip.uid === selected.value; return ( (props => { } lineWidth={isSelected ? 2 : 1} /> - {slotEquip !== null && ( + {slotEquip && ( (props => { + {/* 拥有装备区 */} @@ -517,6 +525,7 @@ export const EquipBox = defineComponent(props => { + {/* 右下角退出按钮 */} (props => { onClick={exit} /> + {/* 拖拽浮层 */} {dragging.value && ( (props => { }; }, equipBoxProps); +/** 装备界面的 UI 控制器 */ export const EquipBoxUI = new GameUI('equipbox', EquipBox); diff --git a/packages-user/client-modules/src/ui/shop.tsx b/packages-user/client-modules/src/ui/shop.tsx index b814542..4a62fcf 100644 --- a/packages-user/client-modules/src/ui/shop.tsx +++ b/packages-user/client-modules/src/ui/shop.tsx @@ -1,7 +1,7 @@ import { GameUI, SetupComponentOptions } from '@motajs/system'; -import { computed, defineComponent, ref } from 'vue'; +import { computed, defineComponent, onMounted, ref } from 'vue'; import { Font } from '@motajs/render'; -import { Scroll } from '@user/client-base'; +import { Scroll, TextContent } from '@user/client-base'; import { IHeroState, IShopState } from '@user/data-base'; import { IShopSystem } from '@user/data-system'; import { IHeroAttr } from '@user/data-common'; @@ -17,6 +17,7 @@ export interface ShopProps extends IUIPropsBase { shopSystem: IShopSystem; } +/** 商店界面组件的 props 声明 */ const shopProps = { props: [ 'controller', @@ -28,7 +29,7 @@ const shopProps = { ] } satisfies SetupComponentOptions; -export interface IShopItemEntry { +interface IShopItemEntry { /** 道具图块数字 */ readonly num: number; /** 道具字符串 id */ @@ -87,12 +88,15 @@ const titleFont = Font.defaults({ size: 14, weight: 700 }); /** 列表与信息字体 */ const textFont = Font.defaults({ size: 12 }); +/** 商店界面组件 */ export const Shop = defineComponent(props => { + /** 商店状态对象 */ const shop = props.shop; + /** 勇士状态对象 */ const hero = props.heroState; // 打开数据端当前商店,使其成为购买 / 售出交易的作用对象 - props.shopSystem.openShop(shop); + onMounted(() => props.shopSystem.openShop(shop)); /** 当前的购买 / 售出模式 */ const mode = ref<'buy' | 'sell'>('buy'); @@ -111,7 +115,7 @@ export const Shop = defineComponent(props => { for (const pair of shop.iterateItems()) { const num = pair[0]; const data = props.state.itemStore.getData(num); - if (data === null) continue; + if (!data) continue; const id = props.state.tileStore.id(num); const price = shop.getPrice(num); list.push({ @@ -215,13 +219,14 @@ export const Shop = defineComponent(props => { return () => { const entry = current.value; let total = 0; - if (entry !== null) { + if (entry) { const price = mode.value === 'buy' ? entry.buyPrice : entry.sellPrice; total = count.value * price; } return ( + {/* 顶部购买 / 售出切换栏 */} (props => { onClick={() => changeMode('sell')} /> + {/* 商店列表 */} {entries.value.map((item, i) => { const isSelected = item.num === selected.value; @@ -289,25 +295,28 @@ export const Shop = defineComponent(props => { ); })} + {/* 选中道具名称 */} + {/* 选中道具描述 */} - + {/* 价格信息 */} (props => { /> (props => { /> (props => { /> (props => { /> (props => { fillStyle="gold" /> + {/* 数量选择 */} (props => { fillStyle="#ffffff" onClick={() => adjustCount(COUNT_STEP)} /> + {/* 购买 / 售出确认按钮 */} (props => { onClick={confirm} /> + {/* 右下角退出按钮 */} (props => { }; }, shopProps); +/** 商店界面的 UI 控制器 */ export const ShopUI = new GameUI('shop', Shop); diff --git a/packages-user/client-modules/src/ui/toolbox.tsx b/packages-user/client-modules/src/ui/toolbox.tsx index 91d00ad..f381330 100644 --- a/packages-user/client-modules/src/ui/toolbox.tsx +++ b/packages-user/client-modules/src/ui/toolbox.tsx @@ -1,7 +1,7 @@ import { GameUI, SetupComponentOptions } from '@motajs/system'; import { computed, defineComponent, ref } from 'vue'; import { Font } from '@motajs/render'; -import { Scroll } from '@user/client-base'; +import { Scroll, TextContent } from '@user/client-base'; import { IHeroItemState, IHeroState } from '@user/data-base'; import { IHeroAttr } from '@user/data-common'; import { FULL_LOC, MAIN_HEIGHT, MAIN_WIDTH } from '../shared'; @@ -12,6 +12,7 @@ export interface ToolBoxProps extends IUIPropsBase { heroState: IHeroState; } +/** 道具栏组件的 props 声明 */ const toolBoxProps = { props: ['controller', 'instance', 'state', 'heroState'] } satisfies SetupComponentOptions; @@ -42,7 +43,9 @@ const itemFont = Font.defaults({ size: 13 }); /** 道具说明字体 */ const descFont = Font.defaults({ size: 12 }); +/** 道具栏组件 */ export const ToolBox = defineComponent(props => { + /** 勇士状态对象 */ const hero = props.heroState; /** 当前选中的道具图块数字,-1 表示未选中 */ @@ -101,6 +104,7 @@ export const ToolBox = defineComponent(props => { const current = selectedItem.value; return ( + {/* 永久道具列 */} (props => { font={titleFont} fillStyle="gold" /> + {/* 可消耗道具列 */} (props => { ); })} + {/* 道具名称 */} + {/* 道具说明 */} - {current === null && ( + {!current && ( (props => { fillStyle="#888888" /> )} - {current !== null && ( - )} + {/* 右下角退出按钮 */} (props => { }; }, toolBoxProps); +/** 道具栏的 UI 控制器 */ export const ToolBoxUI = new GameUI('toolbox', ToolBox);