Commit c854a99e authored by Chunchi Che's avatar Chunchi Che

optimize checkCardModal store

parent 3803129a
Pipeline #21521 passed with stages
in 13 minutes and 49 seconds
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import MsgSelectCard = ygopro.StocGameMessage.MsgSelectCard; import MsgSelectCard = ygopro.StocGameMessage.MsgSelectCard;
import { CardZoneToChinese, fetchCheckCardMeta, messageStore } from "@/stores"; import { fetchCheckCardMeta, messageStore } from "@/stores";
export default (selectCard: MsgSelectCard) => { export default (selectCard: MsgSelectCard) => {
const _player = selectCard.player; const cancelable = selectCard.cancelable;
const _cancelable = selectCard.cancelable; // TODO: 处理可取消逻辑
const min = selectCard.min; const min = selectCard.min;
const max = selectCard.max; const max = selectCard.max;
const cards = selectCard.cards; const cards = selectCard.cards;
// TODO: handle release_param // TODO: handle release_param
messageStore.checkCardModal.selectMin = min; messageStore.selectCardActions.min = min;
messageStore.checkCardModal.selectMax = max; messageStore.selectCardActions.max = max;
messageStore.checkCardModal.onSubmit = "sendSelectCardResponse"; messageStore.selectCardActions.cancelAble = cancelable;
for (const card of cards) { for (const card of cards) {
const tagName = CardZoneToChinese(card.location.location); fetchCheckCardMeta({
fetchCheckCardMeta(card.location.location, {
code: card.code, code: card.code,
location: card.location, location: card.location,
response: card.response, response: card.response,
}); });
} }
messageStore.checkCardModal.isOpen = true; messageStore.selectCardActions.isOpen = true;
}; };
...@@ -7,7 +7,6 @@ import { ...@@ -7,7 +7,6 @@ import {
type MsgSelectChain = ygopro.StocGameMessage.MsgSelectChain; type MsgSelectChain = ygopro.StocGameMessage.MsgSelectChain;
export default (selectChain: MsgSelectChain) => { export default (selectChain: MsgSelectChain) => {
const player = selectChain.player;
const spCount = selectChain.special_count; const spCount = selectChain.special_count;
const forced = selectChain.forced; const forced = selectChain.forced;
const hint0 = selectChain.hint0; const hint0 = selectChain.hint0;
...@@ -58,14 +57,12 @@ export default (selectChain: MsgSelectChain) => { ...@@ -58,14 +57,12 @@ export default (selectChain: MsgSelectChain) => {
case 3: { case 3: {
// 处理强制发动的卡 // 处理强制发动的卡
messageStore.checkCardModal.selectMin = 1; messageStore.selectCardActions.min = 1;
messageStore.checkCardModal.selectMax = 1; messageStore.selectCardActions.max = 1;
messageStore.checkCardModal.onSubmit = "sendSelectChainResponse"; messageStore.selectCardActions.cancelAble = !forced;
messageStore.checkCardModal.cancelAble = !forced;
messageStore.checkCardModal.cancelResponse = -1;
for (const chain of chains) { for (const chain of chains) {
fetchCheckCardMeta(chain.location.location, { fetchCheckCardMeta({
code: chain.code, code: chain.code,
location: chain.location, location: chain.location,
response: chain.response, response: chain.response,
...@@ -75,7 +72,7 @@ export default (selectChain: MsgSelectChain) => { ...@@ -75,7 +72,7 @@ export default (selectChain: MsgSelectChain) => {
fetchSelectHintMeta({ fetchSelectHintMeta({
selectHintData: 203, selectHintData: 203,
}); });
messageStore.checkCardModal.isOpen = true; messageStore.selectCardActions.isOpen = true;
break; break;
} }
......
import { fetchStrings, ygopro } from "@/api"; import { fetchStrings, ygopro } from "@/api";
import { CardMeta, fetchCard } from "@/api/cards"; import { CardMeta, fetchCard } from "@/api/cards";
import { CardZoneToChinese, messageStore } from "@/stores"; import { messageStore } from "@/stores";
type MsgSelectEffectYn = ygopro.StocGameMessage.MsgSelectEffectYn; type MsgSelectEffectYn = ygopro.StocGameMessage.MsgSelectEffectYn;
// 这里改成了 async 不知道有没有影响 // 这里改成了 async 不知道有没有影响
export default async (selectEffectYn: MsgSelectEffectYn) => { export default async (selectEffectYn: MsgSelectEffectYn) => {
const player = selectEffectYn.player;
const code = selectEffectYn.code; const code = selectEffectYn.code;
const location = selectEffectYn.location; const location = selectEffectYn.location;
const effect_description = selectEffectYn.effect_description; const effect_description = selectEffectYn.effect_description;
...@@ -20,7 +19,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => { ...@@ -20,7 +19,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => {
) => { ) => {
const desc1 = desc.replace( const desc1 = desc.replace(
`[%ls]`, `[%ls]`,
CardZoneToChinese(cardLocation.location) fetchStrings("!system", cardLocation.location + 1000)
); );
const desc2 = desc1.replace(`[%ls]`, cardMeta.text.name || "[?]"); const desc2 = desc1.replace(`[%ls]`, cardMeta.text.name || "[?]");
return desc2; return desc2;
...@@ -29,14 +28,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => { ...@@ -29,14 +28,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => {
const desc1 = desc.replace(`[%ls]`, cardMeta.text.name || "[?]"); const desc1 = desc.replace(`[%ls]`, cardMeta.text.name || "[?]");
return desc1; return desc1;
}; };
// dispatch(
// fetchYesNoMeta({
// code,
// location,
// descCode: effect_description,
// textGenerator,
// })
// );
// TODO: 国际化文案 // TODO: 国际化文案
const desc = fetchStrings("!system", effect_description); const desc = fetchStrings("!system", effect_description);
......
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { fetchCheckCardMetasV3, messageStore } from "@/stores"; import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum; type MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum;
export default (selectSum: MsgSelectSum) => { export default (selectSum: MsgSelectSum) => {
messageStore.checkCardModalV3.overflow = selectSum.overflow != 0; messageStore.selectCardActions.overflow = selectSum.overflow != 0;
messageStore.checkCardModalV3.allLevel = selectSum.level_sum; messageStore.selectCardActions.totalLevels = selectSum.level_sum;
messageStore.checkCardModalV3.selectMin = selectSum.min; messageStore.selectCardActions.min = selectSum.min;
messageStore.checkCardModalV3.selectMax = selectSum.max; messageStore.selectCardActions.max = selectSum.max;
fetchCheckCardMetasV3({ for (const option of selectSum.must_select_cards) {
mustSelect: true, fetchCheckCardMeta(option, false, true);
options: selectSum.must_select_cards, }
});
fetchCheckCardMetasV3({ for (const option of selectSum.selectable_cards) {
mustSelect: false, fetchCheckCardMeta(option);
options: selectSum.selectable_cards, }
});
messageStore.checkCardModalV3.isOpen = true; messageStore.selectCardActions.isOpen = true;
}; };
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { fetchCheckCardMetasV3, messageStore } from "@/stores"; import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectTribute = ygopro.StocGameMessage.MsgSelectTribute; type MsgSelectTribute = ygopro.StocGameMessage.MsgSelectTribute;
export default (selectTribute: MsgSelectTribute) => { export default (selectTribute: MsgSelectTribute) => {
// TODO: 当玩家选择卡数大于`max`时,是否也合法? // TODO: 当玩家选择卡数大于`max`时,是否也合法?
messageStore.checkCardModalV3.overflow = true; messageStore.selectCardActions.overflow = true;
messageStore.checkCardModalV3.allLevel = 0; messageStore.selectCardActions.totalLevels = 0;
messageStore.checkCardModalV3.selectMin = selectTribute.min; messageStore.selectCardActions.min = selectTribute.min;
messageStore.checkCardModalV3.selectMax = selectTribute.max; messageStore.selectCardActions.max = selectTribute.max;
fetchCheckCardMetasV3({ for (const option of selectTribute.selectable_cards) {
mustSelect: false, fetchCheckCardMeta(option);
options: selectTribute.selectable_cards.map((card) => { }
return {
code: card.code,
location: card.location,
level1: card.level,
level2: card.level,
response: card.response,
};
}),
});
messageStore.checkCardModalV3.isOpen = true; messageStore.selectCardActions.isOpen = true;
}; };
import { ygopro } from "@/api"; import { ygopro } from "@/api";
import { fetchCheckCardMetasV2, messageStore } from "@/stores"; import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectUnselectCard = ygopro.StocGameMessage.MsgSelectUnselectCard; type MsgSelectUnselectCard = ygopro.StocGameMessage.MsgSelectUnselectCard;
...@@ -11,33 +11,17 @@ export default ({ ...@@ -11,33 +11,17 @@ export default ({
selectable_cards: selectableCards, selectable_cards: selectableCards,
selected_cards: selectedCards, selected_cards: selectedCards,
}: MsgSelectUnselectCard) => { }: MsgSelectUnselectCard) => {
messageStore.checkCardModalV2.isOpen = true; messageStore.selectCardActions.isOpen = true;
messageStore.checkCardModalV2.finishAble = finishable; messageStore.selectCardActions.finishAble = finishable;
messageStore.checkCardModalV2.cancelAble = cancelable; messageStore.selectCardActions.cancelAble = cancelable;
messageStore.checkCardModalV2.selectMin = min; messageStore.selectCardActions.min = min;
messageStore.checkCardModalV2.selectMax = max; messageStore.selectCardActions.max = max;
fetchCheckCardMetasV2({ for (const option of selectableCards) {
selected: false, fetchCheckCardMeta(option);
options: selectableCards.map((card) => { }
return {
code: card.code,
location: card.location,
response: card.response,
};
}),
});
fetchCheckCardMetasV2({ for (const option of selectedCards) {
selected: true, fetchCheckCardMeta(option, true);
options: selectedCards.map((card) => { }
return {
code: card.code,
location: card.location,
response: card.response,
};
}),
});
messageStore.checkCardModalV2.responseable = true;
}; };
import { ygopro } from "@/api";
export function CardZoneToChinese(zone: ygopro.CardZone): string {
switch (zone) {
case ygopro.CardZone.DECK: {
return "卡组";
}
case ygopro.CardZone.HAND: {
return "手牌";
}
case ygopro.CardZone.EXTRA: {
return "额外卡组";
}
case ygopro.CardZone.GRAVE: {
return "墓地";
}
case ygopro.CardZone.FZONE: {
return "FZONE";
}
case ygopro.CardZone.MZONE: {
return "怪兽区";
}
case ygopro.CardZone.SZONE: {
return "魔法陷阱区";
}
case ygopro.CardZone.REMOVED: {
return "除外区";
}
case ygopro.CardZone.OVERLAY: {
return "超量区";
}
case ygopro.CardZone.PZONE: {
return "灵摆区";
}
case ygopro.CardZone.ONFIELD: {
return "场地区";
}
default: {
return "未知区域";
}
}
}
...@@ -2,102 +2,50 @@ import { ygopro } from "@/api"; ...@@ -2,102 +2,50 @@ import { ygopro } from "@/api";
import { fetchCard, getCardStr } from "@/api/cards"; import { fetchCard, getCardStr } from "@/api/cards";
import { matStore, messageStore } from "@/stores"; import { matStore, messageStore } from "@/stores";
import { CardZoneToChinese } from "./cardZoneToChinese";
type Location =
| ygopro.CardLocation
| ReturnType<typeof ygopro.CardLocation.prototype.toObject>;
function cmpCardLocation(
left: Location,
right?: Location,
strict?: boolean
): boolean {
if (strict) {
return JSON.stringify(left) === JSON.stringify(right);
} else {
return (
left.controler === right?.controler &&
left.location === right?.location &&
left.sequence === right?.sequence
);
}
}
/**
* 这段代码定义了一个异步函数 fetchCheckCardMeta,它的作用是获取一张卡片的元数据并将其添加到某个名为 messageStore.checkCardModal 的对象上。
该函数的第一个参数是一个枚举值 ygopro.CardZone,表示卡片所在的区域。其余参数是一个包含卡片编号、位置、响应码和效果描述代码等信息的对象。
首先,这个函数会根据区域类型调用 CardZoneToChinese() 函数生成一个中文名称。然后,它会调用 fetchCard() 异步函数来获取指定卡片的元数据 meta。
接下来,函数会根据传递进来的 location 对象获取卡片所属的控制者,并根据控制者判断这张卡片是我方的还是对方的。然后,它会根据卡片的位置信息获取卡片的实际 ID,并构造一个新的选项 newOption。
接着,函数会遍历已有的 messageStore.checkCardModal.tags,查找是否存在名为 combinedTagName 的标签。如果找到了,则将新选项 newOption 加入该标签的选项列表中并立即返回。如果找不到,则创建一个新标签,并将新选项 newOption 添加到其中。
最后,函数会再次遍历所有标签,查找是否存在名为 combinedTagName 的标签。如果找到了,则遍历该标签中的所有选项,并查找是否存在与 location 对象中指定的卡片位置信息完全相同的选项。如果找到了,则更新该选项的元数据和效果描述等信息。
*/
export const fetchCheckCardMeta = async ( export const fetchCheckCardMeta = async (
zone: ygopro.CardZone,
{ {
code, code,
location, location,
level1,
level2,
response, response,
effectDescCode, effectDescCode,
}: { }: {
code: number; code: number;
location: ygopro.CardLocation; location: ygopro.CardLocation;
level1?: number;
level2?: number;
response: number; response: number;
effectDescCode?: number; effectDescCode?: number;
} },
selected?: boolean,
mustSelect?: boolean
) => { ) => {
const tagName = CardZoneToChinese(zone);
const meta = await fetchCard(code);
const controller = location.controler; const controller = location.controler;
const combinedTagName = matStore.isMe(controller)
? `我方的${tagName}`
: `对方的${tagName}`;
const newID = const newID =
code != 0 code != 0
? code ? code
: matStore.in(location.location).of(controller)[location.sequence] : matStore.in(location.location).of(controller)[location.sequence]
?.occupant?.id || 0; ?.occupant?.id || 0;
const meta = await fetchCard(code);
const effectDesc = effectDescCode
? getCardStr(meta, effectDescCode & 0xf)
: undefined;
const newOption = { const newOption = {
meta: { id: newID, data: {}, text: {} }, code: newID,
location: location.toObject(), location: location.toObject(),
effectDescCode, level1,
level2,
effectDesc,
response, response,
}; };
for (const tag of messageStore.checkCardModal.tags) {
if (tag.tagName === combinedTagName) {
tag.options.push(newOption);
return;
}
}
messageStore.checkCardModal.tags.push({
tagName: combinedTagName,
options: [newOption],
});
for (const tag of messageStore.checkCardModal.tags) { if (selected) {
if (tag.tagName === combinedTagName) { messageStore.selectCardActions.selecteds.push(newOption);
for (const old of tag.options) { } else if (mustSelect) {
if (meta.id == old.meta.id && cmpCardLocation(location, old.location)) { messageStore.selectCardActions.mustSelects.push(newOption);
const cardID = old.meta.id; } else {
old.meta = meta; messageStore.selectCardActions.selectables.push(newOption);
old.meta.id = cardID;
const effectDescCode = old.effectDescCode;
const effectDesc = effectDescCode
? getCardStr(old.meta, effectDescCode & 0xf)
: undefined;
old.effectDesc = effectDesc;
}
}
}
} }
}; };
export * from "./cardZoneToChinese";
export * from "./fetchCheckCardMeta"; export * from "./fetchCheckCardMeta";
export * from "./fetchHint"; export * from "./fetchHint";
export * from "./fetchOverlayMeta"; export * from "./fetchOverlayMeta";
......
import { fetchCard, type ygopro } from "@/api";
import { getCardByLocation, messageStore } from "@/stores";
export const fetchCheckCardMetasV2 = async ({
selected,
options,
}: {
selected: boolean;
options: {
code: number;
location: ygopro.CardLocation;
response: number;
name?: string;
desc?: string;
}[];
}) => {
const metas = await Promise.all(
options.map(async (option) => {
return await fetchCard(option.code, true);
})
);
for (const option of options) {
if (option.code == 0) {
const newCode = getCardByLocation(option.location)?.occupant?.id || 0;
option.code = newCode;
}
}
options.forEach((option) => {
metas.forEach((meta) => {
if (option.code == meta.id) {
option.name = meta.text.name;
option.desc = meta.text.desc;
}
});
});
if (selected) {
messageStore.checkCardModalV2.selectedOptions = options;
} else {
messageStore.checkCardModalV2.selectableOptions = options;
}
};
import { fetchCard, type ygopro } from "@/api";
import { getCardByLocation, messageStore } from "@/stores";
export const fetchCheckCardMetasV3 = async ({
mustSelect,
options,
}: {
mustSelect: boolean;
options: {
code: number;
location: ygopro.CardLocation;
level1: number;
level2: number;
response: number;
}[];
}) => {
const metas = await Promise.all(
options.map(async (option) => {
return await fetchCard(option.code, true);
})
);
const newOptions = options.map((option) => {
if (option.code == 0) {
const newCode = getCardByLocation(option.location)?.occupant?.id || 0;
option.code = newCode;
}
return {
meta: { id: option.code, data: {}, text: {} },
level1: option.level1,
level2: option.level2,
response: option.response,
};
});
newOptions.forEach((option) => {
metas.forEach((meta) => {
if (option.meta.id == meta.id) {
option.meta = meta;
}
});
});
if (mustSelect) {
messageStore.checkCardModalV3.mustSelectList = newOptions;
} else {
messageStore.checkCardModalV3.selectAbleList = newOptions;
}
};
export * from "./clearAllIdleInteractivities"; export * from "./clearAllIdleInteractivities";
export * from "./clearAllPlaceInteradtivities"; export * from "./clearAllPlaceInteradtivities";
export * from "./fetchCheckCardMetasV2";
export * from "./fetchCheckCardMetasV3";
...@@ -5,25 +5,17 @@ import type { ModalState } from "./types"; ...@@ -5,25 +5,17 @@ import type { ModalState } from "./types";
export const messageStore = proxy<ModalState>({ export const messageStore = proxy<ModalState>({
cardModal: { isOpen: false, interactivies: [], counters: {} }, cardModal: { isOpen: false, interactivies: [], counters: {} },
cardListModal: { isOpen: false, list: [] }, cardListModal: { isOpen: false, list: [] },
checkCardModal: { isOpen: false, cancelAble: false, tags: [] }, selectCardActions: {
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCardModalV2: {
isOpen: false, isOpen: false,
cancelAble: false, cancelAble: false,
finishAble: false, finishAble: false,
responseable: false, selecteds: [],
selectableOptions: [], selectables: [],
selectedOptions: [], mustSelects: [],
},
checkCardModalV3: {
isOpen: false,
overflow: false,
allLevel: 0,
mustSelectList: [],
selectAbleList: [],
}, },
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCounterModal: { checkCounterModal: {
isOpen: false, isOpen: false,
options: [], options: [],
......
import type { CardMeta, ygopro } from "@/api"; import type { CardMeta, ygopro } from "@/api";
type CardLocation = ReturnType<typeof ygopro.CardLocation.prototype.toObject>; type CardLocation = ReturnType<typeof ygopro.CardLocation.prototype.toObject>;
interface Option {
// card id
code: number;
location?: CardLocation;
// 效果
effectDesc?: string;
// 作为素材的cost,比如同调召唤的星级
level1?: number;
level2?: number;
response: number;
}
export interface ModalState { export interface ModalState {
// 卡牌弹窗 // 卡牌弹窗
cardModal: { cardModal: {
...@@ -17,24 +29,23 @@ export interface ModalState { ...@@ -17,24 +29,23 @@ export interface ModalState {
interactivies: { desc: string; response: number }[]; interactivies: { desc: string; response: number }[];
}[]; }[];
}; };
// 卡牌选择弹窗 // 卡牌选择状态
checkCardModal: { selectCardActions: {
isOpen: boolean; isOpen: boolean;
onSubmit?: string; min?: number;
selectMin?: number; max?: number;
selectMax?: number;
cancelAble: boolean; cancelAble: boolean;
cancelResponse?: number; finishAble: boolean;
tags: { // 上级/同调/超量/链接召唤的总cost
tagName: string; totalLevels?: number;
options: { // cost是否可以溢出,比如同调召唤是false,某些链接召唤是true
meta: CardMeta; overflow?: boolean;
location?: CardLocation; // 已经选择的列表
effectDescCode?: number; selecteds: Option[];
effectDesc?: string; // 可以选择的列表
response: number; selectables: Option[];
}[]; // 必须选择的列表
}[]; mustSelects: Option[];
}; };
// Yes or No弹窗 // Yes or No弹窗
yesNoModal: { yesNoModal: {
...@@ -51,48 +62,6 @@ export interface ModalState { ...@@ -51,48 +62,6 @@ export interface ModalState {
isOpen: boolean; isOpen: boolean;
options: { msg: string; response: number }[]; options: { msg: string; response: number }[];
}; };
// 卡牌选择弹窗V2
checkCardModalV2: {
isOpen: boolean;
cancelAble: boolean;
finishAble: boolean;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
selectableOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
selectedOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
};
// 卡牌选择弹窗V3
checkCardModalV3: {
isOpen: boolean;
overflow: boolean;
allLevel: number;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
mustSelectList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
selectAbleList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
};
// 指示器选择弹窗 // 指示器选择弹窗
checkCounterModal: { checkCounterModal: {
isOpen: boolean; isOpen: boolean;
......
...@@ -5,8 +5,6 @@ import { ...@@ -5,8 +5,6 @@ import {
CardListModal, CardListModal,
CardModal, CardModal,
CheckCardModal, CheckCardModal,
CheckCardModalV2,
CheckCardModalV3,
CheckCounterModal, CheckCounterModal,
HintNotification, HintNotification,
OptionModal, OptionModal,
...@@ -28,8 +26,6 @@ const NeosDuel = () => { ...@@ -28,8 +26,6 @@ const NeosDuel = () => {
<YesNoModal /> <YesNoModal />
<PositionModal /> <PositionModal />
<OptionModal /> <OptionModal />
<CheckCardModalV2 />
<CheckCardModalV3 />
<CheckCounterModal /> <CheckCounterModal />
<SortCardModal /> <SortCardModal />
</> </>
......
...@@ -4,58 +4,60 @@ import { Button, Col, Popover, Row } from "antd"; ...@@ -4,58 +4,60 @@ import { Button, Col, Popover, Row } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { sendSelectCardResponse, sendSelectChainResponse } from "@/api"; import { fetchStrings, sendSelectCardResponse } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { matStore, messageStore } from "@/stores"; import { matStore, messageStore } from "@/stores";
import { DragModal } from "./DragModal"; import { DragModal } from "./DragModal";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
const CANCEL_RESPONSE = -1;
const FINISH_RESPONSE = -1;
const { checkCardModal } = messageStore; const { selectCardActions } = messageStore;
export const CheckCardModal = () => { export const CheckCardModal = () => {
const snapCheckCardModal = useSnapshot(checkCardModal); const snap = useSnapshot(selectCardActions);
const isOpen = snapCheckCardModal.isOpen; const isOpen = snap.isOpen;
const min = snapCheckCardModal.selectMin ?? 0; const min = snap.min ?? 0;
const max = snapCheckCardModal.selectMax ?? 10; const max = snap.max ?? 10;
const tabs = snapCheckCardModal.tags; const selecteds = snap.selecteds;
const onSubmit = snapCheckCardModal.onSubmit; const selectables = snap.selectables;
const cancelAble = snapCheckCardModal.cancelAble; const mustSelects = snap.mustSelects;
const cancelResponse = snapCheckCardModal.cancelResponse;
const [response, setResponse] = useState<number[]>([]); const [response, setResponse] = useState([]);
const defaultValue: number[] = [];
const hint = useSnapshot(matStore.hint); const hint = useSnapshot(matStore.hint);
const preHintMsg = hint?.esHint || ""; const preHintMsg = hint?.esHint || "";
const selectHintMsg = hint?.esSelectHint || "请选择卡片"; const selectHintMsg = hint?.esSelectHint || "请选择卡片";
// TODO: 这里可以考虑更好地封装 const cancelable = snap.cancelAble;
const sendResponseHandler = ( const finishable = snap.finishAble;
handlerName: string | undefined, const totalLevels = snap.totalLevels || 0;
response: number[] const overflow = snap.overflow || false;
) => { const LevelSum1 = mustSelects
switch (handlerName) { .concat(response)
case "sendSelectChainResponse": { .map((option) => option.level1 || 0)
sendSelectChainResponse(response[0]); .reduce((sum, current) => sum + current, 0);
break; const LevelSum2 = mustSelects
} .concat(response)
case "sendSelectCardResponse": { .map((option) => option.level2 || 0)
sendSelectCardResponse(response); .reduce((sum, current) => sum + current, 0);
break; const levelMatched = overflow
} ? LevelSum1 >= totalLevels || LevelSum2 >= totalLevels
default: { : LevelSum1 == totalLevels || LevelSum2 == totalLevels;
} const submitable =
} response.length >= min && response.length <= max && levelMatched;
};
const resetCheckCardModal = () => { const resetCheckCardModal = () => {
checkCardModal.isOpen = false; selectCardActions.isOpen = false;
checkCardModal.selectMin = undefined; selectCardActions.min = undefined;
checkCardModal.selectMax = undefined; selectCardActions.max = undefined;
checkCardModal.cancelAble = false; selectCardActions.cancelAble = false;
checkCardModal.cancelResponse = undefined; selectCardActions.totalLevels = undefined;
checkCardModal.tags = []; selectCardActions.selecteds = [];
selectCardActions.selectables = [];
selectCardActions.finishAble = false;
selectCardActions.overflow = false;
}; };
return ( return (
...@@ -66,34 +68,42 @@ export const CheckCardModal = () => { ...@@ -66,34 +68,42 @@ export const CheckCardModal = () => {
footer={ footer={
<> <>
<Button <Button
disabled={response.length < min || response.length > max} disabled={!submitable}
onClick={() => { onClick={() => {
sendResponseHandler(onSubmit, response); const values = mustSelects
checkCardModal.isOpen = false; .concat(response)
.map((option) => option.response);
sendSelectCardResponse(values);
resetCheckCardModal(); resetCheckCardModal();
}} }}
onFocus={() => {}} onFocus={() => {}}
onBlur={() => {}} onBlur={() => {}}
> >
submit {fetchStrings("!system", 1211)}
</Button> </Button>
{cancelAble ? (
<Button <Button
disabled={!finishable}
onClick={() => { onClick={() => {
if (cancelResponse) { sendSelectCardResponse([FINISH_RESPONSE]);
sendResponseHandler(onSubmit, [cancelResponse]);
}
checkCardModal.isOpen = false;
resetCheckCardModal(); resetCheckCardModal();
}} }}
onFocus={() => {}} onFocus={() => {}}
onBlur={() => {}} onBlur={() => {}}
> >
cancel {fetchStrings("!system", 1296)}
</Button>
<Button
disabled={!cancelable}
onClick={() => {
sendSelectCardResponse([CANCEL_RESPONSE]);
resetCheckCardModal();
}}
onFocus={() => {}}
onBlur={() => {}}
>
{fetchStrings("!system", 1295)}
</Button> </Button>
) : (
<></>
)}
</> </>
} }
width={800} width={800}
...@@ -102,42 +112,57 @@ export const CheckCardModal = () => { ...@@ -102,42 +112,57 @@ export const CheckCardModal = () => {
multiple multiple
bordered bordered
size="small" size="small"
defaultValue={defaultValue}
onChange={(value) => { onChange={(value) => {
// @ts-ignore // @ts-ignore
setResponse(value); setResponse(value);
}} }}
> >
{tabs.map((tab, idx) => { <Row>
return ( {selectables.map((option, idx) => {
<Row key={idx}>
{tab.options.map((option, idx) => {
return ( return (
<Col span={4} key={idx}> <Col span={4} key={idx}>
<HoverCheckCard <HoverCheckCard
hoverContent={option.effectDesc} hoverContent={option.effectDesc}
title={option.meta.text.name}
description={option.meta.text.desc}
style={{ width: 120 }} style={{ width: 120 }}
cover={ cover={
<img <img
alt={option.meta.id.toString()} alt={option.code.toString()}
src={ src={
option.meta.id option.code
? `${NeosConfig.cardImgUrl}/${option.meta.id}.jpg` ? `${NeosConfig.cardImgUrl}/${option.code}.jpg`
: `${NeosConfig.assetsPath}/card_back.jpg` : `${NeosConfig.assetsPath}/card_back.jpg`
} }
style={{ width: 100 }} style={{ width: 100 }}
/> />
} }
value={option.response} value={option}
/> />
</Col> </Col>
); );
})} })}
</Row> </Row>
<p>{fetchStrings("!system", 212)}</p>
<Row>
{selecteds.concat(mustSelects).map((option, idx) => {
return (
<Col span={4} key={idx}>
<CheckCard
style={{ width: 120 }}
cover={
<img
alt={option.code.toString()}
src={
option.code
? `${NeosConfig.cardImgUrl}/${option.code}.jpg`
: `${NeosConfig.assetsPath}/card_back.jpg`
}
/>
}
/>
</Col>
); );
})} })}
</Row>
</CheckCard.Group> </CheckCard.Group>
</DragModal> </DragModal>
); );
......
import { CheckCard } from "@ant-design/pro-components";
import { Button, Card, Col, Row } from "antd";
import React from "react";
import { useSnapshot } from "valtio";
import { sendSelectUnselectCardResponse } from "@/api";
import { useConfig } from "@/config";
import { matStore, messageStore } from "@/stores";
import { DragModal } from "./DragModal";
const { checkCardModalV2 } = messageStore;
const NeosConfig = useConfig();
export const CheckCardModalV2 = () => {
const snapCheckCardModalV2 = useSnapshot(checkCardModalV2);
const isOpen = snapCheckCardModalV2.isOpen;
const min = snapCheckCardModalV2.selectMin ?? 0;
const max = snapCheckCardModalV2.selectMax ?? 10;
const cancelable = snapCheckCardModalV2.cancelAble;
const finishable = snapCheckCardModalV2.finishAble;
const selectableOptions = snapCheckCardModalV2.selectableOptions;
const selectedOptions = snapCheckCardModalV2.selectedOptions;
const responseable = snapCheckCardModalV2.responseable;
const hint = useSnapshot(matStore.hint);
const preHintMsg = hint?.esHint || "";
const selectHintMsg = hint?.esSelectHint || "请选择卡片";
const resetCheckCardModalV2 = () => {
checkCardModalV2.isOpen = false;
checkCardModalV2.finishAble = false;
checkCardModalV2.cancelAble = false;
checkCardModalV2.responseable = false;
checkCardModalV2.selectableOptions = [];
checkCardModalV2.selectedOptions = [];
};
const onFinishOrCancel = () => {
sendSelectUnselectCardResponse({ cancel_or_finish: true });
checkCardModalV2.isOpen = false;
checkCardModalV2.responseable = false;
resetCheckCardModalV2();
};
return (
<DragModal
title={`${preHintMsg} ${selectHintMsg} ${min}-${max}`}
open={isOpen}
closable={false}
footer={
<>
<Button
disabled={!finishable || !responseable}
onClick={onFinishOrCancel}
>
finish
</Button>
<Button
disabled={!cancelable || !responseable}
onClick={onFinishOrCancel}
>
cancel
</Button>
</>
}
width={800}
>
<CheckCard.Group
bordered
size="small"
onChange={(value) => {
if (responseable) {
// @ts-ignore
sendSelectUnselectCardResponse({ selected_ptr: value });
checkCardModalV2.isOpen = false;
checkCardModalV2.responseable = false;
}
}}
>
<Row>
{selectableOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<CheckCard
title={option.name}
description={option.desc}
style={{ width: 120 }}
cover={
<img
alt={option.code.toString()}
src={`${NeosConfig.cardImgUrl}/${option.code}.jpg`}
style={{ width: 100 }}
/>
}
value={option.response}
/>
</Col>
);
})}
</Row>
</CheckCard.Group>
<p>已经选择的卡片</p>
<Row>
{selectedOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<Card
hoverable
style={{ width: 120 }}
cover={
<img
alt={option.code.toString()}
src={`${NeosConfig.cardImgUrl}/${option.code}.jpg`}
/>
}
/>
</Col>
);
})}
</Row>
</DragModal>
);
};
import { CheckCard } from "@ant-design/pro-components";
import { Button, Card, Col, Row } from "antd";
import React, { useState } from "react";
import { useSnapshot } from "valtio";
import { sendSelectCardResponse } from "@/api";
import { useConfig } from "@/config";
import { matStore, messageStore } from "@/stores";
import { DragModal } from "./DragModal";
const NeosConfig = useConfig();
const { checkCardModalV3 } = messageStore;
export const CheckCardModalV3 = () => {
const snapCheckCardModalV3 = useSnapshot(checkCardModalV3);
const isOpen = snapCheckCardModalV3.isOpen;
const min = snapCheckCardModalV3.selectMin || 0;
const max = snapCheckCardModalV3.selectMax || 0;
const mustSelectOptions = snapCheckCardModalV3.mustSelectList;
const selectAbleOptions = snapCheckCardModalV3.selectAbleList;
const overflow = snapCheckCardModalV3.overflow;
const LevelSum = snapCheckCardModalV3.allLevel;
const [selectedOptions, setSelectedOptions] = useState([]);
const Level1Sum = mustSelectOptions
.concat(selectedOptions)
.map((option) => option.level1)
.reduce((sum, current) => sum + current, 0);
const Level2Sum = mustSelectOptions
.concat(selectedOptions)
.map((option) => option.level2)
.reduce((sum, current) => sum + current, 0);
const hint = useSnapshot(matStore.hint);
const preHintMsg = hint?.esHint || "";
const selectHintMsg = hint?.esSelectHint || "请选择卡片";
const responseable =
(overflow
? Level1Sum >= LevelSum || Level2Sum >= LevelSum
: Level1Sum == LevelSum || Level2Sum == LevelSum) &&
selectedOptions.length <= max &&
selectedOptions.length >= min;
const onFinish = () => {
sendSelectCardResponse(
mustSelectOptions.concat(selectedOptions).map((option) => option.response)
);
checkCardModalV3.isOpen = false;
checkCardModalV3.responseable = false;
checkCardModalV3.overflow = false;
checkCardModalV3.allLevel = 0;
checkCardModalV3.mustSelectList = [];
checkCardModalV3.selectAbleList = [];
};
return (
<DragModal
title={`${preHintMsg} ${selectHintMsg} ${min}-${max}`}
open={isOpen}
closable={false}
footer={
<>
<Button disabled={!responseable} onClick={onFinish}>
finish
</Button>
</>
}
width={800}
>
<CheckCard.Group
bordered
size="small"
multiple={true}
onChange={(values: any) => {
console.log(values);
setSelectedOptions(values);
}}
>
<Row>
{selectAbleOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<CheckCard
title={option.meta.text.name}
description={option.meta.text.desc}
style={{ width: 120 }}
cover={
<img
alt={option.meta.id.toString()}
src={`${NeosConfig.cardImgUrl}/${option.meta.id}.jpg`}
style={{ width: 100 }}
/>
}
value={option}
/>
</Col>
);
})}
</Row>
</CheckCard.Group>
<p>必须选择的卡片</p>
<Row>
{mustSelectOptions.map((option, idx) => {
return (
<Col span={4} key={idx}>
<Card
hoverable
style={{ width: 120 }}
cover={
<img
alt={option.meta.id.toString()}
src={`${NeosConfig.cardImgUrl}/${option.meta.id}.jpg`}
/>
}
/>
</Col>
);
})}
</Row>
</DragModal>
);
};
...@@ -2,8 +2,6 @@ export * from "./Alert"; ...@@ -2,8 +2,6 @@ export * from "./Alert";
export * from "./CardListModal"; export * from "./CardListModal";
export * from "./CardModal"; export * from "./CardModal";
export * from "./CheckCardModal"; export * from "./CheckCardModal";
export * from "./CheckCardModalV2";
export * from "./CheckCardModalV3";
export * from "./CheckCounterModal"; export * from "./CheckCounterModal";
export * from "./DragModal"; export * from "./DragModal";
export * from "./HintNotification"; export * from "./HintNotification";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment