import React, { useState } from 'react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import * as ticketsApi from '../api/tickets.js'; import { getToken } from '../api/client.js'; import { safeSourceUrl } from './Tickets.jsx'; const categories = [['forum_bug', '论坛 Bug'], ['site_bug', '站内 Bug'], ['feature', '功能建议'], ['account', '账号问题'], ['other', '其他问题']]; const priorities = [['low', '低'], ['normal', '普通'], ['high', '高'], ['urgent', '紧急']]; export default function TicketCreate() { const navigate = useNavigate(); const location = useLocation(); const search = new URLSearchParams(location.search); const sourceUrl = safeSourceUrl((location.state && location.state.sourceUrl) || search.get('source_url') || search.get('from') || window.location.pathname); const [form, setForm] = useState({ subject: '', description: '', category: 'site_bug', priority: 'normal', source_url: sourceUrl }); const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const update = (key) => (e) => setForm((prev) => ({ ...prev, [key]: e.target.value })); if (!getToken()) return

登录后提交工单

请先登录,再反馈论坛或站内问题。

去登录
; const submit = async (e) => { e.preventDefault(); const subject = form.subject.trim(); const description = form.description.trim(); if (subject.length < 2) { setError('请填写问题标题(至少 2 个字)'); return; } if (description.length < 10) { setError('请详细描述问题(至少 10 个字)'); return; } setError(''); setBusy(true); try { const sourceValue = String(form.source_url ?? ''); const sourceUrl = safeSourceUrl(sourceValue); const hasInvalidSource = sourceValue.trim() || /[\u0000-\u001f\u007f-\u009f]/.test(sourceValue) || sourceValue.includes('\\'); if (hasInvalidSource && !sourceUrl) { setError('来源地址不合法,请填写站内路径或 http/https 地址'); return; } const data = await ticketsApi.createTicket({ ...form, subject, description, source: form.category === 'forum_bug' ? 'forum' : 'site', source_url: sourceUrl, browser_info: [navigator.userAgent, `${window.innerWidth}x${window.innerHeight}`].join(' | ').slice(0, 1000), }); if (!data.ticket || !data.ticket.id) throw new Error('工单创建成功但未返回编号'); navigate('/tickets/' + data.ticket.id, { replace: true }); } catch (err) { setError(err.message || '提交失败,请稍后重试'); } finally { setBusy(false); } }; return
← 返回工单

提交问题

描述得越具体,越有助于快速定位问题。

{error &&

{error}

}

请用一句话概括遇到的问题(最多 120 字)。