优化表单
This commit is contained in:
parent
57231bc95a
commit
8c23d7e6a7
@ -118,6 +118,8 @@ test("renders cp config route with an authenticated session", async () => {
|
|||||||
renderWithRoute("/activities/cp-config");
|
renderWithRoute("/activities/cp-config");
|
||||||
|
|
||||||
expect((await screen.findAllByText("CP配置")).length).toBeGreaterThan(0);
|
expect((await screen.findAllByText("CP配置")).length).toBeGreaterThan(0);
|
||||||
|
expect(await screen.findByText("已加载 1 条 · 共 1 条")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("共 1 条")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("admin routes declare menu code and permission", () => {
|
test("admin routes declare menu code and permission", () => {
|
||||||
|
|||||||
@ -93,7 +93,6 @@ export function CPConfigPage() {
|
|||||||
rowKey={(item) =>
|
rowKey={(item) =>
|
||||||
isApplicationsTab ? item.applicationId : item.relationshipId || `${item.userA?.userId}-${item.userB?.userId}`
|
isApplicationsTab ? item.applicationId : item.relationshipId || `${item.userA?.userId}-${item.userB?.userId}`
|
||||||
}
|
}
|
||||||
total={activePage.total}
|
|
||||||
/>
|
/>
|
||||||
</AdminListBody>
|
</AdminListBody>
|
||||||
</DataState>
|
</DataState>
|
||||||
|
|||||||
@ -82,7 +82,6 @@ export function useRobotRoomsPage() {
|
|||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const [activeAction, setActiveAction] = useState("");
|
const [activeAction, setActiveAction] = useState("");
|
||||||
const [availableRobotsState, setAvailableRobotsState] = useState({ error: "", loading: false, options: [] });
|
const [availableRobotsState, setAvailableRobotsState] = useState({ error: "", loading: false, options: [] });
|
||||||
const [candidatesTouched, setCandidatesTouched] = useState(false);
|
|
||||||
const [form, setForm] = useState(emptyForm);
|
const [form, setForm] = useState(emptyForm);
|
||||||
const [giftOptionsState, setGiftOptionsState] = useState({ error: "", loading: false, options: [] });
|
const [giftOptionsState, setGiftOptionsState] = useState({ error: "", loading: false, options: [] });
|
||||||
const [humanConfigState, setHumanConfigState] = useState({ config: null, error: "", loading: false });
|
const [humanConfigState, setHumanConfigState] = useState({ config: null, error: "", loading: false });
|
||||||
@ -151,14 +150,21 @@ export function useRobotRoomsPage() {
|
|||||||
}, [activeAction]);
|
}, [activeAction]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeAction !== "create" || candidatesTouched) {
|
if (activeAction !== "create") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ids = availableRobotsState.options.map((item) => item.userId).filter(Boolean);
|
const ownerRobotUserId = String(form.ownerRobotUserId || "");
|
||||||
if (ids.length > 0) {
|
const ids = availableRobotsState.options
|
||||||
setForm((current) => ({ ...current, candidateRobotUserIds: ids }));
|
.map((item) => item.userId)
|
||||||
}
|
.filter((userId) => userId && String(userId) !== ownerRobotUserId);
|
||||||
}, [activeAction, availableRobotsState.options, candidatesTouched]);
|
setForm((current) => {
|
||||||
|
const currentIds = (current.candidateRobotUserIds || []).map(String);
|
||||||
|
if (currentIds.join(",") === ids.map(String).join(",")) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return { ...current, candidateRobotUserIds: ids };
|
||||||
|
});
|
||||||
|
}, [activeAction, availableRobotsState.options, form.ownerRobotUserId]);
|
||||||
|
|
||||||
const changeStatus = (value) => {
|
const changeStatus = (value) => {
|
||||||
setStatus(value || "active");
|
setStatus(value || "active");
|
||||||
@ -172,7 +178,6 @@ export function useRobotRoomsPage() {
|
|||||||
|
|
||||||
const openCreate = () => {
|
const openCreate = () => {
|
||||||
setActiveAction("create");
|
setActiveAction("create");
|
||||||
setCandidatesTouched(false);
|
|
||||||
setForm(emptyForm());
|
setForm(emptyForm());
|
||||||
setAvailableRobotsState({ error: "", loading: false, options: [] });
|
setAvailableRobotsState({ error: "", loading: false, options: [] });
|
||||||
setGiftOptionsState({ error: "", loading: false, options: [] });
|
setGiftOptionsState({ error: "", loading: false, options: [] });
|
||||||
@ -233,16 +238,6 @@ export function useRobotRoomsPage() {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectCandidateRobots = (robots) => {
|
|
||||||
setCandidatesTouched(true);
|
|
||||||
setForm((current) => ({
|
|
||||||
...current,
|
|
||||||
candidateRobotUserIds: robots
|
|
||||||
.map((robot) => robot.userId)
|
|
||||||
.filter((userId) => userId && String(userId) !== String(current.ownerRobotUserId)),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectGiftIds = (key, gifts) => {
|
const selectGiftIds = (key, gifts) => {
|
||||||
setForm((current) => ({ ...current, [key]: gifts.map(giftId).filter(Boolean) }));
|
setForm((current) => ({ ...current, [key]: gifts.map(giftId).filter(Boolean) }));
|
||||||
};
|
};
|
||||||
@ -313,14 +308,6 @@ export function useRobotRoomsPage() {
|
|||||||
() => availableRobotsState.options.find((item) => item.userId === String(form.ownerRobotUserId)) || null,
|
() => availableRobotsState.options.find((item) => item.userId === String(form.ownerRobotUserId)) || null,
|
||||||
[availableRobotsState.options, form.ownerRobotUserId],
|
[availableRobotsState.options, form.ownerRobotUserId],
|
||||||
);
|
);
|
||||||
const selectedCandidateRobots = useMemo(() => {
|
|
||||||
const selected = new Set((form.candidateRobotUserIds || []).map(String));
|
|
||||||
return availableRobotsState.options.filter((item) => selected.has(String(item.userId)));
|
|
||||||
}, [availableRobotsState.options, form.candidateRobotUserIds]);
|
|
||||||
const candidateRobotOptions = useMemo(
|
|
||||||
() => availableRobotsState.options.filter((item) => String(item.userId) !== String(form.ownerRobotUserId)),
|
|
||||||
[availableRobotsState.options, form.ownerRobotUserId],
|
|
||||||
);
|
|
||||||
const countryLabels = useMemo(
|
const countryLabels = useMemo(
|
||||||
() => Object.fromEntries(countryOptions.map((option) => [option.value, option.label])),
|
() => Object.fromEntries(countryOptions.map((option) => [option.value, option.label])),
|
||||||
[countryOptions],
|
[countryOptions],
|
||||||
@ -365,7 +352,6 @@ export function useRobotRoomsPage() {
|
|||||||
availableRobots: availableRobotsState.options,
|
availableRobots: availableRobotsState.options,
|
||||||
changeStatus,
|
changeStatus,
|
||||||
closeAction,
|
closeAction,
|
||||||
candidateRobotOptions,
|
|
||||||
countryOptions,
|
countryOptions,
|
||||||
data,
|
data,
|
||||||
error,
|
error,
|
||||||
@ -387,11 +373,9 @@ export function useRobotRoomsPage() {
|
|||||||
page,
|
page,
|
||||||
reload,
|
reload,
|
||||||
resetFilters,
|
resetFilters,
|
||||||
selectCandidateRobots,
|
|
||||||
selectGiftIds,
|
selectGiftIds,
|
||||||
selectHumanGiftIds,
|
selectHumanGiftIds,
|
||||||
selectOwnerRobot,
|
selectOwnerRobot,
|
||||||
selectedCandidateRobots,
|
|
||||||
selectedGiftOptions,
|
selectedGiftOptions,
|
||||||
selectedLuckyGiftOptions,
|
selectedLuckyGiftOptions,
|
||||||
selectedHumanGiftOptions,
|
selectedHumanGiftOptions,
|
||||||
|
|||||||
@ -7,7 +7,12 @@ import MenuItem from "@mui/material/MenuItem";
|
|||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Tooltip from "@mui/material/Tooltip";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
import { Button } from "@/shared/ui/Button.jsx";
|
import { Button } from "@/shared/ui/Button.jsx";
|
||||||
import { AdminFormDialog } from "@/shared/ui/AdminFormDialog.jsx";
|
import {
|
||||||
|
AdminFormAmountField,
|
||||||
|
AdminFormDialog,
|
||||||
|
AdminFormFieldGrid,
|
||||||
|
AdminFormSection,
|
||||||
|
} from "@/shared/ui/AdminFormDialog.jsx";
|
||||||
import { AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx";
|
import { AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx";
|
||||||
import { DataState } from "@/shared/ui/DataState.jsx";
|
import { DataState } from "@/shared/ui/DataState.jsx";
|
||||||
import { DataTable } from "@/shared/ui/DataTable.jsx";
|
import { DataTable } from "@/shared/ui/DataTable.jsx";
|
||||||
@ -190,190 +195,138 @@ export function RoomRobotPage() {
|
|||||||
onClose={page.closeAction}
|
onClose={page.closeAction}
|
||||||
onSubmit={page.submitCreate}
|
onSubmit={page.submitCreate}
|
||||||
>
|
>
|
||||||
<Autocomplete
|
<AdminFormSection title="房主设置">
|
||||||
getOptionLabel={robotOptionLabel}
|
<Autocomplete
|
||||||
isOptionEqualToValue={(option, value) => option.userId === value.userId}
|
getOptionLabel={robotOptionLabel}
|
||||||
loading={page.availableRobotsLoading}
|
isOptionEqualToValue={(option, value) => option.userId === value.userId}
|
||||||
noOptionsText="当前无数据"
|
loading={page.availableRobotsLoading}
|
||||||
options={page.availableRobots}
|
noOptionsText="当前无数据"
|
||||||
renderInput={(params) => (
|
options={page.availableRobots}
|
||||||
<TextField
|
renderInput={(params) => (
|
||||||
{...params}
|
<TextField
|
||||||
error={Boolean(page.availableRobotsError)}
|
{...params}
|
||||||
helperText={page.availableRobotsError}
|
error={Boolean(page.availableRobotsError)}
|
||||||
label="房主机器人"
|
helperText={page.availableRobotsError}
|
||||||
required
|
label="房主机器人"
|
||||||
/>
|
required
|
||||||
)}
|
|
||||||
renderOption={(props, option) => (
|
|
||||||
<li {...props} key={option.userId}>
|
|
||||||
<OwnerRobotOption
|
|
||||||
countryLabels={page.robotCountryLabels}
|
|
||||||
loadingLocation={page.loadingRobotLocationOptions}
|
|
||||||
option={option}
|
|
||||||
regionLabels={page.robotRegionLabels}
|
|
||||||
/>
|
/>
|
||||||
</li>
|
)}
|
||||||
)}
|
renderOption={(props, option) => (
|
||||||
size="small"
|
<li {...props} key={option.userId}>
|
||||||
value={page.selectedOwnerRobot}
|
<OwnerRobotOption
|
||||||
onChange={(_, option) => page.selectOwnerRobot(option)}
|
countryLabels={page.robotCountryLabels}
|
||||||
/>
|
loadingLocation={page.loadingRobotLocationOptions}
|
||||||
<Autocomplete
|
option={option}
|
||||||
multiple
|
regionLabels={page.robotRegionLabels}
|
||||||
disableCloseOnSelect
|
/>
|
||||||
getOptionLabel={robotOptionLabel}
|
</li>
|
||||||
isOptionEqualToValue={(option, value) => option.userId === value.userId}
|
)}
|
||||||
loading={page.availableRobotsLoading}
|
size="small"
|
||||||
noOptionsText="当前无数据"
|
value={page.selectedOwnerRobot}
|
||||||
options={page.candidateRobotOptions}
|
onChange={(_, option) => page.selectOwnerRobot(option)}
|
||||||
renderInput={(params) => (
|
/>
|
||||||
<TextField
|
</AdminFormSection>
|
||||||
{...params}
|
<AdminFormSection title="进房规则">
|
||||||
error={Boolean(page.availableRobotsError)}
|
<AdminFormFieldGrid>
|
||||||
helperText={page.availableRobotsError}
|
<ConfigNumberField
|
||||||
label={<RequiredLabel>候选机器人</RequiredLabel>}
|
label="最少进房人数"
|
||||||
|
value={page.form.minRobotCount}
|
||||||
|
onChange={(value) => page.setForm({ ...page.form, minRobotCount: value })}
|
||||||
/>
|
/>
|
||||||
)}
|
<ConfigNumberField
|
||||||
renderOption={(props, option) => (
|
label="最多进房人数"
|
||||||
<li {...props} key={option.userId}>
|
value={page.form.maxRobotCount}
|
||||||
<RobotIdentity openInAppUserDetail={false} user={option.user} fallbackId={option.userId} />
|
onChange={(value) => page.setForm({ ...page.form, maxRobotCount: value })}
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
size="small"
|
|
||||||
value={page.selectedCandidateRobots}
|
|
||||||
onChange={(_, options) => page.selectCandidateRobots(options)}
|
|
||||||
/>
|
|
||||||
<div className={styles.formGrid}>
|
|
||||||
<TextField
|
|
||||||
label="最少进房人数"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.form.minRobotCount}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, minRobotCount: event.target.value })}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最多进房人数"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.form.maxRobotCount}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, maxRobotCount: event.target.value })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Autocomplete
|
|
||||||
multiple
|
|
||||||
disableCloseOnSelect
|
|
||||||
getOptionLabel={giftOptionLabel}
|
|
||||||
isOptionEqualToValue={(option, value) => giftId(option) === giftId(value)}
|
|
||||||
loading={page.giftOptionsLoading}
|
|
||||||
noOptionsText="当前无数据"
|
|
||||||
options={page.giftOptions}
|
|
||||||
renderInput={(params) => (
|
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
error={Boolean(page.giftOptionsError)}
|
|
||||||
helperText={page.giftOptionsError}
|
|
||||||
label={<RequiredLabel>礼物合集</RequiredLabel>}
|
|
||||||
/>
|
/>
|
||||||
)}
|
</AdminFormFieldGrid>
|
||||||
size="small"
|
</AdminFormSection>
|
||||||
value={page.selectedGiftOptions}
|
<AdminFormSection title="普通礼物规则">
|
||||||
onChange={(_, options) => page.selectGiftIds("giftIds", options)}
|
<GiftAutocomplete
|
||||||
/>
|
error={Boolean(page.giftOptionsError)}
|
||||||
<TextField
|
helperText={page.giftOptionsError}
|
||||||
label="普通礼物频次(毫秒)"
|
label="礼物合集"
|
||||||
required
|
loading={page.giftOptionsLoading}
|
||||||
type="number"
|
options={page.giftOptions}
|
||||||
value={page.form.normalGiftIntervalMs}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, normalGiftIntervalMs: event.target.value })}
|
|
||||||
/>
|
|
||||||
<div className={styles.formGrid}>
|
|
||||||
<TextField
|
|
||||||
label="最短停留(毫秒)"
|
|
||||||
required
|
required
|
||||||
type="number"
|
value={page.selectedGiftOptions}
|
||||||
value={page.form.robotStayMinMs}
|
onChange={(options) => page.selectGiftIds("giftIds", options)}
|
||||||
onChange={(event) => page.setForm({ ...page.form, robotStayMinMs: event.target.value })}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<AdminFormFieldGrid>
|
||||||
label="最长停留(毫秒)"
|
<ConfigNumberField
|
||||||
required
|
label="普通礼物频次"
|
||||||
type="number"
|
unit="毫秒"
|
||||||
value={page.form.robotStayMaxMs}
|
value={page.form.normalGiftIntervalMs}
|
||||||
onChange={(event) => page.setForm({ ...page.form, robotStayMaxMs: event.target.value })}
|
onChange={(value) => page.setForm({ ...page.form, normalGiftIntervalMs: value })}
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最短补位(毫秒)"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.form.robotReplaceMinMs}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, robotReplaceMinMs: event.target.value })}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最长补位(毫秒)"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.form.robotReplaceMaxMs}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, robotReplaceMaxMs: event.target.value })}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="同时送礼上限"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.form.maxGiftSenders}
|
|
||||||
onChange={(event) => page.setForm({ ...page.form, maxGiftSenders: event.target.value })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Autocomplete
|
|
||||||
multiple
|
|
||||||
disableCloseOnSelect
|
|
||||||
getOptionLabel={giftOptionLabel}
|
|
||||||
isOptionEqualToValue={(option, value) => giftId(option) === giftId(value)}
|
|
||||||
loading={page.giftOptionsLoading}
|
|
||||||
noOptionsText="当前无数据"
|
|
||||||
options={page.giftOptions}
|
|
||||||
renderInput={(params) => (
|
|
||||||
<TextField
|
|
||||||
{...params}
|
|
||||||
error={Boolean(page.giftOptionsError)}
|
|
||||||
helperText={page.giftOptionsError}
|
|
||||||
label={<RequiredLabel>幸运礼物合集</RequiredLabel>}
|
|
||||||
/>
|
/>
|
||||||
)}
|
<ConfigNumberField
|
||||||
size="small"
|
label="最短停留"
|
||||||
value={page.selectedLuckyGiftOptions}
|
unit="毫秒"
|
||||||
onChange={(_, options) => page.selectGiftIds("luckyGiftIds", options)}
|
value={page.form.robotStayMinMs}
|
||||||
/>
|
onChange={(value) => page.setForm({ ...page.form, robotStayMinMs: value })}
|
||||||
<div className={styles.formGrid}>
|
/>
|
||||||
<TextField
|
<ConfigNumberField
|
||||||
label="最少幸运连击"
|
label="最长停留"
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.form.robotStayMaxMs}
|
||||||
|
onChange={(value) => page.setForm({ ...page.form, robotStayMaxMs: value })}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最短补位"
|
||||||
|
min={0}
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.form.robotReplaceMinMs}
|
||||||
|
onChange={(value) => page.setForm({ ...page.form, robotReplaceMinMs: value })}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最长补位"
|
||||||
|
min={0}
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.form.robotReplaceMaxMs}
|
||||||
|
onChange={(value) => page.setForm({ ...page.form, robotReplaceMaxMs: value })}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="同时送礼上限"
|
||||||
|
value={page.form.maxGiftSenders}
|
||||||
|
onChange={(value) => page.setForm({ ...page.form, maxGiftSenders: value })}
|
||||||
|
/>
|
||||||
|
</AdminFormFieldGrid>
|
||||||
|
</AdminFormSection>
|
||||||
|
<AdminFormSection title="幸运礼物规则">
|
||||||
|
<GiftAutocomplete
|
||||||
|
error={Boolean(page.giftOptionsError)}
|
||||||
|
helperText={page.giftOptionsError}
|
||||||
|
label="幸运礼物合集"
|
||||||
|
loading={page.giftOptionsLoading}
|
||||||
|
options={page.giftOptions}
|
||||||
required
|
required
|
||||||
type="number"
|
value={page.selectedLuckyGiftOptions}
|
||||||
value={page.form.luckyComboMin}
|
onChange={(options) => page.selectGiftIds("luckyGiftIds", options)}
|
||||||
onChange={(event) => page.setForm({ ...page.form, luckyComboMin: event.target.value })}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<AdminFormFieldGrid>
|
||||||
label="最多幸运连击"
|
<ConfigNumberField
|
||||||
required
|
label="最少幸运连击"
|
||||||
type="number"
|
value={page.form.luckyComboMin}
|
||||||
value={page.form.luckyComboMax}
|
onChange={(value) => page.setForm({ ...page.form, luckyComboMin: value })}
|
||||||
onChange={(event) => page.setForm({ ...page.form, luckyComboMax: event.target.value })}
|
/>
|
||||||
/>
|
<ConfigNumberField
|
||||||
<TextField
|
label="最多幸运连击"
|
||||||
label="最短幸运间隔(毫秒)"
|
value={page.form.luckyComboMax}
|
||||||
required
|
onChange={(value) => page.setForm({ ...page.form, luckyComboMax: value })}
|
||||||
type="number"
|
/>
|
||||||
value={page.form.luckyPauseMinMs}
|
<ConfigNumberField
|
||||||
onChange={(event) => page.setForm({ ...page.form, luckyPauseMinMs: event.target.value })}
|
label="最短幸运间隔"
|
||||||
/>
|
unit="毫秒"
|
||||||
<TextField
|
value={page.form.luckyPauseMinMs}
|
||||||
label="最长幸运间隔(毫秒)"
|
onChange={(value) => page.setForm({ ...page.form, luckyPauseMinMs: value })}
|
||||||
required
|
/>
|
||||||
type="number"
|
<ConfigNumberField
|
||||||
value={page.form.luckyPauseMaxMs}
|
label="最长幸运间隔"
|
||||||
onChange={(event) => page.setForm({ ...page.form, luckyPauseMaxMs: event.target.value })}
|
unit="毫秒"
|
||||||
/>
|
value={page.form.luckyPauseMaxMs}
|
||||||
</div>
|
onChange={(value) => page.setForm({ ...page.form, luckyPauseMaxMs: value })}
|
||||||
|
/>
|
||||||
|
</AdminFormFieldGrid>
|
||||||
|
</AdminFormSection>
|
||||||
</AdminFormDialog>
|
</AdminFormDialog>
|
||||||
<HumanConfigDialog page={page} />
|
<HumanConfigDialog page={page} />
|
||||||
</section>
|
</section>
|
||||||
@ -446,190 +399,199 @@ function HumanConfigDialog({ page }) {
|
|||||||
onClose={page.closeAction}
|
onClose={page.closeAction}
|
||||||
onSubmit={page.submitHumanConfig}
|
onSubmit={page.submitHumanConfig}
|
||||||
>
|
>
|
||||||
<div className={styles.formGrid}>
|
<AdminFormSection
|
||||||
<label className={styles.switchField}>
|
actions={
|
||||||
<AdminSwitch
|
<div className={styles.configSwitchActions}>
|
||||||
checked={Boolean(page.humanConfigForm.enabled)}
|
<span className={styles.switchField}>
|
||||||
checkedLabel="启用"
|
<AdminSwitch
|
||||||
label="启用真人房间机器人"
|
checked={Boolean(page.humanConfigForm.enabled)}
|
||||||
uncheckedLabel="关闭"
|
checkedLabel="启用"
|
||||||
onChange={(_, checked) =>
|
label="启用真人房间机器人"
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, enabled: checked })
|
uncheckedLabel="关闭"
|
||||||
|
onChange={(_, checked) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, enabled: checked })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
title="基础规则"
|
||||||
|
>
|
||||||
|
<AdminFormFieldGrid>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="真人房间低于人数"
|
||||||
|
value={page.humanConfigForm.candidateRoomMaxOnline}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({
|
||||||
|
...page.humanConfigForm,
|
||||||
|
candidateRoomMaxOnline: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</label>
|
<ConfigNumberField
|
||||||
<label className={styles.switchField}>
|
label="目标人数下限"
|
||||||
<AdminSwitch
|
value={page.humanConfigForm.roomTargetMinOnline}
|
||||||
checked={Boolean(page.humanConfigForm.countryLimitEnabled)}
|
onChange={(value) =>
|
||||||
checkedLabel="启用"
|
page.setHumanConfigForm({ ...page.humanConfigForm, roomTargetMinOnline: value })
|
||||||
label="启用国家配置"
|
}
|
||||||
uncheckedLabel="关闭"
|
|
||||||
onChange={(_, checked) => page.setHumanCountryLimitEnabled(checked)}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
<ConfigNumberField
|
||||||
<TextField
|
label="目标人数上限"
|
||||||
label="真人房间低于人数"
|
value={page.humanConfigForm.roomTargetMaxOnline}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, roomTargetMaxOnline: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminFormFieldGrid>
|
||||||
|
</AdminFormSection>
|
||||||
|
|
||||||
|
<AdminFormSection title="送礼机器人规则">
|
||||||
|
<AdminFormFieldGrid>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最短送礼间隔"
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.normalGiftIntervalMinMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({
|
||||||
|
...page.humanConfigForm,
|
||||||
|
normalGiftIntervalMinMs: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最长送礼间隔"
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.normalGiftIntervalMaxMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({
|
||||||
|
...page.humanConfigForm,
|
||||||
|
normalGiftIntervalMaxMs: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最短停留"
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.robotStayMinMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, robotStayMinMs: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最长停留"
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.robotStayMaxMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, robotStayMaxMs: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最短补位"
|
||||||
|
min={0}
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.robotReplaceMinMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, robotReplaceMinMs: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="最长补位"
|
||||||
|
min={0}
|
||||||
|
unit="毫秒"
|
||||||
|
value={page.humanConfigForm.robotReplaceMaxMs}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, robotReplaceMaxMs: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConfigNumberField
|
||||||
|
label="房间送礼机器人数"
|
||||||
|
value={page.humanConfigForm.maxGiftSenders}
|
||||||
|
onChange={(value) =>
|
||||||
|
page.setHumanConfigForm({ ...page.humanConfigForm, maxGiftSenders: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminFormFieldGrid>
|
||||||
|
</AdminFormSection>
|
||||||
|
|
||||||
|
<AdminFormSection title="礼物合集">
|
||||||
|
<GiftAutocomplete
|
||||||
|
label="普通礼物合集"
|
||||||
|
loading={page.giftOptionsLoading}
|
||||||
|
options={page.giftOptions}
|
||||||
required
|
required
|
||||||
type="number"
|
value={page.selectedHumanGiftOptions.giftIds}
|
||||||
value={page.humanConfigForm.candidateRoomMaxOnline}
|
onChange={(options) => page.selectHumanGiftIds("giftIds", options)}
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({
|
|
||||||
...page.humanConfigForm,
|
|
||||||
candidateRoomMaxOnline: event.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<GiftAutocomplete
|
||||||
label="目标人数下限"
|
label="幸运礼物合集"
|
||||||
required
|
loading={page.giftOptionsLoading}
|
||||||
type="number"
|
options={page.giftOptions}
|
||||||
value={page.humanConfigForm.roomTargetMinOnline}
|
value={page.selectedHumanGiftOptions.luckyGiftIds}
|
||||||
onChange={(event) =>
|
onChange={(options) => page.selectHumanGiftIds("luckyGiftIds", options)}
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, roomTargetMinOnline: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<GiftAutocomplete
|
||||||
label="目标人数上限"
|
label="超级幸运礼物合集"
|
||||||
required
|
loading={page.giftOptionsLoading}
|
||||||
type="number"
|
options={page.giftOptions}
|
||||||
value={page.humanConfigForm.roomTargetMaxOnline}
|
value={page.selectedHumanGiftOptions.superLuckyGiftIds}
|
||||||
onChange={(event) =>
|
onChange={(options) => page.selectHumanGiftIds("superLuckyGiftIds", options)}
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, roomTargetMaxOnline: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</AdminFormSection>
|
||||||
<div className={styles.formGrid}>
|
|
||||||
<TextField
|
<AdminFormSection title="幸运连击规则">
|
||||||
label="最短送礼间隔(毫秒)"
|
<AdminFormFieldGrid>
|
||||||
required
|
<ConfigNumberField
|
||||||
type="number"
|
label="最少幸运连击"
|
||||||
value={page.humanConfigForm.normalGiftIntervalMinMs}
|
value={page.humanConfigForm.luckyComboMin}
|
||||||
onChange={(event) =>
|
onChange={(value) =>
|
||||||
page.setHumanConfigForm({
|
page.setHumanConfigForm({ ...page.humanConfigForm, luckyComboMin: value })
|
||||||
...page.humanConfigForm,
|
}
|
||||||
normalGiftIntervalMinMs: event.target.value,
|
/>
|
||||||
})
|
<ConfigNumberField
|
||||||
}
|
label="最多幸运连击"
|
||||||
/>
|
value={page.humanConfigForm.luckyComboMax}
|
||||||
<TextField
|
onChange={(value) =>
|
||||||
label="最长送礼间隔(毫秒)"
|
page.setHumanConfigForm({ ...page.humanConfigForm, luckyComboMax: value })
|
||||||
required
|
}
|
||||||
type="number"
|
/>
|
||||||
value={page.humanConfigForm.normalGiftIntervalMaxMs}
|
<ConfigNumberField
|
||||||
onChange={(event) =>
|
label="最短幸运间隔"
|
||||||
page.setHumanConfigForm({
|
unit="毫秒"
|
||||||
...page.humanConfigForm,
|
value={page.humanConfigForm.luckyPauseMinMs}
|
||||||
normalGiftIntervalMaxMs: event.target.value,
|
onChange={(value) =>
|
||||||
})
|
page.setHumanConfigForm({ ...page.humanConfigForm, luckyPauseMinMs: value })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<ConfigNumberField
|
||||||
label="最短停留(毫秒)"
|
label="最长幸运间隔"
|
||||||
required
|
unit="毫秒"
|
||||||
type="number"
|
value={page.humanConfigForm.luckyPauseMaxMs}
|
||||||
value={page.humanConfigForm.robotStayMinMs}
|
onChange={(value) =>
|
||||||
onChange={(event) =>
|
page.setHumanConfigForm({ ...page.humanConfigForm, luckyPauseMaxMs: value })
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, robotStayMinMs: event.target.value })
|
}
|
||||||
}
|
/>
|
||||||
/>
|
</AdminFormFieldGrid>
|
||||||
<TextField
|
</AdminFormSection>
|
||||||
label="最长停留(毫秒)"
|
|
||||||
required
|
<AdminFormSection
|
||||||
type="number"
|
actions={
|
||||||
value={page.humanConfigForm.robotStayMaxMs}
|
<div className={styles.configSwitchActions}>
|
||||||
onChange={(event) =>
|
<span className={styles.switchField}>
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, robotStayMaxMs: event.target.value })
|
<AdminSwitch
|
||||||
}
|
checked={Boolean(page.humanConfigForm.countryLimitEnabled)}
|
||||||
/>
|
checkedLabel="启用"
|
||||||
<TextField
|
label="启用国家配置"
|
||||||
label="最短补位(毫秒)"
|
uncheckedLabel="关闭"
|
||||||
required
|
onChange={(_, checked) => page.setHumanCountryLimitEnabled(checked)}
|
||||||
type="number"
|
/>
|
||||||
value={page.humanConfigForm.robotReplaceMinMs}
|
</span>
|
||||||
onChange={(event) =>
|
</div>
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, robotReplaceMinMs: event.target.value })
|
}
|
||||||
}
|
title="国家进房配置"
|
||||||
/>
|
>
|
||||||
<TextField
|
{page.humanConfigForm.countryLimitEnabled ? <HumanCountryRules page={page} /> : null}
|
||||||
label="最长补位(毫秒)"
|
</AdminFormSection>
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.robotReplaceMaxMs}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, robotReplaceMaxMs: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="房间送礼机器人数"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.maxGiftSenders}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, maxGiftSenders: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<GiftAutocomplete
|
|
||||||
label="普通礼物合集"
|
|
||||||
loading={page.giftOptionsLoading}
|
|
||||||
options={page.giftOptions}
|
|
||||||
required
|
|
||||||
value={page.selectedHumanGiftOptions.giftIds}
|
|
||||||
onChange={(options) => page.selectHumanGiftIds("giftIds", options)}
|
|
||||||
/>
|
|
||||||
<div className={styles.formGrid}>
|
|
||||||
<TextField
|
|
||||||
label="最少幸运连击"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.luckyComboMin}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, luckyComboMin: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最多幸运连击"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.luckyComboMax}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, luckyComboMax: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最短幸运间隔(毫秒)"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.luckyPauseMinMs}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, luckyPauseMinMs: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="最长幸运间隔(毫秒)"
|
|
||||||
required
|
|
||||||
type="number"
|
|
||||||
value={page.humanConfigForm.luckyPauseMaxMs}
|
|
||||||
onChange={(event) =>
|
|
||||||
page.setHumanConfigForm({ ...page.humanConfigForm, luckyPauseMaxMs: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<GiftAutocomplete
|
|
||||||
label="幸运礼物合集"
|
|
||||||
loading={page.giftOptionsLoading}
|
|
||||||
options={page.giftOptions}
|
|
||||||
value={page.selectedHumanGiftOptions.luckyGiftIds}
|
|
||||||
onChange={(options) => page.selectHumanGiftIds("luckyGiftIds", options)}
|
|
||||||
/>
|
|
||||||
<GiftAutocomplete
|
|
||||||
label="超级幸运礼物合集"
|
|
||||||
loading={page.giftOptionsLoading}
|
|
||||||
options={page.giftOptions}
|
|
||||||
value={page.selectedHumanGiftOptions.superLuckyGiftIds}
|
|
||||||
onChange={(options) => page.selectHumanGiftIds("superLuckyGiftIds", options)}
|
|
||||||
/>
|
|
||||||
{page.humanConfigForm.countryLimitEnabled ? <HumanCountryRules page={page} /> : null}
|
|
||||||
<section className={styles.robotAutoPoolNotice}>
|
<section className={styles.robotAutoPoolNotice}>
|
||||||
<div className={styles.primaryText}>机器人池自动获取</div>
|
<div className={styles.primaryText}>机器人池自动获取</div>
|
||||||
<div className={styles.meta}>
|
<div className={styles.meta}>
|
||||||
@ -642,12 +604,26 @@ function HumanConfigDialog({ page }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ConfigNumberField({ label, min = 1, onChange, size, unit, value }) {
|
||||||
|
const fieldProps = {
|
||||||
|
label,
|
||||||
|
required: true,
|
||||||
|
size,
|
||||||
|
slotProps: { htmlInput: { min, step: 1 } },
|
||||||
|
type: "number",
|
||||||
|
value,
|
||||||
|
onChange: (event) => onChange(event.target.value),
|
||||||
|
};
|
||||||
|
|
||||||
|
return unit ? <AdminFormAmountField {...fieldProps} unit={unit} /> : <TextField {...fieldProps} />;
|
||||||
|
}
|
||||||
|
|
||||||
function HumanCountryRules({ page }) {
|
function HumanCountryRules({ page }) {
|
||||||
const rows = page.humanConfigForm.countryRules || [];
|
const rows = page.humanConfigForm.countryRules || [];
|
||||||
return (
|
return (
|
||||||
<section className={styles.countryRulesSection}>
|
<section className={styles.countryRulesSection}>
|
||||||
<div className={styles.countryRulesHeader}>
|
<div className={styles.countryRulesHeader}>
|
||||||
<div className={styles.primaryText}>国家进房配置</div>
|
<div className={styles.meta}>按机器人账号国家限制同时进入真人房的房间数量</div>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<AddOutlined fontSize="small" />}
|
startIcon={<AddOutlined fontSize="small" />}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@ -675,15 +651,11 @@ function HumanCountryRules({ page }) {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
<TextField
|
<ConfigNumberField
|
||||||
label="进房数量"
|
label="进房数量"
|
||||||
required
|
|
||||||
size="small"
|
size="small"
|
||||||
type="number"
|
|
||||||
value={rule.maxRoomCount}
|
value={rule.maxRoomCount}
|
||||||
onChange={(event) =>
|
onChange={(value) => page.updateHumanCountryRule(index, { maxRoomCount: value })}
|
||||||
page.updateHumanCountryRule(index, { maxRoomCount: event.target.value })
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<DeleteOutlineOutlined fontSize="small" />}
|
startIcon={<DeleteOutlineOutlined fontSize="small" />}
|
||||||
@ -694,13 +666,13 @@ function HumanCountryRules({ page }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{rows.length === 0 ? <div className={styles.meta}>当前没有国家配置</div> : null}
|
{rows.length === 0 ? <div className={styles.meta}>当前无数据</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function GiftAutocomplete({ label, loading, onChange, options, required = false, value }) {
|
function GiftAutocomplete({ error = false, helperText = "", label, loading, onChange, options, required = false, value }) {
|
||||||
return (
|
return (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
multiple
|
multiple
|
||||||
@ -711,7 +683,12 @@ function GiftAutocomplete({ label, loading, onChange, options, required = false,
|
|||||||
noOptionsText="当前无数据"
|
noOptionsText="当前无数据"
|
||||||
options={options}
|
options={options}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField {...params} label={required ? <RequiredLabel>{label}</RequiredLabel> : label} />
|
<TextField
|
||||||
|
{...params}
|
||||||
|
error={error}
|
||||||
|
helperText={helperText}
|
||||||
|
label={required ? <RequiredLabel>{label}</RequiredLabel> : label}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
size="small"
|
size="small"
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@ -286,6 +286,13 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.configSwitchActions {
|
||||||
|
display: inline-flex;
|
||||||
|
min-width: 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
.robotAutoPoolNotice {
|
.robotAutoPoolNotice {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
@ -319,13 +326,14 @@
|
|||||||
|
|
||||||
.countryRuleRow {
|
.countryRuleRow {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(180px, 1fr) minmax(140px, 0.6fr) auto;
|
grid-template-columns: minmax(220px, 1fr) minmax(132px, 0.42fr) auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.countryRulesHeader,
|
.countryRulesHeader,
|
||||||
|
.configSwitchActions,
|
||||||
.humanConfigActions {
|
.humanConfigActions {
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user