feat: 自动化支持奖励兑换并修复主页滚动同步

This commit is contained in:
NanGua-QWQ
2026-04-24 18:16:59 +08:00
parent 388d935241
commit 0b39a1fffd
10 changed files with 441 additions and 13 deletions
+50
View File
@@ -36,11 +36,13 @@ import {
normalizeTriggerTree,
queryTreeToJson,
normalizeActionDrafts,
parseRewardActionValue,
queryTreeToTriggers,
triggerTreeJsonToQueryTree,
type ActionDraft,
type AutoScoreExecutionBatch,
type AutoScoreExecutionConfig,
type AutoScoreRewardOption,
type AutoScoreRule,
type AutoScoreTagOption,
} from "./AutoScore/AutoScoreUtils"
@@ -55,6 +57,12 @@ interface TagItem {
name: string
}
interface RewardItem {
id: number
name: string
cost_points: number
}
interface RuleFormValues {
name?: string
studentNames?: string[]
@@ -152,6 +160,7 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
const [form] = Form.useForm<RuleFormValues>()
const [messageApi, contextHolder] = message.useMessage()
const [tags, setTags] = useState<TagItem[]>([])
const [rewards, setRewards] = useState<RewardItem[]>([])
const tagOptions = useMemo<AutoScoreTagOption[]>(
() =>
@@ -161,6 +170,18 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
})),
[tags]
)
const rewardOptions = useMemo<AutoScoreRewardOption[]>(
() =>
rewards.map((reward) => ({
label: reward.name,
value: String(reward.id),
})),
[rewards]
)
const rewardLabelById = useMemo(
() => new Map(rewards.map((reward) => [reward.id, reward.name] as const)),
[rewards]
)
const triggerConfig = useMemo(
() => createTriggerQueryConfig(t, tagOptions),
@@ -288,6 +309,20 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
}
}
const fetchRewards = async () => {
const api = (window as any).api
if (!api || !canEdit) return
try {
const res = await api.rewardSettingQuery()
if (res.success && Array.isArray(res.data)) {
setRewards(res.data)
}
} catch {
void 0
}
}
const fetchRules = async () => {
const api = (window as any).api
if (!api || !canEdit) return
@@ -323,6 +358,7 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
useEffect(() => {
if (!canEdit) return
fetchTags().catch(() => void 0)
fetchRewards().catch(() => void 0)
fetchStudents().catch(() => void 0)
fetchRules().catch(() => void 0)
fetchBatches().catch(() => void 0)
@@ -445,6 +481,10 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
messageApi.warning(t("autoScore.tagNamePlaceholder"))
return
}
if (actionPayload.error === "reward_required") {
messageApi.warning(t("autoScore.rewardRequired"))
return
}
if (actionPayload.actions.length === 0) {
messageApi.warning(t("autoScore.actionRequired"))
return
@@ -623,6 +663,15 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
if (action.event === "settle_score") {
return `${t("autoScore.actionSettleScore")}: ${t("autoScore.actionSettleScoreHint")}`
}
if (action.event === "reward_exchange") {
const rewardValue = parseRewardActionValue(action.value)
const rewardLabel = rewardValue
? rewardLabelById.get(rewardValue.rewardId) ||
rewardValue.rewardName ||
`#${rewardValue.rewardId}`
: String(action.value || "").trim() || "-"
return `${t("rewardExchange.title")}: ${rewardLabel}`
}
return `${action.event}: ${String(action.value || "").trim() || "-"}`
}
@@ -905,6 +954,7 @@ function AutoScoreManager({ canEdit }: AutoScoreManagerProps): React.JSX.Element
<ActionEditor
value={actionDrafts}
tagOptions={tagOptions}
rewardOptions={rewardOptions}
canEdit={canEdit}
onChange={(nextDrafts) => setActionDrafts(normalizeActionDrafts(nextDrafts))}
/>