Commit c854a99e authored by Chunchi Che's avatar Chunchi Che

optimize checkCardModal store

parent 3803129a
import { ygopro } from "@/api";
import MsgSelectCard = ygopro.StocGameMessage.MsgSelectCard;
import { CardZoneToChinese, fetchCheckCardMeta, messageStore } from "@/stores";
import { fetchCheckCardMeta, messageStore } from "@/stores";
export default (selectCard: MsgSelectCard) => {
const _player = selectCard.player;
const _cancelable = selectCard.cancelable; // TODO: 处理可取消逻辑
const cancelable = selectCard.cancelable;
const min = selectCard.min;
const max = selectCard.max;
const cards = selectCard.cards;
// TODO: handle release_param
messageStore.checkCardModal.selectMin = min;
messageStore.checkCardModal.selectMax = max;
messageStore.checkCardModal.onSubmit = "sendSelectCardResponse";
messageStore.selectCardActions.min = min;
messageStore.selectCardActions.max = max;
messageStore.selectCardActions.cancelAble = cancelable;
for (const card of cards) {
const tagName = CardZoneToChinese(card.location.location);
fetchCheckCardMeta(card.location.location, {
fetchCheckCardMeta({
code: card.code,
location: card.location,
response: card.response,
});
}
messageStore.checkCardModal.isOpen = true;
messageStore.selectCardActions.isOpen = true;
};
......@@ -7,7 +7,6 @@ import {
type MsgSelectChain = ygopro.StocGameMessage.MsgSelectChain;
export default (selectChain: MsgSelectChain) => {
const player = selectChain.player;
const spCount = selectChain.special_count;
const forced = selectChain.forced;
const hint0 = selectChain.hint0;
......@@ -58,14 +57,12 @@ export default (selectChain: MsgSelectChain) => {
case 3: {
// 处理强制发动的卡
messageStore.checkCardModal.selectMin = 1;
messageStore.checkCardModal.selectMax = 1;
messageStore.checkCardModal.onSubmit = "sendSelectChainResponse";
messageStore.checkCardModal.cancelAble = !forced;
messageStore.checkCardModal.cancelResponse = -1;
messageStore.selectCardActions.min = 1;
messageStore.selectCardActions.max = 1;
messageStore.selectCardActions.cancelAble = !forced;
for (const chain of chains) {
fetchCheckCardMeta(chain.location.location, {
fetchCheckCardMeta({
code: chain.code,
location: chain.location,
response: chain.response,
......@@ -75,7 +72,7 @@ export default (selectChain: MsgSelectChain) => {
fetchSelectHintMeta({
selectHintData: 203,
});
messageStore.checkCardModal.isOpen = true;
messageStore.selectCardActions.isOpen = true;
break;
}
......
import { fetchStrings, ygopro } from "@/api";
import { CardMeta, fetchCard } from "@/api/cards";
import { CardZoneToChinese, messageStore } from "@/stores";
import { messageStore } from "@/stores";
type MsgSelectEffectYn = ygopro.StocGameMessage.MsgSelectEffectYn;
// 这里改成了 async 不知道有没有影响
export default async (selectEffectYn: MsgSelectEffectYn) => {
const player = selectEffectYn.player;
const code = selectEffectYn.code;
const location = selectEffectYn.location;
const effect_description = selectEffectYn.effect_description;
......@@ -20,7 +19,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => {
) => {
const desc1 = desc.replace(
`[%ls]`,
CardZoneToChinese(cardLocation.location)
fetchStrings("!system", cardLocation.location + 1000)
);
const desc2 = desc1.replace(`[%ls]`, cardMeta.text.name || "[?]");
return desc2;
......@@ -29,14 +28,7 @@ export default async (selectEffectYn: MsgSelectEffectYn) => {
const desc1 = desc.replace(`[%ls]`, cardMeta.text.name || "[?]");
return desc1;
};
// dispatch(
// fetchYesNoMeta({
// code,
// location,
// descCode: effect_description,
// textGenerator,
// })
// );
// TODO: 国际化文案
const desc = fetchStrings("!system", effect_description);
......
import { ygopro } from "@/api";
import { fetchCheckCardMetasV3, messageStore } from "@/stores";
import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum;
export default (selectSum: MsgSelectSum) => {
messageStore.checkCardModalV3.overflow = selectSum.overflow != 0;
messageStore.checkCardModalV3.allLevel = selectSum.level_sum;
messageStore.checkCardModalV3.selectMin = selectSum.min;
messageStore.checkCardModalV3.selectMax = selectSum.max;
messageStore.selectCardActions.overflow = selectSum.overflow != 0;
messageStore.selectCardActions.totalLevels = selectSum.level_sum;
messageStore.selectCardActions.min = selectSum.min;
messageStore.selectCardActions.max = selectSum.max;
fetchCheckCardMetasV3({
mustSelect: true,
options: selectSum.must_select_cards,
});
for (const option of selectSum.must_select_cards) {
fetchCheckCardMeta(option, false, true);
}
fetchCheckCardMetasV3({
mustSelect: false,
options: selectSum.selectable_cards,
});
for (const option of selectSum.selectable_cards) {
fetchCheckCardMeta(option);
}
messageStore.checkCardModalV3.isOpen = true;
messageStore.selectCardActions.isOpen = true;
};
import { ygopro } from "@/api";
import { fetchCheckCardMetasV3, messageStore } from "@/stores";
import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectTribute = ygopro.StocGameMessage.MsgSelectTribute;
export default (selectTribute: MsgSelectTribute) => {
// TODO: 当玩家选择卡数大于`max`时,是否也合法?
messageStore.checkCardModalV3.overflow = true;
messageStore.checkCardModalV3.allLevel = 0;
messageStore.checkCardModalV3.selectMin = selectTribute.min;
messageStore.checkCardModalV3.selectMax = selectTribute.max;
messageStore.selectCardActions.overflow = true;
messageStore.selectCardActions.totalLevels = 0;
messageStore.selectCardActions.min = selectTribute.min;
messageStore.selectCardActions.max = selectTribute.max;
fetchCheckCardMetasV3({
mustSelect: false,
options: selectTribute.selectable_cards.map((card) => {
return {
code: card.code,
location: card.location,
level1: card.level,
level2: card.level,
response: card.response,
};
}),
});
for (const option of selectTribute.selectable_cards) {
fetchCheckCardMeta(option);
}
messageStore.checkCardModalV3.isOpen = true;
messageStore.selectCardActions.isOpen = true;
};
import { ygopro } from "@/api";
import { fetchCheckCardMetasV2, messageStore } from "@/stores";
import { fetchCheckCardMeta, messageStore } from "@/stores";
type MsgSelectUnselectCard = ygopro.StocGameMessage.MsgSelectUnselectCard;
......@@ -11,33 +11,17 @@ export default ({
selectable_cards: selectableCards,
selected_cards: selectedCards,
}: MsgSelectUnselectCard) => {
messageStore.checkCardModalV2.isOpen = true;
messageStore.checkCardModalV2.finishAble = finishable;
messageStore.checkCardModalV2.cancelAble = cancelable;
messageStore.checkCardModalV2.selectMin = min;
messageStore.checkCardModalV2.selectMax = max;
messageStore.selectCardActions.isOpen = true;
messageStore.selectCardActions.finishAble = finishable;
messageStore.selectCardActions.cancelAble = cancelable;
messageStore.selectCardActions.min = min;
messageStore.selectCardActions.max = max;
fetchCheckCardMetasV2({
selected: false,
options: selectableCards.map((card) => {
return {
code: card.code,
location: card.location,
response: card.response,
};
}),
});
for (const option of selectableCards) {
fetchCheckCardMeta(option);
}
fetchCheckCardMetasV2({
selected: true,
options: selectedCards.map((card) => {
return {
code: card.code,
location: card.location,
response: card.response,
};
}),
});
messageStore.checkCardModalV2.responseable = true;
for (const option of selectedCards) {
fetchCheckCardMeta(option, 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";
import { fetchCard, getCardStr } from "@/api/cards";
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 (
zone: ygopro.CardZone,
{
code,
location,
level1,
level2,
response,
effectDescCode,
}: {
code: number;
location: ygopro.CardLocation;
level1?: number;
level2?: number;
response: number;
effectDescCode?: number;
}
},
selected?: boolean,
mustSelect?: boolean
) => {
const tagName = CardZoneToChinese(zone);
const meta = await fetchCard(code);
const controller = location.controler;
const combinedTagName = matStore.isMe(controller)
? `我方的${tagName}`
: `对方的${tagName}`;
const newID =
code != 0
? code
: matStore.in(location.location).of(controller)[location.sequence]
?.occupant?.id || 0;
const meta = await fetchCard(code);
const effectDesc = effectDescCode
? getCardStr(meta, effectDescCode & 0xf)
: undefined;
const newOption = {
meta: { id: newID, data: {}, text: {} },
code: newID,
location: location.toObject(),
effectDescCode,
level1,
level2,
effectDesc,
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 (tag.tagName === combinedTagName) {
for (const old of tag.options) {
if (meta.id == old.meta.id && cmpCardLocation(location, old.location)) {
const cardID = old.meta.id;
old.meta = meta;
old.meta.id = cardID;
const effectDescCode = old.effectDescCode;
const effectDesc = effectDescCode
? getCardStr(old.meta, effectDescCode & 0xf)
: undefined;
old.effectDesc = effectDesc;
}
}
}
if (selected) {
messageStore.selectCardActions.selecteds.push(newOption);
} else if (mustSelect) {
messageStore.selectCardActions.mustSelects.push(newOption);
} else {
messageStore.selectCardActions.selectables.push(newOption);
}
};
export * from "./cardZoneToChinese";
export * from "./fetchCheckCardMeta";
export * from "./fetchHint";
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 "./clearAllPlaceInteradtivities";
export * from "./fetchCheckCardMetasV2";
export * from "./fetchCheckCardMetasV3";
......@@ -5,25 +5,17 @@ import type { ModalState } from "./types";
export const messageStore = proxy<ModalState>({
cardModal: { isOpen: false, interactivies: [], counters: {} },
cardListModal: { isOpen: false, list: [] },
checkCardModal: { isOpen: false, cancelAble: false, tags: [] },
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCardModalV2: {
selectCardActions: {
isOpen: false,
cancelAble: false,
finishAble: false,
responseable: false,
selectableOptions: [],
selectedOptions: [],
},
checkCardModalV3: {
isOpen: false,
overflow: false,
allLevel: 0,
mustSelectList: [],
selectAbleList: [],
selecteds: [],
selectables: [],
mustSelects: [],
},
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCounterModal: {
isOpen: false,
options: [],
......
import type { CardMeta, ygopro } from "@/api";
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 {
// 卡牌弹窗
cardModal: {
......@@ -17,24 +29,23 @@ export interface ModalState {
interactivies: { desc: string; response: number }[];
}[];
};
// 卡牌选择弹窗
checkCardModal: {
// 卡牌选择状态
selectCardActions: {
isOpen: boolean;
onSubmit?: string;
selectMin?: number;
selectMax?: number;
min?: number;
max?: number;
cancelAble: boolean;
cancelResponse?: number;
tags: {
tagName: string;
options: {
meta: CardMeta;
location?: CardLocation;
effectDescCode?: number;
effectDesc?: string;
response: number;
}[];
}[];
finishAble: boolean;
// 上级/同调/超量/链接召唤的总cost
totalLevels?: number;
// cost是否可以溢出,比如同调召唤是false,某些链接召唤是true
overflow?: boolean;
// 已经选择的列表
selecteds: Option[];
// 可以选择的列表
selectables: Option[];
// 必须选择的列表
mustSelects: Option[];
};
// Yes or No弹窗
yesNoModal: {
......@@ -51,48 +62,6 @@ export interface ModalState {
isOpen: boolean;
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: {
isOpen: boolean;
......
......@@ -5,8 +5,6 @@ import {
CardListModal,
CardModal,
CheckCardModal,
CheckCardModalV2,
CheckCardModalV3,
CheckCounterModal,
HintNotification,
OptionModal,
......@@ -28,8 +26,6 @@ const NeosDuel = () => {
<YesNoModal />
<PositionModal />
<OptionModal />
<CheckCardModalV2 />
<CheckCardModalV3 />
<CheckCounterModal />
<SortCardModal />
</>
......
......@@ -4,58 +4,60 @@ import { Button, Col, Popover, Row } from "antd";
import React, { useState } from "react";
import { useSnapshot } from "valtio";
import { sendSelectCardResponse, sendSelectChainResponse } from "@/api";
import { fetchStrings, sendSelectCardResponse } from "@/api";
import { useConfig } from "@/config";
import { matStore, messageStore } from "@/stores";
import { DragModal } from "./DragModal";
const NeosConfig = useConfig();
const CANCEL_RESPONSE = -1;
const FINISH_RESPONSE = -1;
const { checkCardModal } = messageStore;
const { selectCardActions } = messageStore;
export const CheckCardModal = () => {
const snapCheckCardModal = useSnapshot(checkCardModal);
const isOpen = snapCheckCardModal.isOpen;
const min = snapCheckCardModal.selectMin ?? 0;
const max = snapCheckCardModal.selectMax ?? 10;
const tabs = snapCheckCardModal.tags;
const onSubmit = snapCheckCardModal.onSubmit;
const cancelAble = snapCheckCardModal.cancelAble;
const cancelResponse = snapCheckCardModal.cancelResponse;
const snap = useSnapshot(selectCardActions);
const isOpen = snap.isOpen;
const min = snap.min ?? 0;
const max = snap.max ?? 10;
const selecteds = snap.selecteds;
const selectables = snap.selectables;
const mustSelects = snap.mustSelects;
const [response, setResponse] = useState<number[]>([]);
const defaultValue: number[] = [];
const [response, setResponse] = useState([]);
const hint = useSnapshot(matStore.hint);
const preHintMsg = hint?.esHint || "";
const selectHintMsg = hint?.esSelectHint || "请选择卡片";
// TODO: 这里可以考虑更好地封装
const sendResponseHandler = (
handlerName: string | undefined,
response: number[]
) => {
switch (handlerName) {
case "sendSelectChainResponse": {
sendSelectChainResponse(response[0]);
break;
}
case "sendSelectCardResponse": {
sendSelectCardResponse(response);
break;
}
default: {
}
}
};
const cancelable = snap.cancelAble;
const finishable = snap.finishAble;
const totalLevels = snap.totalLevels || 0;
const overflow = snap.overflow || false;
const LevelSum1 = mustSelects
.concat(response)
.map((option) => option.level1 || 0)
.reduce((sum, current) => sum + current, 0);
const LevelSum2 = mustSelects
.concat(response)
.map((option) => option.level2 || 0)
.reduce((sum, current) => sum + current, 0);
const levelMatched = overflow
? LevelSum1 >= totalLevels || LevelSum2 >= totalLevels
: LevelSum1 == totalLevels || LevelSum2 == totalLevels;
const submitable =
response.length >= min && response.length <= max && levelMatched;
const resetCheckCardModal = () => {
checkCardModal.isOpen = false;
checkCardModal.selectMin = undefined;
checkCardModal.selectMax = undefined;
checkCardModal.cancelAble = false;
checkCardModal.cancelResponse = undefined;
checkCardModal.tags = [];
selectCardActions.isOpen = false;
selectCardActions.min = undefined;
selectCardActions.max = undefined;
selectCardActions.cancelAble = false;
selectCardActions.totalLevels = undefined;
selectCardActions.selecteds = [];
selectCardActions.selectables = [];
selectCardActions.finishAble = false;
selectCardActions.overflow = false;
};
return (
......@@ -66,34 +68,42 @@ export const CheckCardModal = () => {
footer={
<>
<Button
disabled={response.length < min || response.length > max}
disabled={!submitable}
onClick={() => {
sendResponseHandler(onSubmit, response);
checkCardModal.isOpen = false;
const values = mustSelects
.concat(response)
.map((option) => option.response);
sendSelectCardResponse(values);
resetCheckCardModal();
}}
onFocus={() => {}}
onBlur={() => {}}
>
submit
{fetchStrings("!system", 1211)}
</Button>
{cancelAble ? (
<Button
disabled={!finishable}
onClick={() => {
if (cancelResponse) {
sendResponseHandler(onSubmit, [cancelResponse]);
}
checkCardModal.isOpen = false;
sendSelectCardResponse([FINISH_RESPONSE]);
resetCheckCardModal();
}}
onFocus={() => {}}
onBlur={() => {}}
>
cancel
{fetchStrings("!system", 1296)}
</Button>
<Button
disabled={!cancelable}
onClick={() => {
sendSelectCardResponse([CANCEL_RESPONSE]);
resetCheckCardModal();
}}
onFocus={() => {}}
onBlur={() => {}}
>
{fetchStrings("!system", 1295)}
</Button>
) : (
<></>
)}
</>
}
width={800}
......@@ -102,42 +112,57 @@ export const CheckCardModal = () => {
multiple
bordered
size="small"
defaultValue={defaultValue}
onChange={(value) => {
// @ts-ignore
setResponse(value);
}}
>
{tabs.map((tab, idx) => {
return (
<Row key={idx}>
{tab.options.map((option, idx) => {
<Row>
{selectables.map((option, idx) => {
return (
<Col span={4} key={idx}>
<HoverCheckCard
hoverContent={option.effectDesc}
title={option.meta.text.name}
description={option.meta.text.desc}
style={{ width: 120 }}
cover={
<img
alt={option.meta.id.toString()}
alt={option.code.toString()}
src={
option.meta.id
? `${NeosConfig.cardImgUrl}/${option.meta.id}.jpg`
option.code
? `${NeosConfig.cardImgUrl}/${option.code}.jpg`
: `${NeosConfig.assetsPath}/card_back.jpg`
}
style={{ width: 100 }}
/>
}
value={option.response}
value={option}
/>
</Col>
);
})}
</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>
</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";
export * from "./CardListModal";
export * from "./CardModal";
export * from "./CheckCardModal";
export * from "./CheckCardModalV2";
export * from "./CheckCardModalV3";
export * from "./CheckCounterModal";
export * from "./DragModal";
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