feat(feedback): 移除联系方式步骤,登录态用户身份已知
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
之前第三步要求填写微信/钉钉等联系方式,但用户已登录,后端已经 记录 user_id / user_name(与水印取的同一份),可以直接通过内部 渠道触达,无需再问。 流程从 4 步收紧为 3 步: 1) 选类型 2) 写内容 + 截图 + 板块 3) 成功页 提交概览页一并删除(信息不变就直接提交,少一次点击)。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -71,11 +71,10 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [historyOpen, setHistoryOpen] = useState(false);
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const [step, setStep] = useState<1 | 2 | 3 | 4>(1);
|
||||
const [step, setStep] = useState<1 | 2 | 3>(1); // 1=选类型, 2=写内容, 3=成功页
|
||||
const [type, setType] = useState<FeedbackType | null>(null);
|
||||
const [mod, setMod] = useState<string>('');
|
||||
const [content, setContent] = useState('');
|
||||
const [contact, setContact] = useState('');
|
||||
const [shots, setShots] = useState<UploadedImg[]>([]);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
@@ -125,7 +124,6 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
setStep(1);
|
||||
setType(null);
|
||||
setContent('');
|
||||
setContact('');
|
||||
setShots([]);
|
||||
setError(null);
|
||||
};
|
||||
@@ -147,12 +145,11 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
type,
|
||||
module: mod || null,
|
||||
content: content.trim(),
|
||||
contact: contact.trim() || null,
|
||||
screenshots: shots.map(s => s.url),
|
||||
userAgent: navigator.userAgent.slice(0, 500),
|
||||
}),
|
||||
});
|
||||
setStep(4);
|
||||
setStep(3);
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : String(e));
|
||||
} finally {
|
||||
@@ -162,21 +159,17 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
|
||||
const next = () => {
|
||||
if (step === 1 && !type) return;
|
||||
if (step === 2 && !content.trim()) {
|
||||
taRef.current?.focus();
|
||||
return;
|
||||
}
|
||||
if (step === 3) {
|
||||
if (step === 2) {
|
||||
if (!content.trim()) { taRef.current?.focus(); return; }
|
||||
submit();
|
||||
return;
|
||||
}
|
||||
setStep((step + 1) as typeof step);
|
||||
};
|
||||
|
||||
const back = () => setStep((Math.max(1, step - 1)) as typeof step);
|
||||
|
||||
const canNext = step === 1 ? !!type : step === 2 ? content.trim().length > 0 : true;
|
||||
const progress = ((step === 4 ? 4 : step) / 4) * 100;
|
||||
const progress = step >= 3 ? 100 : (step / 2) * 100;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -265,13 +258,12 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-black text-slate-800 leading-tight">
|
||||
{step === 4 ? '收到啦~' : '提个建议'}
|
||||
{step === 3 ? '收到啦~' : '提个建议'}
|
||||
</div>
|
||||
<div className="text-[10px] text-slate-400 font-bold">
|
||||
{step === 1 && '第一步 / 共 3 步'}
|
||||
{step === 2 && '第二步 / 共 3 步'}
|
||||
{step === 3 && '第三步 / 共 3 步'}
|
||||
{step === 4 && '感谢你的反馈'}
|
||||
{step === 1 && '第一步 / 共 2 步'}
|
||||
{step === 2 && '第二步 / 共 2 步'}
|
||||
{step === 3 && '感谢你的反馈'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -411,32 +403,7 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
)}
|
||||
|
||||
{step === 3 && (
|
||||
<motion.div key="s3" initial={{ opacity: 0, x: 12 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -12 }} transition={{ duration: 0.2 }} className="space-y-3">
|
||||
<p className="text-[12px] font-bold text-slate-600">方便留个联系方式吗?</p>
|
||||
<p className="text-[11px] text-slate-400 font-bold">非必填。留下我们可以跟进进展,没留也不影响提交~</p>
|
||||
<input
|
||||
type="text"
|
||||
value={contact}
|
||||
onChange={(e) => setContact(e.target.value)}
|
||||
autoFocus
|
||||
maxLength={120}
|
||||
placeholder="微信 / 钉钉 / 邮箱 / 手机号 都行"
|
||||
className="w-full bg-slate-50 border-none rounded-xl p-3 text-[12px] text-slate-700 outline-none focus:ring-2 focus:ring-blue-500/20"
|
||||
/>
|
||||
<div className="bg-slate-50 rounded-xl p-3 mt-1">
|
||||
<div className="text-[10px] font-bold text-slate-400 uppercase mb-1.5">提交概览</div>
|
||||
<div className="text-[11px] text-slate-600 space-y-1">
|
||||
<div>类型:<span className="font-bold text-slate-800">{TYPE_OPTIONS.find(t => t.key === type)?.label}</span></div>
|
||||
<div>板块:<span className="font-bold text-slate-800">{MODULE_LABELS[mod] || '通用'}</span></div>
|
||||
<div className="break-words">内容:<span className="font-bold text-slate-800 line-clamp-3">{content}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
{error && <div className="text-[11px] text-rose-500 font-bold">{error}</div>}
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{step === 4 && (
|
||||
<motion.div key="s4" initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.3 }} className="text-center py-6">
|
||||
<motion.div key="s3" initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.3 }} className="text-center py-6">
|
||||
<motion.div
|
||||
initial={{ scale: 0, rotate: -180 }}
|
||||
animate={{ scale: 1, rotate: 0 }}
|
||||
@@ -446,14 +413,14 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
<Check size={28} strokeWidth={3} className="text-white" />
|
||||
</motion.div>
|
||||
<div className="text-base font-black text-slate-800 mb-1">谢谢你的反馈 ❤️</div>
|
||||
<div className="text-[12px] text-slate-500 font-bold leading-relaxed">产品同学会认真看每一条<br />有进展会通过你留的联系方式同步</div>
|
||||
<div className="text-[12px] text-slate-500 font-bold leading-relaxed">产品同学会认真看每一条<br />有进展可以在「我的反馈」里查看</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
{step < 4 && (
|
||||
{step < 3 && (
|
||||
<div className="px-4 py-3 border-t border-slate-100 flex items-center gap-2">
|
||||
{step > 1 && (
|
||||
<button
|
||||
@@ -469,12 +436,12 @@ export default function FeedbackFab({ module: moduleProp }: Props = {}) {
|
||||
disabled={!canNext || submitting}
|
||||
className="px-4 py-2 rounded-xl text-[12px] font-bold bg-blue-600 text-white shadow shadow-blue-100 disabled:bg-slate-200 disabled:text-slate-400 disabled:shadow-none flex items-center gap-1"
|
||||
>
|
||||
{submitting ? '提交中…' : step === 3 ? '提交' : '下一步'}
|
||||
{!submitting && step !== 3 && <ChevronRight size={14} />}
|
||||
{submitting ? '提交中…' : step === 2 ? '提交' : '下一步'}
|
||||
{!submitting && step !== 2 && <ChevronRight size={14} />}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{step === 4 && (
|
||||
{step === 3 && (
|
||||
<div className="px-4 py-3 border-t border-slate-100">
|
||||
<button
|
||||
onClick={close}
|
||||
|
||||
Reference in New Issue
Block a user