forked from wangziqi/gongxue-base
feat: configure daily check-in rewards
This commit is contained in:
@@ -94,6 +94,20 @@ function intText(value: unknown, fallback = '') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function metadataNumberText(metadata: Record<string, unknown> | undefined, key: string) {
|
||||
const value = metadata?.[key];
|
||||
if (value === null || value === undefined || value === '') return '';
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) ? String(Math.trunc(parsed)) : '';
|
||||
}
|
||||
|
||||
function optionalPositiveIntText(value: string) {
|
||||
if (!value.trim()) return undefined;
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed)) return undefined;
|
||||
return Math.max(1, Math.trunc(parsed));
|
||||
}
|
||||
|
||||
function taskTypeLabel(type?: string | null) {
|
||||
if (type === 'daily_check_in') return '每日签到';
|
||||
if (type === 'feedback_submit') return '提交反馈';
|
||||
@@ -207,6 +221,10 @@ interface PointTaskFormState {
|
||||
validFrom: string;
|
||||
validTo: string;
|
||||
order: string;
|
||||
requiredStreak: string;
|
||||
minStreak: string;
|
||||
maxStreak: string;
|
||||
streakMultipleOf: string;
|
||||
}
|
||||
|
||||
function defaultPointTaskForm(): PointTaskFormState {
|
||||
@@ -223,6 +241,10 @@ function defaultPointTaskForm(): PointTaskFormState {
|
||||
validFrom: '',
|
||||
validTo: '',
|
||||
order: '0',
|
||||
requiredStreak: '',
|
||||
minStreak: '',
|
||||
maxStreak: '',
|
||||
streakMultipleOf: '',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -500,6 +522,10 @@ export default function TenantMarketingPage() {
|
||||
validFrom: item.validFrom ? item.validFrom.slice(0, 10) : '',
|
||||
validTo: item.validTo ? item.validTo.slice(0, 10) : '',
|
||||
order: intText(item.order, '0'),
|
||||
requiredStreak: metadataNumberText(item.metadata, 'requiredStreak'),
|
||||
minStreak: metadataNumberText(item.metadata, 'minStreak'),
|
||||
maxStreak: metadataNumberText(item.metadata, 'maxStreak'),
|
||||
streakMultipleOf: metadataNumberText(item.metadata, 'streakMultipleOf'),
|
||||
});
|
||||
setPointFilter(prev => ({ ...prev, selectedTaskId: item.id }));
|
||||
}
|
||||
@@ -612,6 +638,17 @@ export default function TenantMarketingPage() {
|
||||
setBusy('point-task-save');
|
||||
setError('');
|
||||
try {
|
||||
const metadata: Record<string, unknown> = { source: 'taro-tenant-admin' };
|
||||
if (pointTaskForm.taskType === 'daily_check_in') {
|
||||
const requiredStreak = optionalPositiveIntText(pointTaskForm.requiredStreak);
|
||||
const minStreak = optionalPositiveIntText(pointTaskForm.minStreak);
|
||||
const maxStreak = optionalPositiveIntText(pointTaskForm.maxStreak);
|
||||
const streakMultipleOf = optionalPositiveIntText(pointTaskForm.streakMultipleOf);
|
||||
if (requiredStreak !== undefined) metadata.requiredStreak = requiredStreak;
|
||||
if (minStreak !== undefined) metadata.minStreak = minStreak;
|
||||
if (maxStreak !== undefined) metadata.maxStreak = maxStreak;
|
||||
if (streakMultipleOf !== undefined) metadata.streakMultipleOf = streakMultipleOf;
|
||||
}
|
||||
const result = await upsertPointActivityTask({
|
||||
id: pointTaskForm.id || undefined,
|
||||
code: pointTaskForm.code.trim(),
|
||||
@@ -625,7 +662,7 @@ export default function TenantMarketingPage() {
|
||||
validFrom: pointTaskForm.validFrom || null,
|
||||
validTo: pointTaskForm.validTo || null,
|
||||
order: Math.trunc(Number(pointTaskForm.order || 0)),
|
||||
metadata: { source: 'taro-tenant-admin' },
|
||||
metadata,
|
||||
});
|
||||
Taro.showToast({ title: '积分任务已保存', icon: 'success' });
|
||||
if (result.item?.id) setPointFilter(prev => ({ ...prev, selectedTaskId: result.item?.id || prev.selectedTaskId }));
|
||||
@@ -978,6 +1015,14 @@ export default function TenantMarketingPage() {
|
||||
<Input className='admin-input' type='number' placeholder='奖励积分' value={pointTaskForm.rewardPoints} onInput={event => setPointTaskForm(prev => ({ ...prev, rewardPoints: String(event.detail.value || '') }))} />
|
||||
<Input className='admin-input' type='number' placeholder='单用户领取上限' value={pointTaskForm.claimLimitPerUser} onInput={event => setPointTaskForm(prev => ({ ...prev, claimLimitPerUser: String(event.detail.value || '') }))} />
|
||||
</View>
|
||||
{pointTaskForm.taskType === 'daily_check_in' ? (
|
||||
<View className='admin-form-grid'>
|
||||
<Input className='admin-input' type='number' placeholder='仅第 N 天奖励' value={pointTaskForm.requiredStreak} onInput={event => setPointTaskForm(prev => ({ ...prev, requiredStreak: String(event.detail.value || '') }))} />
|
||||
<Input className='admin-input' type='number' placeholder='最小连续天数' value={pointTaskForm.minStreak} onInput={event => setPointTaskForm(prev => ({ ...prev, minStreak: String(event.detail.value || '') }))} />
|
||||
<Input className='admin-input' type='number' placeholder='最大连续天数' value={pointTaskForm.maxStreak} onInput={event => setPointTaskForm(prev => ({ ...prev, maxStreak: String(event.detail.value || '') }))} />
|
||||
<Input className='admin-input' type='number' placeholder='每 N 天循环奖励' value={pointTaskForm.streakMultipleOf} onInput={event => setPointTaskForm(prev => ({ ...prev, streakMultipleOf: String(event.detail.value || '') }))} />
|
||||
</View>
|
||||
) : null}
|
||||
<View className='admin-actions compact'>
|
||||
{(['manual', 'practice_complete', 'vocabulary_review', 'mock_exam_submit', 'daily_check_in', 'feedback_submit', 'feedback_resolved'] as const).map(type => (
|
||||
<Button key={type} className={`admin-button ${pointTaskForm.taskType === type ? 'active' : ''}`} onClick={() => setPointTaskForm(prev => ({ ...prev, taskType: type }))}>{taskTypeLabel(type)}</Button>
|
||||
|
||||
Reference in New Issue
Block a user