import React, {Component, PureComponent} from 'react'; import {SafeTextarea} from './Common'; import './UserAction.css'; import {API_BASE} from './Common'; const LOGIN_BASE=window.location.protocol==='https:' ? '/login_proxy' : 'http://www.pkuhelper.com/services/login'; const MAX_IMG_PX=1000; const MAX_IMG_FILESIZE=100000; export const TokenCtx=React.createContext({ value: null, set_value: ()=>{}, }); export class LoginForm extends Component { constructor(props) { super(props); this.state={ loading_status: 'done', }; this.username_ref=React.createRef(); this.password_ref=React.createRef(); } do_login(event,set_token) { event.preventDefault(); if(this.state.loading_status==='loading') return; this.setState({ loading_status: 'loading', }); let data=new URLSearchParams(); data.append('uid', this.username_ref.current.value); data.append('password', this.password_ref.current.value); fetch(LOGIN_BASE+'/login.php?platform=hole_xmcp_ml', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } set_token(json.token); alert(`成功以 ${json.name} 的身份登录`); this.setState({ loading_status: 'done', }); }) .catch((e)=>{ alert('登录失败'); this.setState({ loading_status: 'done', }); console.error(e); }); } render() { return ( {(token)=>
this.do_login(e,token.set_value)}>

{token.value ? 您已登录。Token: {token.value||'(null)'} : '登录后可以使用关注、回复等功能' }

{this.state.loading_status==='loading' ? : }

  • 我们不会记录您的密码和个人信息
  • 请勿泄露 Token,它代表您的登录状态,与您的账户唯一对应且泄露后无法重置
  • 如果您不愿输入密码,可以直接修改 localStorage['TOKEN']
}
) } } export class ReplyForm extends Component { constructor(props) { super(props); this.state={ text: '', loading_status: 'done', }; this.on_change_bound=this.on_change.bind(this); this.area_ref=React.createRef(); } on_change(value) { this.setState({ text: value, }); } on_submit(event) { event.preventDefault(); if(this.state.loading_status==='loading') return; this.setState({ loading_status: 'loading', }); let data=new URLSearchParams(); data.append('action','docomment'); data.append('pid',this.props.pid); data.append('text',this.state.text); data.append('token',this.props.token); fetch(API_BASE+'/api.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } this.setState({ loading_status: 'done', text: '', }); this.area_ref.current.clear(); this.props.on_complete(); }) .catch((e)=>{ console.error(e); alert('回复失败\n(树洞服务器经常抽风,其实有可能已经回复上了,不妨点“刷新回复”看一看)'); this.setState({ loading_status: 'done', }); }); } render() { return (
{this.state.loading_status==='loading' ? : } ) } } export class PostForm extends Component { constructor(props) { super(props); this.state={ text: '', loading_status: 'done', }; this.img_ref=React.createRef(); this.area_ref=React.createRef(); this.on_change_bound=this.on_change.bind(this); } on_change(value) { this.setState({ text: value, }); } do_post(text,img) { let data=new URLSearchParams(); data.append('action','dopost'); data.append('text',this.state.text); data.append('type',img ? 'image' : 'text'); data.append('token',this.props.token); if(img) data.append('data',img); fetch(API_BASE+'/api.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: data, }) .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { if(json.msg) alert(json.msg); throw new Error(json); } this.setState({ loading_status: 'done', text: '', }); this.area_ref.current.clear(); this.props.on_complete(); }) .catch((e)=>{ console.error(e); alert('发表失败'); this.setState({ loading_status: 'done', }); }); } proc_img(file) { // http://pkuhole.chenpong.com/ return new Promise((resolve,reject)=>{ function return_url(url) { const idx=url.indexOf(';base64,'); if(idx===-1) throw new Error('img not base64 encoded'); resolve(url.substr(idx+8)); } let reader=new FileReader(); reader.onload=((event)=>{ // check size const url=event.target.result; const image = new Image(); image.src=url; image.onload=(()=>{ let width=image.width; let height=image.height; if(width>MAX_IMG_PX) { height=height*MAX_IMG_PX/width; width=MAX_IMG_PX; } if(height>MAX_IMG_PX) { width=width*MAX_IMG_PX/height; height=MAX_IMG_PX; } let canvas=document.createElement('canvas'); let ctx=canvas.getContext('2d'); canvas.width=width; canvas.height=height; ctx.drawImage(image,0,0,width,height); for(let quality=.9;quality>0;quality-=0.1) { const url=canvas.toDataURL('image/jpeg',quality); console.log('quality',quality,'size',url.length); if(url.length<=MAX_IMG_FILESIZE) { console.log('chosen img quality',quality); return return_url(url); } } // else alert('图片过大,无法上传'); reject('img too large'); }); }); reader.readAsDataURL(file); }); } on_submit(event) { event.preventDefault(); if(this.state.loading_status==='loading') return; if(this.img_ref.current.files.length) { this.setState({ loading_status: 'processing', }); this.proc_img(this.img_ref.current.files[0]) .then((img)=>{ this.setState({ loading_status: 'loading', }); this.do_post(this.state.text,img); }) } else { this.setState({ loading_status: 'loading', }); this.do_post(this.state.text,null); } } render() { return (
{this.state.loading_status!=='done' ? : }
) } }