mirror of
https://github.com/motajs/template.git
synced 2026-10-15 01:30:17 +08:00
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
This commit is contained in:
parent
4c383f6999
commit
fc159ce11f
@ -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<EquipBoxProps>;
|
||||
@ -67,7 +69,9 @@ const titleFont = Font.defaults({ size: 15, weight: 700 });
|
||||
/** 属性名与描述文本字体 */
|
||||
const labelFont = Font.defaults({ size: 13 });
|
||||
|
||||
/** 装备界面组件 */
|
||||
export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
/** 勇士状态对象 */
|
||||
const hero = props.heroState;
|
||||
|
||||
/** 当前选中的装备实例 uid,-1 表示未选中 */
|
||||
@ -112,7 +116,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(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<EquipBoxProps>(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<EquipBoxProps>(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<EquipBoxProps>(props => {
|
||||
onMove={ev => movePress(ev.absoluteX, ev.absoluteY)}
|
||||
onUp={endPress}
|
||||
>
|
||||
{/* 状态区 */}
|
||||
<text
|
||||
text="状态"
|
||||
loc={[8, 8]}
|
||||
@ -305,10 +310,11 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
})}
|
||||
</Scroll>
|
||||
|
||||
{/* 描述区 */}
|
||||
<container
|
||||
loc={[RIGHT_LEFT, DESC_TOP, RIGHT_WIDTH, DESC_HEIGHT]}
|
||||
>
|
||||
{equip === null && (
|
||||
{!equip && (
|
||||
<text
|
||||
text="未选择装备"
|
||||
loc={[8, 12]}
|
||||
@ -317,7 +323,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
fillStyle="#888888"
|
||||
/>
|
||||
)}
|
||||
{equip !== null && (
|
||||
{equip && (
|
||||
<text
|
||||
text={equip.item.name}
|
||||
loc={[8, 12]}
|
||||
@ -326,7 +332,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
fillStyle="gold"
|
||||
/>
|
||||
)}
|
||||
{equip !== null && (
|
||||
{equip && (
|
||||
<text
|
||||
text={`装备孔:${equip.item.equip.slots.join(' / ')}`}
|
||||
loc={[8, 36]}
|
||||
@ -335,15 +341,15 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
fillStyle="#bbbbbb"
|
||||
/>
|
||||
)}
|
||||
{equip !== null && (
|
||||
{equip && (
|
||||
<Scroll
|
||||
noscroll
|
||||
loc={[0, 56, RIGHT_WIDTH, DESC_HEIGHT - 56]}
|
||||
>
|
||||
<text
|
||||
<TextContent
|
||||
text={equip.item.text}
|
||||
loc={[8, 4]}
|
||||
anc={[0, 0]}
|
||||
width={RIGHT_WIDTH - 16}
|
||||
loc={[8, 4, RIGHT_WIDTH - 16, DESC_HEIGHT - 60]}
|
||||
font={labelFont}
|
||||
fillStyle="#dddddd"
|
||||
/>
|
||||
@ -351,6 +357,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
)}
|
||||
</container>
|
||||
|
||||
{/* 装备槽区 */}
|
||||
<container
|
||||
loc={[RIGHT_LEFT, SLOT_TOP, RIGHT_WIDTH, SLOT_HEIGHT]}
|
||||
>
|
||||
@ -362,7 +369,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
{hero.equip.slots.map((name, i) => {
|
||||
const slotEquip = equippedList.value[i];
|
||||
const isSelected =
|
||||
slotEquip !== null &&
|
||||
!!slotEquip &&
|
||||
slotEquip.uid === selected.value;
|
||||
return (
|
||||
<container
|
||||
@ -399,7 +406,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
}
|
||||
lineWidth={isSelected ? 2 : 1}
|
||||
/>
|
||||
{slotEquip !== null && (
|
||||
{slotEquip && (
|
||||
<icon
|
||||
icon={slotEquip.item.num}
|
||||
loc={[
|
||||
@ -437,6 +444,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
</Scroll>
|
||||
</container>
|
||||
|
||||
{/* 拥有装备区 */}
|
||||
<container
|
||||
loc={[RIGHT_LEFT, OWNED_TOP, RIGHT_WIDTH, OWNED_HEIGHT]}
|
||||
>
|
||||
@ -517,6 +525,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
</Scroll>
|
||||
</container>
|
||||
|
||||
{/* 右下角退出按钮 */}
|
||||
<text
|
||||
text="退出"
|
||||
loc={[MAIN_WIDTH - 12, MAIN_HEIGHT - 10]}
|
||||
@ -527,6 +536,7 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
onClick={exit}
|
||||
/>
|
||||
|
||||
{/* 拖拽浮层 */}
|
||||
{dragging.value && (
|
||||
<icon
|
||||
icon={dragNum.value}
|
||||
@ -545,4 +555,5 @@ export const EquipBox = defineComponent<EquipBoxProps>(props => {
|
||||
};
|
||||
}, equipBoxProps);
|
||||
|
||||
/** 装备界面的 UI 控制器 */
|
||||
export const EquipBoxUI = new GameUI('equipbox', EquipBox);
|
||||
|
||||
@ -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<ShopProps>;
|
||||
|
||||
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<ShopProps>(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<ShopProps>(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<ShopProps>(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 (
|
||||
<container loc={FULL_LOC}>
|
||||
{/* 顶部购买 / 售出切换栏 */}
|
||||
<container loc={[0, 0, MAIN_WIDTH, MODE_BAR_HEIGHT]}>
|
||||
<text
|
||||
text="购买选项"
|
||||
@ -242,6 +247,7 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
onClick={() => changeMode('sell')}
|
||||
/>
|
||||
</container>
|
||||
{/* 商店列表 */}
|
||||
<Scroll loc={[0, LIST_TOP, LIST_WIDTH, LIST_HEIGHT]}>
|
||||
{entries.value.map((item, i) => {
|
||||
const isSelected = item.num === selected.value;
|
||||
@ -289,25 +295,28 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
);
|
||||
})}
|
||||
</Scroll>
|
||||
{/* 选中道具名称 */}
|
||||
<text
|
||||
text={entry === null ? '未选择道具' : entry.name}
|
||||
text={entry ? entry.name : '未选择道具'}
|
||||
loc={[INFO_LEFT + 14, NAME_TOP + 13]}
|
||||
anc={[0, 0.5]}
|
||||
font={titleFont}
|
||||
fillStyle="gold"
|
||||
/>
|
||||
{/* 选中道具描述 */}
|
||||
<Scroll
|
||||
noscroll
|
||||
loc={[INFO_LEFT, DESC_TOP, INFO_WIDTH, DESC_HEIGHT]}
|
||||
>
|
||||
<text
|
||||
text={entry === null ? '' : entry.text}
|
||||
loc={[14, 4]}
|
||||
anc={[0, 0]}
|
||||
<TextContent
|
||||
text={entry ? entry.text : ''}
|
||||
width={INFO_WIDTH - 28}
|
||||
loc={[14, 4, INFO_WIDTH - 28, DESC_HEIGHT - 8]}
|
||||
font={textFont}
|
||||
fillStyle="#dddddd"
|
||||
/>
|
||||
</Scroll>
|
||||
{/* 价格信息 */}
|
||||
<container
|
||||
loc={[
|
||||
INFO_LEFT,
|
||||
@ -325,9 +334,9 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
/>
|
||||
<text
|
||||
text={
|
||||
entry === null
|
||||
? '-'
|
||||
: core.formatBigNumber(entry.buyPrice)
|
||||
entry
|
||||
? core.formatBigNumber(entry.buyPrice)
|
||||
: '-'
|
||||
}
|
||||
loc={[INFO_WIDTH - 14, 10]}
|
||||
anc={[1, 0.5]}
|
||||
@ -343,9 +352,9 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
/>
|
||||
<text
|
||||
text={
|
||||
entry === null
|
||||
? '-'
|
||||
: core.formatBigNumber(entry.sellPrice)
|
||||
entry
|
||||
? core.formatBigNumber(entry.sellPrice)
|
||||
: '-'
|
||||
}
|
||||
loc={[INFO_WIDTH - 14, 30]}
|
||||
anc={[1, 0.5]}
|
||||
@ -361,9 +370,9 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
/>
|
||||
<text
|
||||
text={
|
||||
entry === null
|
||||
? '-'
|
||||
: core.formatBigNumber(entry.stock)
|
||||
entry
|
||||
? core.formatBigNumber(entry.stock)
|
||||
: '-'
|
||||
}
|
||||
loc={[INFO_WIDTH - 14, 50]}
|
||||
anc={[1, 0.5]}
|
||||
@ -379,9 +388,9 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
/>
|
||||
<text
|
||||
text={
|
||||
entry === null
|
||||
? '-'
|
||||
: core.formatBigNumber(entry.owned)
|
||||
entry
|
||||
? core.formatBigNumber(entry.owned)
|
||||
: '-'
|
||||
}
|
||||
loc={[INFO_WIDTH - 14, 70]}
|
||||
anc={[1, 0.5]}
|
||||
@ -403,6 +412,7 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
fillStyle="gold"
|
||||
/>
|
||||
</container>
|
||||
{/* 数量选择 */}
|
||||
<text
|
||||
text={mode.value === 'buy' ? '购买数量' : '售出数量'}
|
||||
loc={[INFO_LEFT + INFO_WIDTH / 2, COUNT_LABEL_Y]}
|
||||
@ -453,6 +463,7 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
fillStyle="#ffffff"
|
||||
onClick={() => adjustCount(COUNT_STEP)}
|
||||
/>
|
||||
{/* 购买 / 售出确认按钮 */}
|
||||
<container loc={[INFO_LEFT, CONFIRM_Y, INFO_WIDTH, 30]}>
|
||||
<g-rectr
|
||||
loc={[14, 0, INFO_WIDTH - 28, 30]}
|
||||
@ -473,6 +484,7 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
onClick={confirm}
|
||||
/>
|
||||
</container>
|
||||
{/* 右下角退出按钮 */}
|
||||
<text
|
||||
text="退出"
|
||||
loc={[MAIN_WIDTH - 12, MAIN_HEIGHT - 10]}
|
||||
@ -487,4 +499,5 @@ export const Shop = defineComponent<ShopProps>(props => {
|
||||
};
|
||||
}, shopProps);
|
||||
|
||||
/** 商店界面的 UI 控制器 */
|
||||
export const ShopUI = new GameUI('shop', Shop);
|
||||
|
||||
@ -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<IHeroAttr>;
|
||||
}
|
||||
|
||||
/** 道具栏组件的 props 声明 */
|
||||
const toolBoxProps = {
|
||||
props: ['controller', 'instance', 'state', 'heroState']
|
||||
} satisfies SetupComponentOptions<ToolBoxProps>;
|
||||
@ -42,7 +43,9 @@ const itemFont = Font.defaults({ size: 13 });
|
||||
/** 道具说明字体 */
|
||||
const descFont = Font.defaults({ size: 12 });
|
||||
|
||||
/** 道具栏组件 */
|
||||
export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
/** 勇士状态对象 */
|
||||
const hero = props.heroState;
|
||||
|
||||
/** 当前选中的道具图块数字,-1 表示未选中 */
|
||||
@ -101,6 +104,7 @@ export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
const current = selectedItem.value;
|
||||
return (
|
||||
<container loc={FULL_LOC}>
|
||||
{/* 永久道具列 */}
|
||||
<text
|
||||
text="永久道具"
|
||||
loc={[8, HEADER_HEIGHT / 2]}
|
||||
@ -108,6 +112,7 @@ export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
font={titleFont}
|
||||
fillStyle="gold"
|
||||
/>
|
||||
{/* 可消耗道具列 */}
|
||||
<text
|
||||
text="可消耗道具"
|
||||
loc={[COLUMN_WIDTH + 8, HEADER_HEIGHT / 2]}
|
||||
@ -222,18 +227,20 @@ export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
);
|
||||
})}
|
||||
</Scroll>
|
||||
{/* 道具名称 */}
|
||||
<text
|
||||
text={current === null ? '未选择道具' : current.raw.name}
|
||||
text={current ? current.raw.name : '未选择道具'}
|
||||
loc={[INFO_LEFT + 8, 14]}
|
||||
anc={[0, 0]}
|
||||
font={titleFont}
|
||||
fillStyle="gold"
|
||||
/>
|
||||
{/* 道具说明 */}
|
||||
<Scroll
|
||||
noscroll
|
||||
loc={[INFO_LEFT, DESC_TOP, COLUMN_WIDTH, DESC_HEIGHT]}
|
||||
>
|
||||
{current === null && (
|
||||
{!current && (
|
||||
<text
|
||||
text="未选择道具"
|
||||
loc={[8, 4]}
|
||||
@ -242,16 +249,17 @@ export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
fillStyle="#888888"
|
||||
/>
|
||||
)}
|
||||
{current !== null && (
|
||||
<text
|
||||
{current && (
|
||||
<TextContent
|
||||
text={current.raw.text}
|
||||
loc={[8, 4]}
|
||||
anc={[0, 0]}
|
||||
width={COLUMN_WIDTH - 16}
|
||||
loc={[8, 4, COLUMN_WIDTH - 16, DESC_HEIGHT - 8]}
|
||||
font={descFont}
|
||||
fillStyle="#dddddd"
|
||||
/>
|
||||
)}
|
||||
</Scroll>
|
||||
{/* 右下角退出按钮 */}
|
||||
<text
|
||||
text="退出"
|
||||
loc={[MAIN_WIDTH - 12, MAIN_HEIGHT - 10]}
|
||||
@ -266,4 +274,5 @@ export const ToolBox = defineComponent<ToolBoxProps>(props => {
|
||||
};
|
||||
}, toolBoxProps);
|
||||
|
||||
/** 道具栏的 UI 控制器 */
|
||||
export const ToolBoxUI = new GameUI('toolbox', ToolBox);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user