v1.2.64 - 添加联系我们功能和反馈查看面板
This commit is contained in:
parent
e1ac548115
commit
441c8a5aa7
|
|
@ -255,3 +255,15 @@ class UserRole:
|
||||||
cls.USER: "用户"
|
cls.USER: "用户"
|
||||||
}
|
}
|
||||||
return names.get(role, "用户")
|
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()
|
db.commit()
|
||||||
|
|
||||||
return {"message": "删除成功"}
|
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 [seekStats, setSeekStats] = useState({ seekCount: 0, matchedCount: 0 })
|
||||||
const [recentPosts, setRecentPosts] = useState([])
|
const [recentPosts, setRecentPosts] = useState([])
|
||||||
const [dragonStats, setDragonStats] = 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) || '/'
|
const currentPath = window.location.hash.slice(1) || '/'
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -65,6 +68,25 @@ export default function Home() {
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
|
|
||||||
// 获取最新一尘帖子
|
// 获取最新一尘帖子
|
||||||
|
// 提交反馈
|
||||||
|
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 => {
|
fetch('/api/yichens/stats/dragons-today').then(res => res.json()).then(data => {
|
||||||
setDragonStats(data || {})
|
setDragonStats(data || {})
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
|
|
@ -104,6 +126,34 @@ export default function Home() {
|
||||||
{ label: '总利润', value: formatMoney(stats.totalProfit) + '万', color: stats.totalProfit >= 0 ? '#10b981' : '#f43f5e' }
|
{ 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 (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
minHeight: '100vh', overflowY: 'auto',
|
minHeight: '100vh', overflowY: 'auto',
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ export default function Info() {
|
||||||
const [myList, setMyList] = useState([])
|
const [myList, setMyList] = useState([])
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [editingItem, setEditingItem] = useState(null)
|
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 [expandedItems, setExpandedItems] = useState({}) // 展开状态
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
|
@ -558,9 +559,29 @@ export default function Info() {
|
||||||
>
|
>
|
||||||
💰 行情
|
💰 行情
|
||||||
</button>
|
</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>
|
</div>
|
||||||
|
|
||||||
{/* 发布列表 */}
|
{showFeedbackTab ? (
|
||||||
|
<div style={{ marginTop: '20px' }}>
|
||||||
|
<div style={{ color: '#fff', fontSize: '16px', fontWeight: '600', marginBottom: '12px' }}>📮 用户反馈</div>
|
||||||
|
<FeedbackList />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
/* 发布列表 */
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div style={{ color: '#9ca3af', textAlign: 'center', padding: '30px' }}>加载中...</div>
|
<div style={{ color: '#9ca3af', textAlign: 'center', padding: '30px' }}>加载中...</div>
|
||||||
) : filteredList.length === 0 ? (
|
) : filteredList.length === 0 ? (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue