feat: 反馈加反馈类型/运营回复 + 提现加提现类型筛选 (#34)
用户反馈后台 + 提现审核后台的运营字段与筛选。 - 反馈页:新增「反馈类型」列(比价反馈/普通反馈 + 场景)、顶部「反馈类型」筛选;审核抽屉采纳/拒绝 都能填「给用户的回复」(用户端可见),并回显反馈类型/场景/运营回复。 - 提现页:新增「提现类型」列(福利页提现/邀请提现)、顶部「提现类型」筛选,详情抽屉展示提现类型。 - types.ts:Feedback 加 source/scene/admin_reply,WithdrawOrder 加 source。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: zzhyyyyy <2685922758@qq.com> Reviewed-on: #34 Co-authored-by: zhuzihao <zhuzihao@wonderable.ai> Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
This commit was merged in pull request #34.
This commit is contained in:
@@ -49,6 +49,17 @@ const statusTag = (s: string) => {
|
||||
return <Tag color={m.color}>{m.label}</Tag>;
|
||||
};
|
||||
|
||||
// 反馈类型:comparison=比价反馈 / profile(及旧数据)=普通反馈
|
||||
const SOURCE_META: Record<string, { label: string; color: string }> = {
|
||||
comparison: { label: '比价反馈', color: 'geekblue' },
|
||||
profile: { label: '普通反馈', color: 'default' },
|
||||
};
|
||||
|
||||
const sourceTag = (s: string) => {
|
||||
const m = SOURCE_META[s] ?? { label: '普通反馈', color: 'default' };
|
||||
return <Tag color={m.color}>{m.label}</Tag>;
|
||||
};
|
||||
|
||||
function FeedbackImages({ images }: { images: string[] | null }) {
|
||||
if (!images || !images.length) return <Text type="secondary">无截图</Text>;
|
||||
return (
|
||||
@@ -113,12 +124,14 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
await api.post(`/admin/api/feedbacks/${feedback.id}/approve`, {
|
||||
reward_coins: v.reward_coins,
|
||||
note: v.note?.trim() || null,
|
||||
reply: v.reply?.trim() || null,
|
||||
});
|
||||
message.success(`已采纳,发放 ${v.reward_coins} 金币`);
|
||||
} else {
|
||||
await api.post(`/admin/api/feedbacks/${feedback.id}/reject`, {
|
||||
reason: v.reason.trim(),
|
||||
note: v.note?.trim() || null,
|
||||
reply: v.reply?.trim() || null,
|
||||
});
|
||||
message.success('已拒绝');
|
||||
}
|
||||
@@ -155,6 +168,14 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
<Text type="secondary">
|
||||
用户 {feedback.user_id} · {formatWallTime(feedback.created_at)}
|
||||
</Text>
|
||||
<div style={{ marginTop: 6 }}>
|
||||
{sourceTag(feedback.source)}
|
||||
{feedback.scene ? (
|
||||
<Text type="secondary" style={{ marginLeft: 6 }}>
|
||||
场景:{feedback.scene}
|
||||
</Text>
|
||||
) : null}
|
||||
</div>
|
||||
<Paragraph style={{ whiteSpace: 'pre-wrap', marginTop: 8, marginBottom: 8 }}>
|
||||
{feedback.content || '-'}
|
||||
</Paragraph>
|
||||
@@ -200,7 +221,11 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
</div>
|
||||
)}
|
||||
<div style={{ marginTop: 6 }}>
|
||||
审核备注:{feedback.review_note || <Text type="secondary">(无)</Text>}
|
||||
审核备注(内部):{feedback.review_note || <Text type="secondary">(无)</Text>}
|
||||
</div>
|
||||
<div style={{ marginTop: 6 }}>
|
||||
给用户的回复(用户可见):
|
||||
{feedback.admin_reply || <Text type="secondary">(无)</Text>}
|
||||
</div>
|
||||
{isPending(feedback.status) && (
|
||||
<div style={{ marginTop: 6 }}>
|
||||
@@ -243,11 +268,23 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="note"
|
||||
label="采纳要点 / 审核备注(选填)"
|
||||
label="采纳要点 / 审核备注(选填,内部)"
|
||||
rules={[{ max: 256, message: '最多 256 字' }]}
|
||||
>
|
||||
<Input.TextArea rows={3} maxLength={256} showCount placeholder="如:建议已采纳,将在下个版本上线" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="reply"
|
||||
label="给用户的回复(选填,用户端可见)"
|
||||
rules={[{ max: 256, message: '最多 256 字' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={2}
|
||||
maxLength={256}
|
||||
showCount
|
||||
placeholder="将展示在用户的「我的反馈」里,如:感谢反馈,已收到~"
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -268,6 +305,18 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
>
|
||||
<Input.TextArea rows={2} maxLength={256} showCount placeholder="运营内部备注" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="reply"
|
||||
label="给用户的回复(选填,用户端可见)"
|
||||
rules={[{ max: 256, message: '最多 256 字' }]}
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={2}
|
||||
maxLength={256}
|
||||
showCount
|
||||
placeholder="除未采纳原因外,想额外对用户说的话(选填)"
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
@@ -294,7 +343,10 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
<Text type="secondary">
|
||||
#{h.id} · {formatWallTime(h.created_at)}
|
||||
</Text>
|
||||
{statusTag(h.status)}
|
||||
<Space size={4}>
|
||||
{sourceTag(h.source)}
|
||||
{statusTag(h.status)}
|
||||
</Space>
|
||||
</div>
|
||||
<Paragraph
|
||||
style={{ whiteSpace: 'pre-wrap', margin: '6px 0 0' }}
|
||||
@@ -313,6 +365,9 @@ export default function FeedbackHandleDrawer({ feedback, open, onClose, onDone }
|
||||
未采纳:{h.reject_reason || '-'}
|
||||
</Text>
|
||||
)}
|
||||
{h.admin_reply ? (
|
||||
<div style={{ fontSize: 12, marginTop: 2 }}>回复:{h.admin_reply}</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
|
||||
Reference in New Issue
Block a user