v0.2.6 - 移除注册时的手机号和短信验证功能(C环境)
This commit is contained in:
parent
645819844e
commit
02711d73c9
|
|
@ -1 +1 @@
|
||||||
1.2.98
|
VERSION=v0.2.1
|
||||||
|
|
|
||||||
|
|
@ -91,21 +91,7 @@ def register(user_data: UserCreate, db: Session = Depends(get_db)):
|
||||||
# 更新:
|
# 更新:
|
||||||
|
|
||||||
# 更新:
|
# 更新:
|
||||||
# 检查手机号是否已存在
|
# 检查手机号是否已存在(移除,2026-06-13)
|
||||||
# 更新:
|
|
||||||
if user_data.phone:
|
|
||||||
# 更新:
|
|
||||||
existing_phone = db.query(User).filter(User.phone == user_data.phone).first()
|
|
||||||
# 更新:
|
|
||||||
if existing_phone:
|
|
||||||
# 更新:
|
|
||||||
raise HTTPException(
|
|
||||||
# 更新:
|
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
|
||||||
# 更新:
|
|
||||||
detail="E00040:该手机号已被注册,请更换手机号"
|
|
||||||
# 更新:
|
|
||||||
)
|
|
||||||
# 更新:
|
# 更新:
|
||||||
if user_data.email:
|
if user_data.email:
|
||||||
# 更新:
|
# 更新:
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ def get_information_list(
|
||||||
user_id: Optional[str] = Query(None, description="用户ID,用于获取该用户的行情"),
|
user_id: Optional[str] = Query(None, description="用户ID,用于获取该用户的行情"),
|
||||||
deal_date: Optional[str] = Query(None, description="成交日期过滤,格式YYYY-MM-DD"),
|
deal_date: Optional[str] = Query(None, description="成交日期过滤,格式YYYY-MM-DD"),
|
||||||
page: int = Query(1, ge=1),
|
page: int = Query(1, ge=1),
|
||||||
page_size: int = Query(20, ge=1, le=500),
|
page_size: int = Query(20, ge=1, le=1000),
|
||||||
current_user: Optional[User] = Depends(get_current_user),
|
current_user: Optional[User] = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
response: Response = None
|
response: Response = None
|
||||||
|
|
@ -880,7 +880,7 @@ def get_deal_stats(
|
||||||
@router.get("/my/list", response_model=List[InformationResponse])
|
@router.get("/my/list", response_model=List[InformationResponse])
|
||||||
def get_my_information_list(
|
def get_my_information_list(
|
||||||
page: int = Query(1, ge=1),
|
page: int = Query(1, ge=1),
|
||||||
page_size: int = Query(20, ge=1, le=500),
|
page_size: int = Query(20, ge=1, le=1000),
|
||||||
current_user: User = Depends(get_current_user),
|
current_user: User = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class UserBase(BaseModel):
|
||||||
class UserCreate(UserBase):
|
class UserCreate(UserBase):
|
||||||
password: str = Field(..., min_length=6)
|
password: str = Field(..., min_length=6)
|
||||||
invite_code: Optional[str] = Field(None, alias="inviteCode") # 填写的邀请码(选填)
|
invite_code: Optional[str] = Field(None, alias="inviteCode") # 填写的邀请码(选填)
|
||||||
|
# 移除手机号和短信验证(2026-06-13)
|
||||||
|
|
||||||
|
|
||||||
class UserUpdate(BaseModel):
|
class UserUpdate(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,18 @@
|
||||||
# 版本更新记录
|
# 版本更新记录
|
||||||
|
|
||||||
|
## v0.2.5 (2026-05-13)
|
||||||
|
|
||||||
|
### 前端更新
|
||||||
|
- **News.jsx**
|
||||||
|
- 移除成交行情价格统计表格,只显示筛选后的结果
|
||||||
|
- 成交行情获取数量改为500条
|
||||||
|
|
||||||
|
- **YichensBoard.jsx**
|
||||||
|
- 增加复制链接功能,点击可复制原帖链接
|
||||||
|
|
||||||
|
### 环境配置
|
||||||
|
- C环境Nginx配置为代理到B环境后端
|
||||||
|
|
||||||
## v0.2.3 (2026-05-11)
|
## v0.2.3 (2026-05-11)
|
||||||
|
|
||||||
### 前端更新
|
### 前端更新
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
VERSION=v0.1.8
|
VERSION=0.2.5
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
{
|
{
|
||||||
"version": "0.2.4",
|
"version": "0.2.6",
|
||||||
"updated": "2026-05-11",
|
"updated": "2026-06-13",
|
||||||
"modules": {
|
"modules": {
|
||||||
"frontend": {
|
"frontend": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"pages": {
|
"pages": {
|
||||||
|
"Login": "0.0.2",
|
||||||
"Add": "0.0.2",
|
"Add": "0.0.2",
|
||||||
"News": "0.2.0"
|
"News": "0.1.2",
|
||||||
|
"YichensBoard": "0.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"routers": {
|
"routers": {
|
||||||
|
"auth": "0.0.2",
|
||||||
"seek": "0.2.0",
|
"seek": "0.2.0",
|
||||||
"purchase": "0.3.0"
|
"purchase": "0.3.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<title>甲辰收藏 v=0.0.9</title>
|
<title>甲辰收藏 v0.2.5</title>
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="/static/icons/favicon.png" />
|
<link rel="icon" type="image/png" href="/static/icons/favicon.png" />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Login - 登录页面
|
* Login - 登录页面
|
||||||
* Version: 0.0.1
|
* Version: 0.0.2 (2026-06-13)
|
||||||
* 更新:
|
* 更新:移除注册时的手机号和短信验证功能
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
@ -23,79 +23,22 @@ export default function Login() {
|
||||||
password: '',
|
password: '',
|
||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
email: '',
|
email: '',
|
||||||
phone: '',
|
|
||||||
verifyCode: '',
|
|
||||||
inviteCode: ''
|
inviteCode: ''
|
||||||
})
|
})
|
||||||
const [registerLoading, setRegisterLoading] = useState(false)
|
const [registerLoading, setRegisterLoading] = useState(false)
|
||||||
const [registerError, setRegisterError] = useState('')
|
const [registerError, setRegisterError] = useState('')
|
||||||
|
|
||||||
// 短信获取相关
|
|
||||||
const [sendingCode, setSendingCode] = useState(false)
|
|
||||||
const [codeCountdown, setCodeCountdown] = useState(0)
|
|
||||||
const [codeSent, setCodeSent] = useState(false)
|
|
||||||
|
|
||||||
// 生成获取
|
// 生成获取
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
generateCaptcha()
|
generateCaptcha()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// 获取倒计时
|
|
||||||
useEffect(() => {
|
|
||||||
if (codeCountdown > 0) {
|
|
||||||
const timer = setTimeout(() => setCodeCountdown(codeCountdown - 1), 1000)
|
|
||||||
return () => clearTimeout(timer)
|
|
||||||
}
|
|
||||||
}, [codeCountdown])
|
|
||||||
|
|
||||||
const generateCaptcha = () => {
|
const generateCaptcha = () => {
|
||||||
const num1 = Math.floor(Math.random() * 10)
|
const num1 = Math.floor(Math.random() * 10)
|
||||||
const num2 = Math.floor(Math.random() * 10)
|
const num2 = Math.floor(Math.random() * 10)
|
||||||
setCaptcha({ num1, num2, answer: '' })
|
setCaptcha({ num1, num2, answer: '' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送短信获取
|
|
||||||
const handleSendCode = async () => {
|
|
||||||
if (!registerData.phone) {
|
|
||||||
setRegisterError('请先输入手机号')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证手机号格式
|
|
||||||
const phoneRegex = /^1[3-9]\d{9}$/
|
|
||||||
if (!phoneRegex.test(registerData.phone)) {
|
|
||||||
setRegisterError('请输入正确的手机号')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setSendingCode(true)
|
|
||||||
setRegisterError('')
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch('/api/auth/send-verification-code', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ phone: registerData.phone })
|
|
||||||
})
|
|
||||||
|
|
||||||
const data = await res.json()
|
|
||||||
|
|
||||||
if (data.success) {
|
|
||||||
setCodeSent(true)
|
|
||||||
setCodeCountdown(60)
|
|
||||||
setRegisterError('')
|
|
||||||
} else {
|
|
||||||
setRegisterError(data.message || '发送失败')
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
setRegisterError('发送失败,请稍后重试')
|
|
||||||
} finally {
|
|
||||||
setSendingCode(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理注册
|
// 处理注册
|
||||||
const handleRegister = async () => {
|
const handleRegister = async () => {
|
||||||
// 验证输入
|
// 验证输入
|
||||||
|
|
@ -124,33 +67,13 @@ export default function Login() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证手机号
|
|
||||||
if (!registerData.phone) {
|
|
||||||
setRegisterError('手机号为必填项')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const phoneRegex = /^1[3-9]\d{9}$/
|
|
||||||
if (!phoneRegex.test(registerData.phone)) {
|
|
||||||
setRegisterError('请输入正确的手机号')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证短信获取
|
|
||||||
if (!registerData.verifyCode) {
|
|
||||||
setRegisterError('请输入短信获取')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setRegisterLoading(true)
|
setRegisterLoading(true)
|
||||||
setRegisterError('')
|
setRegisterError('')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
username: registerData.username,
|
username: registerData.username,
|
||||||
password: registerData.password,
|
password: registerData.password
|
||||||
phone: registerData.phone,
|
|
||||||
verifyCode: registerData.verifyCode
|
|
||||||
}
|
}
|
||||||
if (registerData.email) {
|
if (registerData.email) {
|
||||||
payload.email = registerData.email
|
payload.email = registerData.email
|
||||||
|
|
@ -175,9 +98,7 @@ export default function Login() {
|
||||||
|
|
||||||
alert('注册成功!请登录')
|
alert('注册成功!请登录')
|
||||||
setShowRegister(false)
|
setShowRegister(false)
|
||||||
setRegisterData({ username: '', password: '', confirmPassword: '', email: '', phone: '', verifyCode: '', inviteCode: '' })
|
setRegisterData({ username: '', password: '', confirmPassword: '', email: '', inviteCode: '' })
|
||||||
setCodeSent(false)
|
|
||||||
setCodeCountdown(0)
|
|
||||||
generateCaptcha()
|
generateCaptcha()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('注册错误:', err)
|
console.error('注册错误:', err)
|
||||||
|
|
@ -491,68 +412,6 @@ export default function Login() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 手机号 */}
|
|
||||||
<div style={{ marginBottom: '16px' }}>
|
|
||||||
<input
|
|
||||||
type="tel"
|
|
||||||
value={registerData.phone}
|
|
||||||
onChange={(e) => setRegisterData(prev => ({ ...prev, phone: e.target.value }))}
|
|
||||||
placeholder="手机号(11位)"
|
|
||||||
maxLength={11}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
padding: '14px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.2)',
|
|
||||||
background: 'rgba(255,255,255,0.05)',
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: '16px',
|
|
||||||
outline: 'none'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 短信获取 */}
|
|
||||||
<div style={{ marginBottom: '16px' }}>
|
|
||||||
<div style={{ display: 'flex', gap: '12px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={registerData.verifyCode}
|
|
||||||
onChange={(e) => setRegisterData(prev => ({ ...prev, verifyCode: e.target.value }))}
|
|
||||||
placeholder="短信验证码"
|
|
||||||
maxLength={6}
|
|
||||||
style={{
|
|
||||||
flex: 1, minWidth: "90px", width: "auto",
|
|
||||||
padding: '14px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.2)',
|
|
||||||
background: 'rgba(255,255,255,0.05)',
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: '16px',
|
|
||||||
outline: 'none'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={handleSendCode}
|
|
||||||
disabled={sendingCode || codeCountdown > 0}
|
|
||||||
style={{
|
|
||||||
minWidth: "90px", width: "auto",
|
|
||||||
padding: '14px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: 'none',
|
|
||||||
background: codeCountdown > 0 ? 'rgba(148, 163, 184, 0.3)' : 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)',
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: '14px',
|
|
||||||
fontWeight: '600',
|
|
||||||
cursor: codeCountdown > 0 ? 'not-allowed' : 'pointer',
|
|
||||||
whiteSpace: 'nowrap'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{codeCountdown > 0 ? `${codeCountdown}秒` : sendingCode ? '发送中...' : '获取验证码'}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 邮箱(可选) */}
|
{/* 邮箱(可选) */}
|
||||||
<div style={{ marginBottom: '16px' }}>
|
<div style={{ marginBottom: '16px' }}>
|
||||||
<input
|
<input
|
||||||
|
|
@ -656,10 +515,8 @@ export default function Login() {
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowRegister(false)
|
setShowRegister(false)
|
||||||
setRegisterData({ username: '', password: '', confirmPassword: '', email: '', phone: '', verifyCode: '', inviteCode: '' })
|
setRegisterData({ username: '', password: '', confirmPassword: '', email: '', inviteCode: '' })
|
||||||
setRegisterError('')
|
setRegisterError('')
|
||||||
setCodeSent(false)
|
|
||||||
setCodeCountdown(0)
|
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
flex: 1, minWidth: "90px", width: "auto",
|
flex: 1, minWidth: "90px", width: "auto",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* News - 资讯列表页面
|
* News - 资讯列表页面
|
||||||
* Version: 0.1.0 (2026-05-07)
|
* Version: 0.1.2 (2026-05-13)
|
||||||
* 更新:成交行情列表和详情弹窗列表都按成交日期(deal_date)倒序排序
|
* 更新:移除成交行情价格统计表格,增加获取数量到500
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
@ -97,7 +97,7 @@ export default function News() {
|
||||||
? `${API_BASE}/api/seek/list`
|
? `${API_BASE}/api/seek/list`
|
||||||
: `${API_BASE}/api/deal/list`
|
: `${API_BASE}/api/deal/list`
|
||||||
|
|
||||||
// 成交行情和寻配号每页500条
|
// 成交行情获取所有数据(不分页)
|
||||||
if (activeTab === 'deal') {
|
if (activeTab === 'deal') {
|
||||||
url += (url.includes('?') ? '&' : '?') + 'page_size=500'
|
url += (url.includes('?') ? '&' : '?') + 'page_size=500'
|
||||||
if (dealDate) {
|
if (dealDate) {
|
||||||
|
|
@ -660,60 +660,6 @@ export default function News() {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ overflowX: 'auto' }}>
|
|
||||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '13px' }}>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style={{ padding: '8px', textAlign: 'left', color: '#94a3b8', borderBottom: '1px solid rgba(255,255,255,0.1)' }}></th>
|
|
||||||
{packagings.map(p => (
|
|
||||||
<th key={p} style={{ padding: '8px', textAlign: 'center', color: '#94a3b8', borderBottom: '1px solid rgba(255,255,255,0.1)' }}>{p}</th>
|
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{(() => {
|
|
||||||
// 计算每个分类的平均价格
|
|
||||||
const catAvg = categories.map(cat => {
|
|
||||||
const prices = []
|
|
||||||
packagings.forEach(pkg => {
|
|
||||||
const d = calcAvg(pkg, cat)
|
|
||||||
if (d) prices.push(d.avg)
|
|
||||||
})
|
|
||||||
const avg = prices.length > 0 ? Math.round(prices.reduce((a,b) => a+b, 0) / prices.length) : 0
|
|
||||||
return { cat, avg }
|
|
||||||
}).filter(c => c.avg > 0)
|
|
||||||
// 分类名称标准化并按固定顺序排序
|
|
||||||
catAvg.sort((a, b) => a.avg - b.avg)
|
|
||||||
const categoryOrder = ['带4号', '带7号', '永恒号', '天马号', '天马王', '金山号', '金山王', '钻石号', '朦胧号', '朦胧王', '金马号', '金马王', '倒置号', '圆圆号']
|
|
||||||
const sortedCats = categoryOrder.filter(cat => catAvg.some(c => c.cat === cat))
|
|
||||||
.concat(catAvg.filter(c => !categoryOrder.includes(c.cat)).map(c => c.cat))
|
|
||||||
|
|
||||||
return sortedCats.map(cat => {
|
|
||||||
const rowData = packagings.map(pkg => calcAvg(pkg, cat))
|
|
||||||
const hasData = rowData.some(d => d !== null)
|
|
||||||
if (!hasData) return null
|
|
||||||
return (
|
|
||||||
<tr key={cat}>
|
|
||||||
<td style={{ padding: '8px', color: '#fbbf24', fontWeight: '500', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>{cat}</td>
|
|
||||||
{rowData.map((d, i) => (
|
|
||||||
<td key={i} style={{ padding: '8px', textAlign: 'center', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
|
|
||||||
{d ? (
|
|
||||||
<div style={{ color: '#22c55e', fontWeight: '600', cursor: 'pointer' }}
|
|
||||||
onClick={() => setDealDetailItems(d.items)}>
|
|
||||||
¥{d.avg.toLocaleString()}
|
|
||||||
<span style={{ color: '#64748b', fontSize: '11px', marginLeft: '4px' }}>({d.count})</span>
|
|
||||||
</div>
|
|
||||||
) : <span style={{ color: '#475569' }}>-</span>}
|
|
||||||
</td>
|
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})()}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* YichensBoard - 一尘看板页面
|
* YichensBoard - 一尘看板页面
|
||||||
* Version: 0.0.3
|
* Version: 0.0.5 (2026-05-13)
|
||||||
* 更新:
|
* 更新:增加复制链接功能
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
|
|
@ -265,7 +265,12 @@ export default function YichensBoard() {
|
||||||
<div style={{ color: '#e2e8f0', fontSize: 13, lineHeight: 1.6, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 300, overflowY: 'auto' }}>
|
<div style={{ color: '#e2e8f0', fontSize: 13, lineHeight: 1.6, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 300, overflowY: 'auto' }}>
|
||||||
{post.content}
|
{post.content}
|
||||||
</div>
|
</div>
|
||||||
{post.url && <a href={post.url} target='_blank' rel='noopener noreferrer' style={{ display:'inline-block', marginTop:12, padding:'8px 16px', background:'rgba(59,130,246,0.2)', borderRadius:8, color:'#60a5fa', textDecoration:'none', fontSize:13 }}>查看原帖</a>}
|
{post.url && (
|
||||||
|
<div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
|
||||||
|
<a href={post.url} target='_blank' rel='noopener noreferrer' style={{ padding:'8px 16px', background:'rgba(59,130,246,0.2)', borderRadius:8, color:'#60a5fa', textDecoration:'none', fontSize:13 }}>查看原帖</a>
|
||||||
|
<button onClick={() => { navigator.clipboard.writeText(post.url); alert('链接已复制!'); }} style={{ padding:'8px 16px', background:'rgba(34,197,94,0.2)', borderRadius:8, color:'#22c55e', border:'none', cursor:'pointer', fontSize:13 }}>复制链接</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue