Commit 37fdc115 authored by timel's avatar timel

feat: complete select catds modal

parent 1ce37d9e
Pipeline #22383 failed with stages
in 15 minutes and 52 seconds
.checkcard-container {
position: relative;
// padding-left: 10px;
// &::after {
// position: absolute;
// width: 3px;
// height: 100%;
// content: "";
// z-index: 1;
// left: 0;
// top: 0;
// background-color: rgb(0, 54, 189);
// }
.btns {
width: 100%;
top: 50%;
display: flex;
justify-content: space-between;
padding: 0 10px;
box-sizing: border-box;
height: 0;
button {
transform: translateY(-50%);
}
}
.ant-pro-checkcard {
border-radius: 4px;
overflow: hidden;
}
// 多选卡片的样式
.ant-pro-checkcard-checked {
&::before {
position: absolute;
width: 100%;
height: 100%;
content: "";
z-index: 1;
background-color: #0023bf32;
box-shadow: 0 0 0 2px #0087e6 inset;
}
&::after {
display: none;
}
}
}
import "./index.scss";
import { CheckCard } from "@ant-design/pro-components";
import { Button, Segmented, Space, Tooltip } from "antd";
import { type FC, useEffect, useState } from "react";
import { proxy, useSnapshot } from "valtio";
import { type FC } from "react";
import { proxy, useSnapshot, INTERNAL_Snapshot as Snapshot } from "valtio";
import type { CardMeta, ygopro } from "@/api";
import {
fetchStrings,
sendSelectMultiResponse,
sendSelectSingleResponse,
} from "@/api";
import { useConfig } from "@/config";
import { matStore } from "@/stores";
import { YgoCard } from "@/ui/Shared";
import { sendSelectMultiResponse, sendSelectSingleResponse } from "@/api";
import { groupBy } from "../../utils";
import { showCardModal } from "../CardModal";
import { NeosModal } from "../NeosModal";
import { SelectCardsModal, type Option } from "../SelectCardsModal";
const CANCEL_RESPONSE = -1;
const FINISH_RESPONSE = -1;
......@@ -55,49 +43,8 @@ export const SelectActionsModal: FC = () => {
overflow,
} = useSnapshot(localStore);
const [response, setResponse] = useState<Option[]>([]);
const [submitable, setSubmitable] = useState(false);
const hint = useSnapshot(matStore.hint);
const preHintMsg = hint?.esHint || "";
const selectHintMsg = hint?.esSelectHint || "请选择卡片";
const minMaxText = min === max ? min : `${min}-${max}`;
// 判断是否可以提交
useEffect(() => {
const [sumLevel1, sumLevel2] = (["level1", "level2"] as const).map((key) =>
[...mustSelects, ...response]
.map((option) => option[key] || 0)
.reduce((sum, current) => sum + current, 0)
);
const levelMatched = overflow
? sumLevel1 >= totalLevels || sumLevel2 >= totalLevels
: sumLevel1 === totalLevels || sumLevel2 === totalLevels;
setSubmitable(
single
? response.length === 1
: response.length >= min && response.length <= max && levelMatched
);
}, [response.length]);
const grouped = groupBy(selectables, (option) => option.location?.zone!);
const zoneOptions = grouped.map((x) => ({
value: x[0],
label: fetchStrings("!system", x[0] + 1000),
}));
const [selectedZone, setSelectedZone] = useState(zoneOptions[0]?.value);
useEffect(() => {
setSelectedZone(zoneOptions[0]?.value);
}, [selectables]);
const onSubmit = () => {
const values = mustSelects
.concat(response)
.map((option) => option.response);
const onSubmit = (options: Snapshot<Option[]>) => {
const values = options.map((option) => option.response);
if (isChain) {
sendSelectSingleResponse(values[0]);
} else {
......@@ -116,142 +63,28 @@ export const SelectActionsModal: FC = () => {
rs();
};
const [submitText, finishText, cancelText] = [1211, 1296, 1295].map((n) =>
fetchStrings("!system", n)
);
return (
<NeosModal
title={
<>
<span>{preHintMsg}</span>
<span>{selectHintMsg}</span>
<span>(请选择 {single ? 1 : minMaxText} 张卡)</span>
</>
} // TODO: 这里可以再细化一些
width={600}
okButtonProps={{
disabled: !submitable,
<SelectCardsModal
{...{
isOpen,
isChain,
min,
max,
single,
selecteds,
selectables,
mustSelects,
cancelable,
finishable,
totalLevels,
overflow,
onSubmit,
onFinish,
onCancel,
}}
open={isOpen}
footer={
<>
<Button danger disabled={!cancelable} onClick={onCancel}>
{cancelText}
</Button>
<Button type="dashed" disabled={!finishable} onClick={onFinish}>
{finishText}
</Button>
<Button type="primary" disabled={!submitable} onClick={onSubmit}>
{submitText}
</Button>
</>
}
>
<div className="check-container">
<Space
direction="vertical"
style={{ width: "100%", overflow: "hidden" }}
>
<Selector
zoneOptions={zoneOptions}
selectedZone={selectedZone}
onChange={setSelectedZone as any}
/>
{grouped.map(
(options, i) =>
options[0] === selectedZone && (
<div className="checkcard-container" key={i}>
<CheckCard.Group
onChange={setResponse as any}
// TODO 考虑如何设置默认值,比如只有一个的,就直接选中
multiple
style={{
display: "grid",
gridTemplateColumns: "repeat(6, 1fr)",
gap: 10,
}}
>
{options[1].map((card, j) => (
<Tooltip
title={card.effectDesc}
placement="bottom"
key={j}
>
{/* 这儿必须有一个div,不然tooltip不生效 */}
<div>
<CheckCard
cover={
<YgoCard
code={card.meta.id}
style={{
width: "100%",
height: "100%",
position: "absolute",
left: 0,
top: 0,
}}
/>
}
style={{
width: 100,
aspectRatio: 5.9 / 8.6,
marginInlineEnd: 0,
marginBlockEnd: 0,
flexShrink: 0,
}}
value={card}
onClick={() => {
showCardModal(card);
}}
/>
</div>
</Tooltip>
))}
</CheckCard.Group>
</div>
)
)}
</Space>
</div>
</NeosModal>
);
};
/** 选择区域 */
const Selector: FC<{
zoneOptions: {
value: ygopro.CardZone;
label: string;
}[];
selectedZone: ygopro.CardZone;
onChange: (value: ygopro.CardZone) => void;
}> = ({ zoneOptions, selectedZone, onChange }) =>
zoneOptions.length > 1 ? (
<Segmented
block
options={zoneOptions}
style={{ margin: "10px 0" }}
value={selectedZone}
onChange={onChange as any}
/>
) : (
<></>
);
export interface Option {
// card id
meta: CardMeta;
location?: ygopro.CardLocation;
// 效果
effectDesc?: string;
// 作为素材的cost,比如同调召唤的星级
level1?: number;
level2?: number;
response: number;
}
const config = useConfig();
};
let rs: (v?: any) => void = () => {};
......
.checkcard-container {
position: relative;
// padding-left: 10px;
// &::after {
// position: absolute;
// width: 3px;
// height: 100%;
// content: "";
// z-index: 1;
// left: 0;
// top: 0;
// background-color: rgb(0, 54, 189);
// }
.btns {
width: 100%;
top: 50%;
display: flex;
justify-content: space-between;
padding: 0 10px;
box-sizing: border-box;
height: 0;
button {
transform: translateY(-50%);
}
}
.ant-pro-checkcard {
border-radius: 4px;
overflow: hidden;
}
// 多选卡片的样式
.ant-pro-checkcard-checked {
&::before {
position: absolute;
width: 100%;
height: 100%;
content: "";
z-index: 1;
background-color: #0023bf32;
box-shadow: 0 0 0 2px #0087e6 inset;
}
&::after {
display: none;
}
}
}
......@@ -3,7 +3,7 @@ import "./index.scss";
import { CheckCard } from "@ant-design/pro-components";
import { Button, Segmented, Space, Tooltip } from "antd";
import { type FC, useEffect, useState } from "react";
import { useSnapshot } from "valtio";
import { useSnapshot, INTERNAL_Snapshot as Snapshot } from "valtio";
import type { CardMeta, ygopro } from "@/api";
import { fetchStrings } from "@/api";
......@@ -14,20 +14,20 @@ import { groupBy } from "../../utils";
import { showCardModal } from "../CardModal";
import { NeosModal } from "../NeosModal";
export const SelectActionsModal: FC<{
isOpen: false;
isChain: false;
export const SelectCardsModal: FC<{
isOpen: boolean;
isChain: boolean;
min: number;
max: number;
single: true;
selecteds: Option[]; // 已经选择了的卡
selectables: Option[]; // 最多选择多少卡
mustSelects: Option[]; // 单选
cancelable: false; // 能否取消
finishable: false; // 选择足够了之后,能否确认
totalLevels: 0; // 需要的总等级数(用于同调/仪式/...)
overflow: false; // 选择等级时候,是否可以溢出
onSubmit: (options: Option[]) => void;
single: boolean;
selecteds: Snapshot<Option[]>; // 已经选择了的卡
selectables: Snapshot<Option[]>; // 最多选择多少卡
mustSelects: Snapshot<Option[]>; // 单选
cancelable: boolean; // 能否取消
finishable: boolean; // 选择足够了之后,能否确认
totalLevels: number; // 需要的总等级数(用于同调/仪式/...)
overflow: boolean; // 选择等级时候,是否可以溢出
onSubmit: (options: Snapshot<Option[]>) => void;
onCancel: () => void;
onFinish: () => void;
}> = ({
......
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