@@ -13,7 +13,11 @@ import {
1313 SelectTrigger ,
1414 SelectValue ,
1515} from "#/components/ui/select"
16- import type { CreateDefinitionInput , TaskCategory } from "#/lib/types/task"
16+ import type {
17+ CreateDefinitionInput ,
18+ TaskCategory ,
19+ TaskRewardTier ,
20+ } from "#/lib/types/task"
1721
1822interface DefinitionFormProps {
1923 defaultValues ?: Partial < CreateDefinitionInput >
@@ -48,12 +52,34 @@ export function DefinitionForm({
4852 isHidden : defaultValues ?. isHidden ?? false ,
4953 sortOrder : defaultValues ?. sortOrder ?? 0 ,
5054 activityId : defaultValues ?. activityId ?? ( null as string | null ) ,
55+ rewardTiersJson : JSON . stringify (
56+ defaultValues ?. rewardTiers ?? [ ] ,
57+ null ,
58+ 2 ,
59+ ) ,
5160 } ,
5261 onSubmit : async ( { value } ) => {
5362 const isEventBased =
5463 value . countingMethod === "event_count" ||
5564 value . countingMethod === "event_value"
5665 const trimmedFilter = value . filter . trim ( )
66+
67+ let rewardTiers : TaskRewardTier [ ] = [ ]
68+ const rewardTiersRaw = value . rewardTiersJson . trim ( )
69+ if ( rewardTiersRaw . length > 0 ) {
70+ try {
71+ const parsed = JSON . parse ( rewardTiersRaw ) as unknown
72+ if ( ! Array . isArray ( parsed ) ) {
73+ throw new Error ( "rewardTiers must be an array" )
74+ }
75+ rewardTiers = parsed as TaskRewardTier [ ]
76+ } catch ( err ) {
77+ throw new Error (
78+ `阶段性奖励 JSON 解析失败: ${ err instanceof Error ? err . message : String ( err ) } ` ,
79+ )
80+ }
81+ }
82+
5783 const input : CreateDefinitionInput = {
5884 name : value . name ,
5985 alias : value . alias || null ,
@@ -72,6 +98,7 @@ export function DefinitionForm({
7298 sortOrder : value . sortOrder ,
7399 activityId : value . activityId ,
74100 rewards : defaultValues ?. rewards ?? [ { type : "item" , id : "" , count : 1 } ] ,
101+ rewardTiers,
75102 }
76103 await onSubmit ( input )
77104 } ,
@@ -384,6 +411,27 @@ export function DefinitionForm({
384411 ) }
385412 </ form . Field >
386413
414+ < form . Field name = "rewardTiersJson" >
415+ { ( field ) => (
416+ < div className = "space-y-2" >
417+ < Label htmlFor = { field . name } > 阶段性奖励 (JSON, 可留空)</ Label >
418+ < Textarea
419+ id = { field . name }
420+ value = { field . state . value }
421+ onBlur = { field . handleBlur }
422+ onChange = { ( e ) => field . handleChange ( e . target . value ) }
423+ rows = { 5 }
424+ className = "font-mono text-xs"
425+ placeholder = '[{"alias":"tier-1","threshold":3,"rewards":[{"type":"item","id":"gold-uuid","count":100}]}]'
426+ />
427+ < p className = "text-xs text-muted-foreground" >
428+ 到达 threshold 后,该阶段奖励独立结算(autoClaim 任务走邮件自动发放,否则走手动领取)。
429+ alias 必须唯一,threshold 必须严格递增且不超过 targetValue。
430+ </ p >
431+ </ div >
432+ ) }
433+ </ form . Field >
434+
387435 < Button type = "submit" disabled = { isPending } >
388436 { isPending ? m . common_saving ( ) : submitLabel }
389437 </ Button >
0 commit comments