v1.2.64 - 添加联系我们功能和反馈查看面板
This commit is contained in:
parent
e1ac548115
commit
441c8a5aa7
|
|
@ -255,3 +255,15 @@ class UserRole:
|
|||
cls.USER: "用户"
|
||||
}
|
||||
return names.get(role, "用户")
|
||||
|
||||
class UserFeedback(Base):
|
||||
"""用户反馈表"""
|
||||
__tablename__ = "user_feedbacks"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.f99_90_id"), nullable=False)
|
||||
content = Column(Text, nullable=False)
|
||||
contact = Column(String(100), default="")
|
||||
status = Column(String(20), default="pending") # pending, resolved
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
|
|
|
|||
|
|
@ -303,3 +303,47 @@ def delete_user(
|
|||
db.commit()
|
||||
|
||||
return {"message": "删除成功"}
|
||||
|
||||
|
||||
@router.post("/feedback")
|
||||
async def submit_feedback(
|
||||
content: str,
|
||||
contact: str = "",
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""用户提交反馈"""
|
||||
from app.models import UserFeedback
|
||||
|
||||
feedback = UserFeedback(
|
||||
user_id=current_user.f99_90_id,
|
||||
content=content,
|
||||
contact=contact,
|
||||
status="pending"
|
||||
)
|
||||
db.add(feedback)
|
||||
db.commit()
|
||||
|
||||
return {"success": True, "message": "反馈已提交"}
|
||||
|
||||
|
||||
@router.get("/feedback/list")
|
||||
async def list_feedbacks(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取用户反馈列表(仅管理员)"""
|
||||
if current_user.role != "admin":
|
||||
return {"error": "无权限"}, 403
|
||||
|
||||
from app.models import UserFeedback
|
||||
feedbacks = db.query(UserFeedback).order_by(UserFeedback.created_at.desc()).all()
|
||||
|
||||
return [{
|
||||
"id": f.id,
|
||||
"user_id": f.user_id,
|
||||
"content": f.content,
|
||||
"contact": f.contact,
|
||||
"status": f.status,
|
||||
"created_at": f.created_at.isoformat() if f.created_at else None
|
||||
} for f in feedbacks]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ export default function Home() {
|
|||
const [seekStats, setSeekStats] = useState({ seekCount: 0, matchedCount: 0 })
|
||||
const [recentPosts, setRecentPosts] = useState([])
|
||||
const [dragonStats, setDragonStats] = useState({})
|
||||
const [showFeedback, setShowFeedback] = useState(false)
|
||||
const [feedbackContent, setFeedbackContent] = useState('')
|
||||
const [feedbackContact, setFeedbackContact] = useState('')
|
||||
const currentPath = window.location.hash.slice(1) || '/'
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -65,7 +68,26 @@ export default function Home() {
|
|||
}).catch(() => {})
|
||||
|
||||
// 获取最新一尘帖子
|
||||
fetch('/api/yichens/stats/dragons-today').then(res => res.json()).then(data => {
|
||||
// 提交反馈
|
||||
const submitFeedback = async () => {
|
||||
if (!feedbackContent.trim()) return alert('请输入反馈内容')
|
||||
try {
|
||||
const res = await fetch('/api/users/feedback', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` },
|
||||
body: JSON.stringify({ content: feedbackContent, contact: feedbackContact })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.success) {
|
||||
alert('反馈已提交,感谢您的意见!')
|
||||
setShowFeedback(false)
|
||||
setFeedbackContent('')
|
||||
setFeedbackContact('')
|
||||
}
|
||||
} catch (e) { alert('提交失败') }
|
||||
}
|
||||
|
||||
fetch('/api/yichens/stats/dragons-today').then(res => res.json()).then(data => {
|
||||
setDragonStats(data || {})
|
||||
}).catch(() => {})
|
||||
|
||||
|
|
@ -104,6 +126,34 @@ export default function Home() {
|
|||
{ label: '总利润', value: formatMoney(stats.totalProfit) + '万', color: stats.totalProfit >= 0 ? '#10b981' : '#f43f5e' }
|
||||
]
|
||||
|
||||
// 反馈弹窗
|
||||
if (showFeedback) {
|
||||
return (
|
||||
<div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.8)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999 }}>
|
||||
<div style={{ background: '#1a1a2e', borderRadius: '12px', padding: '24px', width: '90%', maxWidth: '400px' }}>
|
||||
<div style={{ fontSize: '18px', fontWeight: 'bold', marginBottom: '16px', color: '#fff' }}>联系我们</div>
|
||||
<textarea
|
||||
value={feedbackContent}
|
||||
onChange={(e) => setFeedbackContent(e.target.value)}
|
||||
placeholder="请输入您的反馈内容..."
|
||||
style={{ width: '100%', height: '120px', background: '#16213e', border: '1px solid #333', borderRadius: '8px', padding: '12px', color: '#fff', fontSize: '14px', marginBottom: '12px' }}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={feedbackContact}
|
||||
onChange={(e) => setFeedbackContact(e.target.value)}
|
||||
placeholder="联系方式(选填)"
|
||||
style={{ width: '100%', background: '#16213e', border: '1px solid #333', borderRadius: '8px', padding: '12px', color: '#fff', fontSize: '14px', marginBottom: '16px' }}
|
||||
/>
|
||||
<div style={{ display: 'flex', gap: '12px' }}>
|
||||
<button onClick={() => setShowFeedback(false)} style={{ flex: 1, padding: '12px', background: '#333', border: 'none', borderRadius: '8px', color: '#fff', cursor: 'pointer' }}>取消</button>
|
||||
<button onClick={submitFeedback} style={{ flex: 1, padding: '12px', background: '#3b82f6', border: 'none', borderRadius: '8px', color: '#fff', cursor: 'pointer', fontWeight: 'bold' }}>提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
minHeight: '100vh', overflowY: 'auto',
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ export default function Info() {
|
|||
const [myList, setMyList] = useState([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [editingItem, setEditingItem] = useState(null)
|
||||
const [filterType, setFilterType] = useState('all') // all/seek/deal
|
||||
const [filterType, setFilterType] = useState('all')
|
||||
const [showFeedbackTab, setShowFeedbackTab] = useState(false) // all/seek/deal
|
||||
const [expandedItems, setExpandedItems] = useState({}) // 展开状态
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
|
|
@ -558,9 +559,29 @@ export default function Info() {
|
|||
>
|
||||
💰 行情
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowFeedbackTab(true)}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: showFeedbackTab ? '#8b5cf6' : '#374151',
|
||||
border: 'none',
|
||||
borderRadius: '6px',
|
||||
color: '#fff',
|
||||
fontSize: '13px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
📮 反馈
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 发布列表 */}
|
||||
{showFeedbackTab ? (
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<div style={{ color: '#fff', fontSize: '16px', fontWeight: '600', marginBottom: '12px' }}>📮 用户反馈</div>
|
||||
<FeedbackList />
|
||||
</div>
|
||||
) : (
|
||||
/* 发布列表 */
|
||||
{loading ? (
|
||||
<div style={{ color: '#9ca3af', textAlign: 'center', padding: '30px' }}>加载中...</div>
|
||||
) : filteredList.length === 0 ? (
|
||||
|
|
|
|||
Loading…
Reference in New Issue