thuhole update
@@ -3,19 +3,19 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" href="%PUBLIC_URL%/static/favicon/256.png">
|
<link rel="icon" href="%PUBLIC_URL%/static/favicon/512.png">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
|
||||||
<link rel="stylesheet" href="%PUBLIC_URL%/static/fonts_7/icomoon.css" />
|
<link rel="stylesheet" href="%PUBLIC_URL%/static/fonts_7/icomoon.css" />
|
||||||
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<link rel="shortcut icon" href="%PUBLIC_URL%/static/favicon/256.png">
|
<link rel="shortcut icon" href="%PUBLIC_URL%/static/favicon/512.png">
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/static/manifest.json">
|
<link rel="manifest" href="%PUBLIC_URL%/static/manifest.json">
|
||||||
<meta name="theme-color" content="#333333"/>
|
<meta name="theme-color" content="#333333"/>
|
||||||
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/static/favicon/180.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/static/favicon/180.png" />
|
||||||
<link rel="apple-touch-icon" sizes="256x256" href="%PUBLIC_URL%/static/favicon/256.png" />
|
<link rel="apple-touch-icon" sizes="512x512" href="%PUBLIC_URL%/static/favicon/512.png" />
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||||
<meta name="apple-mobile-web-app-title" content="树洞">
|
<meta name="apple-mobile-web-app-title" content="树洞">
|
||||||
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/750x1334.png" media="(device-width: 375px) and (-webkit-device-pixel-ratio: 2)"/>
|
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/750x1334.png" media="(device-width: 375px) and (-webkit-device-pixel-ratio: 2)"/>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/1668x2388.png" media="(device-width: 834px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"/>
|
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/1668x2388.png" media="(device-width: 834px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"/>
|
||||||
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/2388x1668.png" media="(device-width: 834px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"/>
|
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/static/splash/2388x1668.png" media="(device-width: 834px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"/>
|
||||||
|
|
||||||
<title>P大树洞</title>
|
<title>T大树洞</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
BIN
public/static/bg/cyberpunk.jpg
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 17 KiB |
BIN
public/static/favicon/512.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"short_name": "树洞",
|
"short_name": "树洞",
|
||||||
"name": "P大树洞",
|
"name": "T大树洞",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon/256.png",
|
"src": "favicon/512.png",
|
||||||
"sizes": "256x256",
|
"sizes": "512x512",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
var _czc=_czc||[];
|
// var _czc=_czc||[];
|
||||||
_czc.push(["_setAccount","1274501752"]);
|
// _czc.push(["_setAccount","1274501752"]);
|
||||||
_czc.push(["_setCustomVar","has_token",localStorage['TOKEN']?'yes':'no',1]);
|
// _czc.push(["_setCustomVar","has_token",localStorage['TOKEN']?'yes':'no',1]);
|
||||||
_czc.push(["_setCustomVar","standalone",((window.matchMedia('(display-mode: standalone)').matches) || (window.navigator.standalone))?'yes':'no',1]);
|
// _czc.push(["_setCustomVar","standalone",((window.matchMedia('(display-mode: standalone)').matches) || (window.navigator.standalone))?'yes':'no',1]);
|
||||||
_czc.push(["_setCustomVar","build_info","%REACT_APP_BUILD_INFO%"||'---']);
|
// _czc.push(["_setCustomVar","build_info","%REACT_APP_BUILD_INFO%"||'---']);
|
||||||
var cr_version=/Chrome\/(\d+)/.exec(navigator.userAgent);
|
// var cr_version=/Chrome\/(\d+)/.exec(navigator.userAgent);
|
||||||
_czc.push(["_setCustomVar","cr_version_test",cr_version?cr_version[1]:'[null]',2]);
|
// _czc.push(["_setCustomVar","cr_version_test",cr_version?cr_version[1]:'[null]',2]);
|
||||||
/*
|
// /*
|
||||||
// track config
|
// // track config
|
||||||
try {
|
// try {
|
||||||
var config=JSON.parse(localStorage['hole_config']||'{}');
|
// var config=JSON.parse(localStorage['hole_config']||'{}');
|
||||||
for(var key in config)
|
// for(var key in config)
|
||||||
if(config.hasOwnProperty(key))
|
// if(config.hasOwnProperty(key))
|
||||||
_czc.push(["_trackEvent",'config',key,encodeURIComponent(JSON.stringify(config[key])),0,'']);
|
// _czc.push(["_trackEvent",'config',key,encodeURIComponent(JSON.stringify(config[key])),0,'']);
|
||||||
//_czc.push(["_setCustomVar","config_"+key,encodeURIComponent(JSON.stringify(config[key])),0]);
|
// //_czc.push(["_setCustomVar","config_"+key,encodeURIComponent(JSON.stringify(config[key])),0]);
|
||||||
} catch(e) {
|
// } catch(e) {
|
||||||
console.trace(e);
|
// console.trace(e);
|
||||||
}
|
// }
|
||||||
*/
|
// */
|
||||||
var cnzz_s_tag = document.createElement('script');
|
// var cnzz_s_tag = document.createElement('script');
|
||||||
cnzz_s_tag.type = 'text/javascript';
|
// cnzz_s_tag.type = 'text/javascript';
|
||||||
cnzz_s_tag.async = true;
|
// cnzz_s_tag.async = true;
|
||||||
cnzz_s_tag.charset = "utf-8";
|
// cnzz_s_tag.charset = "utf-8";
|
||||||
cnzz_s_tag.src = "https://w.cnzz.com/c.php?id=1274501752&async=1";
|
// cnzz_s_tag.src = "https://w.cnzz.com/c.php?id=1274501752&async=1";
|
||||||
document.head.appendChild(cnzz_s_tag);
|
// document.head.appendChild(cnzz_s_tag);
|
||||||
@@ -106,14 +106,14 @@ class App extends Component {
|
|||||||
<LoginPopup token_callback={token.set_value}>{(do_popup)=>(
|
<LoginPopup token_callback={token.set_value}>{(do_popup)=>(
|
||||||
<a onClick={do_popup}>
|
<a onClick={do_popup}>
|
||||||
<span className="icon icon-login" />
|
<span className="icon icon-login" />
|
||||||
登录到 PKU Helper
|
登录到 T大树洞
|
||||||
</a>
|
</a>
|
||||||
)}</LoginPopup>
|
)}</LoginPopup>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{this.inpku_flag||token.value ?
|
{this.inpku_flag||token.value||true ?
|
||||||
<Flow key={this.state.flow_render_key} show_sidebar={this.show_sidebar_bound}
|
<Flow key={this.state.flow_render_key} show_sidebar={this.show_sidebar_bound}
|
||||||
mode={this.state.mode} search_text={this.state.search_text} token={token.value}
|
mode={this.state.mode} search_text={this.state.search_text} token={token.value}
|
||||||
/> :
|
/> :
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React, {Component, PureComponent} from 'react';
|
import React, {Component, PureComponent} from 'react';
|
||||||
import {format_time,Time,TitleLine} from './infrastructure/widgets';
|
import {format_time,Time,TitleLine} from './infrastructure/widgets';
|
||||||
import {PKUHELPER_ROOT} from './flows_api';
|
import {THUHOLE_API_ROOT} from './flows_api';
|
||||||
|
|
||||||
import './Common.css';
|
import './Common.css';
|
||||||
|
|
||||||
export {format_time,Time,TitleLine};
|
export {format_time,Time,TitleLine};
|
||||||
|
|
||||||
export const API_BASE=PKUHELPER_ROOT+'services/pkuhole';
|
export const API_BASE=THUHOLE_API_ROOT+'services/thuhole';
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||||
function escape_regex(string) {
|
function escape_regex(string) {
|
||||||
@@ -37,9 +37,9 @@ export class HighlightedText extends PureComponent {
|
|||||||
let [rule,p]=part;
|
let [rule,p]=part;
|
||||||
return (
|
return (
|
||||||
<span key={idx}>{
|
<span key={idx}>{
|
||||||
rule==='url_pid' ? <span className="url-pid-link" title={p}>/hole/##</span> :
|
rule==='url_pid' ? <span className="url-pid-link" title={p}>/##</span> :
|
||||||
rule==='url' ? <a href={normalize_url(p)} target="_blank" rel="noopener">{p}</a> :
|
rule==='url' ? <a href={normalize_url(p)} target="_blank" rel="noopener">{p}</a> :
|
||||||
rule==='pid' ? <a href={'##'+p} onClick={(e)=>{e.preventDefault(); this.props.show_pid(p);}}>{p}</a> :
|
rule==='pid' ? <a href={'#'+p} onClick={(e)=>{e.preventDefault(); this.props.show_pid(p.substring(1));}}>{p}</a> :
|
||||||
rule==='nickname' ? <ColoredSpan colors={this.props.color_picker.get(p)}>{p}</ColoredSpan> :
|
rule==='nickname' ? <ColoredSpan colors={this.props.color_picker.get(p)}>{p}</ColoredSpan> :
|
||||||
rule==='search' ? <span className="search-query-highlight">{p}</span> :
|
rule==='search' ? <span className="search-query-highlight">{p}</span> :
|
||||||
p
|
p
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const BUILTIN_IMGS={
|
|||||||
'static/bg/eriri.jpg': '平成著名画师',
|
'static/bg/eriri.jpg': '平成著名画师',
|
||||||
'static/bg/yurucamp.jpg': '露营天下第一',
|
'static/bg/yurucamp.jpg': '露营天下第一',
|
||||||
'static/bg/minecraft.jpg': '麦恩·库拉夫特',
|
'static/bg/minecraft.jpg': '麦恩·库拉夫特',
|
||||||
|
'static/bg/cyberpunk.jpg': '赛博城市',
|
||||||
'static/bg/sif.jpg': '梦开始的地方',
|
'static/bg/sif.jpg': '梦开始的地方',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,7 +239,7 @@ export class ConfigUI extends PureComponent {
|
|||||||
<hr />
|
<hr />
|
||||||
<p>
|
<p>
|
||||||
新功能建议或问题反馈请在
|
新功能建议或问题反馈请在
|
||||||
<a href="https://github.com/pkuhelper-web/webhole/issues" target="_blank">GitHub <span className="icon icon-github" /></a>
|
<a href="https://github.com/thuhole/webhole/issues" target="_blank">GitHub <span className="icon icon-github" /></a>
|
||||||
提出。
|
提出。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
15
src/Flows.js
@@ -8,14 +8,15 @@ import LazyLoad from './react-lazyload/src';
|
|||||||
import {AudioWidget} from './AudioWidget';
|
import {AudioWidget} from './AudioWidget';
|
||||||
import {TokenCtx, ReplyForm} from './UserAction';
|
import {TokenCtx, ReplyForm} from './UserAction';
|
||||||
|
|
||||||
import {API, PKUHELPER_ROOT} from './flows_api';
|
import {API, THUHOLE_API_ROOT} from './flows_api';
|
||||||
|
|
||||||
const IMAGE_BASE=PKUHELPER_ROOT+'services/pkuhole/images/';
|
const IMAGE_BASE=THUHOLE_API_ROOT+'services/thuhole/images/';
|
||||||
const AUDIO_BASE=PKUHELPER_ROOT+'services/pkuhole/audios/';
|
const AUDIO_BASE=THUHOLE_API_ROOT+'services/thuhole/audios/';
|
||||||
|
|
||||||
const CLICKABLE_TAGS={a: true, audio: true};
|
const CLICKABLE_TAGS={a: true, audio: true};
|
||||||
const PREVIEW_REPLY_COUNT=10;
|
const PREVIEW_REPLY_COUNT=10;
|
||||||
const QUOTE_BLACKLIST=['23333','233333','66666','666666','10086','10000','100000','99999','999999','55555','555555'];
|
// const QUOTE_BLACKLIST=['23333','233333','66666','666666','10086','10000','100000','99999','999999','55555','555555'];
|
||||||
|
const QUOTE_BLACKLIST=[];
|
||||||
|
|
||||||
window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0;
|
window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0;
|
||||||
|
|
||||||
@@ -521,7 +522,8 @@ class FlowItemRow extends PureComponent {
|
|||||||
|
|
||||||
let quote_id=null;
|
let quote_id=null;
|
||||||
if(!this.props.is_quote)
|
if(!this.props.is_quote)
|
||||||
for(let [mode,content] of parts)
|
for(let [mode,content] of parts) {
|
||||||
|
content = content.length > 0 ? content.substring(1) : content
|
||||||
if(mode==='pid' && QUOTE_BLACKLIST.indexOf(content)===-1 && parseInt(content)<parseInt(this.state.info.pid))
|
if(mode==='pid' && QUOTE_BLACKLIST.indexOf(content)===-1 && parseInt(content)<parseInt(this.state.info.pid))
|
||||||
if(quote_id===null)
|
if(quote_id===null)
|
||||||
quote_id=parseInt(content);
|
quote_id=parseInt(content);
|
||||||
@@ -529,6 +531,7 @@ class FlowItemRow extends PureComponent {
|
|||||||
quote_id=null;
|
quote_id=null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let res=(
|
let res=(
|
||||||
<div className={'flow-item-row flow-item-row-with-prompt'+(this.props.is_quote ? ' flow-item-row-quote' : '')} onClick={(event)=>{
|
<div className={'flow-item-row flow-item-row-with-prompt'+(this.props.is_quote ? ' flow-item-row-quote' : '')} onClick={(event)=>{
|
||||||
@@ -809,7 +812,7 @@ export class Flow extends PureComponent {
|
|||||||
<TitleLine text={
|
<TitleLine text={
|
||||||
this.state.loading_status==='loading' ?
|
this.state.loading_status==='loading' ?
|
||||||
<span><span className="icon icon-loading" /> Loading...</span> :
|
<span><span className="icon icon-loading" /> Loading...</span> :
|
||||||
'© xmcp'
|
'© thuhole'
|
||||||
} />
|
} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, {Component, PureComponent} from 'react';
|
import React, {Component, PureComponent} from 'react';
|
||||||
import {PKUHELPER_ROOT, get_json, API_VERSION_PARAM} from './flows_api';
|
import {THUHOLE_API_ROOT, get_json, API_VERSION_PARAM} from './flows_api';
|
||||||
import {Time} from './Common';
|
import {Time} from './Common';
|
||||||
|
|
||||||
export class MessageViewer extends PureComponent {
|
export class MessageViewer extends PureComponent {
|
||||||
@@ -20,7 +20,7 @@ export class MessageViewer extends PureComponent {
|
|||||||
this.setState({
|
this.setState({
|
||||||
loading_status: 'loading',
|
loading_status: 'loading',
|
||||||
},()=>{
|
},()=>{
|
||||||
fetch(PKUHELPER_ROOT+'api_xmcp/hole/system_msg?user_token='+encodeURIComponent(this.props.token)+API_VERSION_PARAM())
|
fetch(THUHOLE_API_ROOT+'api_xmcp/hole/system_msg?user_token='+encodeURIComponent(this.props.token)+API_VERSION_PARAM())
|
||||||
.then(get_json)
|
.then(get_json)
|
||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
if(json.error)
|
if(json.error)
|
||||||
|
|||||||
10
src/Title.js
@@ -1,5 +1,5 @@
|
|||||||
import React, {Component, PureComponent} from 'react';
|
import React, {Component, PureComponent} from 'react';
|
||||||
import {AppSwitcher} from './infrastructure/widgets';
|
// import {AppSwitcher} from './infrastructure/widgets';
|
||||||
import {InfoSidebar, PostForm} from './UserAction';
|
import {InfoSidebar, PostForm} from './UserAction';
|
||||||
import {TokenCtx} from './UserAction';
|
import {TokenCtx} from './UserAction';
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class ControlBar extends PureComponent {
|
|||||||
/>
|
/>
|
||||||
<a className="no-underline control-btn" onClick={()=>{
|
<a className="no-underline control-btn" onClick={()=>{
|
||||||
this.props.show_sidebar(
|
this.props.show_sidebar(
|
||||||
'P大树洞',
|
'T大树洞',
|
||||||
<InfoSidebar show_sidebar={this.props.show_sidebar} />
|
<InfoSidebar show_sidebar={this.props.show_sidebar} />
|
||||||
)
|
)
|
||||||
}}>
|
}}>
|
||||||
@@ -124,15 +124,15 @@ class ControlBar extends PureComponent {
|
|||||||
export function Title(props) {
|
export function Title(props) {
|
||||||
return (
|
return (
|
||||||
<div className="title-bar">
|
<div className="title-bar">
|
||||||
<AppSwitcher appid="hole" />
|
{/* <AppSwitcher appid="hole" /> */}
|
||||||
<div className="aux-margin">
|
<div className="aux-margin">
|
||||||
<div className="title">
|
<div className="title">
|
||||||
<p className="centered-line">
|
<p className="centered-line">
|
||||||
<span onClick={()=>props.show_sidebar(
|
<span onClick={()=>props.show_sidebar(
|
||||||
'P大树洞',
|
'T大树洞',
|
||||||
<InfoSidebar show_sidebar={props.show_sidebar} />
|
<InfoSidebar show_sidebar={props.show_sidebar} />
|
||||||
)}>
|
)}>
|
||||||
P大树洞
|
T大树洞
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {ConfigUI} from './Config';
|
|||||||
import fixOrientation from 'fix-orientation';
|
import fixOrientation from 'fix-orientation';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import {cache} from './cache';
|
import {cache} from './cache';
|
||||||
import {API_VERSION_PARAM, PKUHELPER_ROOT, API, get_json, token_param} from './flows_api';
|
import {API_VERSION_PARAM, THUHOLE_API_ROOT, API, get_json, token_param} from './flows_api';
|
||||||
|
|
||||||
import './UserAction.css';
|
import './UserAction.css';
|
||||||
|
|
||||||
@@ -20,179 +20,179 @@ export const TokenCtx=React.createContext({
|
|||||||
set_value: ()=>{},
|
set_value: ()=>{},
|
||||||
});
|
});
|
||||||
|
|
||||||
class LifeInfoBox extends Component {
|
// class LifeInfoBox extends Component {
|
||||||
constructor(props) {
|
// constructor(props) {
|
||||||
super(props);
|
// super(props);
|
||||||
if(!window._life_info_cache)
|
// if(!window._life_info_cache)
|
||||||
window._life_info_cache={};
|
// window._life_info_cache={};
|
||||||
this.CACHE_TIMEOUT_S=15;
|
// this.CACHE_TIMEOUT_S=15;
|
||||||
this.state={
|
// this.state={
|
||||||
today_info: this.cache_get('today_info'),
|
// today_info: this.cache_get('today_info'),
|
||||||
card_balance: this.cache_get('card_balance'),
|
// card_balance: this.cache_get('card_balance'),
|
||||||
net_balance: this.cache_get('net_balance'),
|
// net_balance: this.cache_get('net_balance'),
|
||||||
mail_count: this.cache_get('mail_count'),
|
// mail_count: this.cache_get('mail_count'),
|
||||||
};
|
// };
|
||||||
this.INTERNAL_NETWORK_FAILURE='_network_failure';
|
// this.INTERNAL_NETWORK_FAILURE='_network_failure';
|
||||||
this.API_NAME={
|
// this.API_NAME={
|
||||||
today_info: 'hole/today_info',
|
// today_info: 'hole/today_info',
|
||||||
card_balance: 'isop/card_balance',
|
// card_balance: 'isop/card_balance',
|
||||||
net_balance: 'isop/net_balance',
|
// net_balance: 'isop/net_balance',
|
||||||
mail_count: 'isop/mail_count',
|
// mail_count: 'isop/mail_count',
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
cache_get(key) {
|
// cache_get(key) {
|
||||||
let cache_item=window._life_info_cache[key];
|
// let cache_item=window._life_info_cache[key];
|
||||||
if(!cache_item || (+new Date())-cache_item[0]>1000*this.CACHE_TIMEOUT_S)
|
// if(!cache_item || (+new Date())-cache_item[0]>1000*this.CACHE_TIMEOUT_S)
|
||||||
return null;
|
// return null;
|
||||||
else
|
// else
|
||||||
return cache_item[1];
|
// return cache_item[1];
|
||||||
}
|
// }
|
||||||
cache_set(key,value) {
|
// cache_set(key,value) {
|
||||||
if(!window._life_info_cache[key] || window._life_info_cache[key][1]!==value)
|
// if(!window._life_info_cache[key] || window._life_info_cache[key][1]!==value)
|
||||||
window._life_info_cache[key]=[+new Date(),value];
|
// window._life_info_cache[key]=[+new Date(),value];
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
load(state_key) {
|
// load(state_key) {
|
||||||
this.setState({
|
// this.setState({
|
||||||
[state_key]: null,
|
// [state_key]: null,
|
||||||
},()=>{
|
// },()=>{
|
||||||
fetch(
|
// fetch(
|
||||||
PKUHELPER_ROOT+'api_xmcp/'+this.API_NAME[state_key]
|
// PKUHELPER_ROOT+'api_xmcp/'+this.API_NAME[state_key]
|
||||||
+'?user_token='+encodeURIComponent(this.props.token)
|
// +'?user_token='+encodeURIComponent(this.props.token)
|
||||||
+API_VERSION_PARAM()
|
// +API_VERSION_PARAM()
|
||||||
)
|
// )
|
||||||
.then(get_json)
|
// .then(get_json)
|
||||||
.then((json)=>{
|
// .then((json)=>{
|
||||||
//console.log(json);
|
// //console.log(json);
|
||||||
this.setState({
|
// this.setState({
|
||||||
[state_key]: json,
|
// [state_key]: json,
|
||||||
});
|
// });
|
||||||
})
|
// })
|
||||||
.catch((e)=>{
|
// .catch((e)=>{
|
||||||
this.setState({
|
// this.setState({
|
||||||
[state_key]: {
|
// [state_key]: {
|
||||||
errMsg: '网络错误 '+e,
|
// errMsg: '网络错误 '+e,
|
||||||
errCode: this.INTERNAL_NETWORK_FAILURE,
|
// errCode: this.INTERNAL_NETWORK_FAILURE,
|
||||||
success: false,
|
// success: false,
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
})
|
// })
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
componentDidMount() {
|
// componentDidMount() {
|
||||||
['today_info','card_balance','net_balance','mail_count'].forEach((k)=>{
|
// ['today_info','card_balance','net_balance','mail_count'].forEach((k)=>{
|
||||||
if(!this.state[k])
|
// if(!this.state[k])
|
||||||
this.load(k);
|
// this.load(k);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
reload_all() {
|
// reload_all() {
|
||||||
['today_info','card_balance','net_balance','mail_count'].forEach((k)=>{
|
// ['today_info','card_balance','net_balance','mail_count'].forEach((k)=>{
|
||||||
this.load(k);
|
// this.load(k);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
render_line(state_key,title,value_fn,action,url_fn,do_login) {
|
// render_line(state_key,title,value_fn,action,url_fn,do_login) {
|
||||||
let s=this.state[state_key];
|
// let s=this.state[state_key];
|
||||||
if(!s)
|
// if(!s)
|
||||||
return (
|
// return (
|
||||||
<tr>
|
// <tr>
|
||||||
<td>{title}</td>
|
// <td>{title}</td>
|
||||||
<td>加载中……</td>
|
// <td>加载中……</td>
|
||||||
<td />
|
// <td />
|
||||||
</tr>
|
// </tr>
|
||||||
);
|
// );
|
||||||
else if(!s.success) {
|
// else if(!s.success) {
|
||||||
let type='加载失败';
|
// let type='加载失败';
|
||||||
if(s.errCode===this.INTERNAL_NETWORK_FAILURE)
|
// if(s.errCode===this.INTERNAL_NETWORK_FAILURE)
|
||||||
type='网络错误';
|
// type='网络错误';
|
||||||
else if(['E01','E02','E03'].indexOf(s.errCode)!==-1)
|
// else if(['E01','E02','E03'].indexOf(s.errCode)!==-1)
|
||||||
type='授权失效';
|
// type='授权失效';
|
||||||
|
//
|
||||||
let details=JSON.stringify(s);
|
// let details=JSON.stringify(s);
|
||||||
if(s.errMsg)
|
// if(s.errMsg)
|
||||||
details=s.errMsg;
|
// details=s.errMsg;
|
||||||
else if(s.error)
|
// else if(s.error)
|
||||||
details=s.error;
|
// details=s.error;
|
||||||
|
//
|
||||||
return (
|
// return (
|
||||||
<tr>
|
// <tr>
|
||||||
<td>{title}</td>
|
// <td>{title}</td>
|
||||||
<td className="life-info-error">
|
// <td className="life-info-error">
|
||||||
<a onClick={()=>alert(details)}>{type}</a>
|
// <a onClick={()=>alert(details)}>{type}</a>
|
||||||
</td>
|
// </td>
|
||||||
<td>
|
// <td>
|
||||||
{type==='授权失效' ?
|
// {type==='授权失效' ?
|
||||||
<a onClick={do_login}>
|
// <a onClick={do_login}>
|
||||||
<span className="icon icon-forward" /> 重新登录
|
// <span className="icon icon-forward" /> 重新登录
|
||||||
</a> :
|
// </a> :
|
||||||
<a onClick={()=>this.load(state_key)}>
|
// <a onClick={()=>this.load(state_key)}>
|
||||||
<span className="icon icon-forward" /> 重试
|
// <span className="icon icon-forward" /> 重试
|
||||||
</a>
|
// </a>
|
||||||
}
|
// }
|
||||||
</td>
|
// </td>
|
||||||
</tr>
|
// </tr>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
this.cache_set(state_key,s);
|
// this.cache_set(state_key,s);
|
||||||
|
//
|
||||||
return (
|
// return (
|
||||||
<tr>
|
// <tr>
|
||||||
<td>{title}</td>
|
// <td>{title}</td>
|
||||||
<td>{value_fn(s)}</td>
|
// <td>{value_fn(s)}</td>
|
||||||
<td>
|
// <td>
|
||||||
<a href={url_fn(s)} target="_blank">
|
// <a href={url_fn(s)} target="_blank">
|
||||||
<span className="icon icon-forward" /> {action}
|
// <span className="icon icon-forward" /> {action}
|
||||||
</a>
|
// </a>
|
||||||
</td>
|
// </td>
|
||||||
</tr>
|
// </tr>
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
render() {
|
// render() {
|
||||||
return (
|
// return (
|
||||||
<LoginPopup token_callback={(t)=>{
|
// <LoginPopup token_callback={(t)=>{
|
||||||
this.props.set_token(t);
|
// this.props.set_token(t);
|
||||||
this.reload_all();
|
// this.reload_all();
|
||||||
}}>{(do_login)=>(
|
// }}>{(do_login)=>(
|
||||||
<div className="box">
|
// <div className="box">
|
||||||
<table className="life-info-table">
|
// <table className="life-info-table">
|
||||||
<tbody>
|
// <tbody>
|
||||||
{this.render_line(
|
// {this.render_line(
|
||||||
'today_info',
|
// 'today_info',
|
||||||
'今日',(s)=>s.info,
|
// '今日',(s)=>s.info,
|
||||||
'校历',(s)=>s.schedule_url,
|
// '校历',(s)=>s.schedule_url,
|
||||||
do_login,
|
// do_login,
|
||||||
)}
|
// )}
|
||||||
{this.render_line(
|
// {this.render_line(
|
||||||
'card_balance',
|
// 'card_balance',
|
||||||
'校园卡',(s)=>`余额¥${s.balance.toFixed(2)}`,
|
// '校园卡',(s)=>`余额¥${s.balance.toFixed(2)}`,
|
||||||
'充值',()=>'https://virtualprod.alipay.com/educate/educatePcRecharge.htm?schoolCode=PKU&schoolName=',
|
// '充值',()=>'https://virtualprod.alipay.com/educate/educatePcRecharge.htm?schoolCode=PKU&schoolName=',
|
||||||
do_login,
|
// do_login,
|
||||||
)}
|
// )}
|
||||||
{this.render_line(
|
// {this.render_line(
|
||||||
'net_balance',
|
// 'net_balance',
|
||||||
'网费',(s)=>`余额¥${s.balance.toFixed(2)}`,
|
// '网费',(s)=>`余额¥${s.balance.toFixed(2)}`,
|
||||||
'充值',()=>'https://its.pku.edu.cn/epay.jsp',
|
// '充值',()=>'https://its.pku.edu.cn/epay.jsp',
|
||||||
do_login,
|
// do_login,
|
||||||
)}
|
// )}
|
||||||
{this.render_line(
|
// {this.render_line(
|
||||||
'mail_count',
|
// 'mail_count',
|
||||||
'邮件',(s)=>`未读 ${s.count} 封`,
|
// '邮件',(s)=>`未读 ${s.count} 封`,
|
||||||
'查看',()=>'https://mail.pku.edu.cn/',
|
// '查看',()=>'https://mail.pku.edu.cn/',
|
||||||
do_login,
|
// do_login,
|
||||||
)}
|
// )}
|
||||||
</tbody>
|
// </tbody>
|
||||||
</table>
|
// </table>
|
||||||
</div>
|
// </div>
|
||||||
)}</LoginPopup>
|
// )}</LoginPopup>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function InfoSidebar(props) {
|
export function InfoSidebar(props) {
|
||||||
return (
|
return (
|
||||||
@@ -207,23 +207,25 @@ export function InfoSidebar(props) {
|
|||||||
<span className="icon icon-settings" /><label>网页版树洞设置</label>
|
<span className="icon icon-settings" /><label>网页版树洞设置</label>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="http://pkuhelper.pku.edu.cn/treehole_rules.html" target="_blank">
|
{/*<a href="http://pkuhelper.pku.edu.cn/treehole_rules.html" target="_blank">*/}
|
||||||
<span className="icon icon-textfile" /><label>树洞规范</label>
|
{/* <span className="icon icon-textfile" /><label>树洞规范</label>*/}
|
||||||
</a>
|
{/*</a>*/}
|
||||||
|
{/* */}
|
||||||
<a href="https://github.com/pkuhelper-web/webhole/issues" target="_blank">
|
<a href="https://github.com/thuhole/webhole/issues" target="_blank">
|
||||||
<span className="icon icon-github" /><label>意见反馈</label>
|
<span className="icon icon-github" /><label>意见反馈</label>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="box help-desc-box">
|
<div className="box help-desc-box">
|
||||||
<p>
|
<p>
|
||||||
PKUHelper 网页版树洞 by @xmcp,
|
T大树洞 网页版 by @thuhole,
|
||||||
基于
|
基于
|
||||||
<a href="https://www.gnu.org/licenses/gpl-3.0.zh-cn.html" target="_blank">GPLv3</a>
|
<a href="https://www.gnu.org/licenses/gpl-3.0.zh-cn.html" target="_blank">GPLv3</a>
|
||||||
协议在 <a href="https://github.com/pkuhelper-web/webhole" target="_blank">GitHub</a> 开源
|
协议在 <a href="https://github.com/thuhole/webhole" target="_blank">GitHub</a> 开源
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
PKUHelper 网页版的诞生离不开
|
T大树洞 网页版的诞生离不开
|
||||||
|
<a href="https://github.com/pkuhelper-web/webhole" target="_blank" rel="noopener">P大树洞</a>
|
||||||
|
、
|
||||||
<a href="https://reactjs.org/" target="_blank" rel="noopener">React</a>
|
<a href="https://reactjs.org/" target="_blank" rel="noopener">React</a>
|
||||||
、
|
、
|
||||||
<a href="https://icomoon.io/#icons" target="_blank" rel="noopener">IcoMoon</a>
|
<a href="https://icomoon.io/#icons" target="_blank" rel="noopener">IcoMoon</a>
|
||||||
@@ -280,7 +282,7 @@ class ResetUsertokenWidget extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
loading_status: 'loading',
|
loading_status: 'loading',
|
||||||
},()=>{
|
},()=>{
|
||||||
fetch(PKUHELPER_ROOT+'api_xmcp/hole/reset_usertoken', {
|
fetch(THUHOLE_API_ROOT+'api_xmcp/hole/reset_usertoken', {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -329,9 +331,9 @@ export class LoginForm extends Component {
|
|||||||
return (
|
return (
|
||||||
<TokenCtx.Consumer>{(token)=>
|
<TokenCtx.Consumer>{(token)=>
|
||||||
<div>
|
<div>
|
||||||
{!!token.value &&
|
{/*{!!token.value &&*/}
|
||||||
<LifeInfoBox token={token.value} set_token={token.set_value} />
|
{/* <LifeInfoBox token={token.value} set_token={token.set_value} />*/}
|
||||||
}
|
{/*}*/}
|
||||||
<div className="login-form box">
|
<div className="login-form box">
|
||||||
{token.value ?
|
{token.value ?
|
||||||
<div>
|
<div>
|
||||||
@@ -354,7 +356,7 @@ export class LoginForm extends Component {
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a onClick={this.copy_token.bind(this,token.value)}>复制 User Token</a><br />
|
<a onClick={this.copy_token.bind(this,token.value)}>复制 User Token</a><br />
|
||||||
User Token 用于迁移登录状态,切勿告知他人,若怀疑被盗号请尽快 <ResetUsertokenWidget token={token.value} />
|
User Token 用于迁移登录状态,切勿告知他人{/*,若怀疑被盗号请尽快 <ResetUsertokenWidget token={token.value} />*/}
|
||||||
</p>
|
</p>
|
||||||
</div> :
|
</div> :
|
||||||
<LoginPopup token_callback={token.set_value}>{(do_popup)=>(
|
<LoginPopup token_callback={token.set_value}>{(do_popup)=>(
|
||||||
@@ -366,7 +368,7 @@ export class LoginForm extends Component {
|
|||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p><small>
|
<p><small>
|
||||||
PKU Helper 面向北京大学学生,通过 ISOP(北京大学数据共享开放服务平台)验证您的身份并提供服务。
|
T大树洞 面向清华大学学生,通过清华邮箱验证您的身份并提供服务。
|
||||||
</small></p>
|
</small></p>
|
||||||
</div>
|
</div>
|
||||||
)}</LoginPopup>
|
)}</LoginPopup>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {get_json, API_VERSION_PARAM} from './infrastructure/functions';
|
import {get_json, API_VERSION_PARAM} from './infrastructure/functions';
|
||||||
import {PKUHELPER_ROOT} from './infrastructure/const';
|
import {THUHOLE_API_ROOT} from './infrastructure/const';
|
||||||
import {API_BASE} from './Common';
|
import {API_BASE} from './Common';
|
||||||
import {cache} from './cache';
|
import {cache} from './cache';
|
||||||
|
|
||||||
export {PKUHELPER_ROOT, API_VERSION_PARAM};
|
export {THUHOLE_API_ROOT, API_VERSION_PARAM};
|
||||||
|
|
||||||
export function token_param(token) {
|
export function token_param(token) {
|
||||||
return API_VERSION_PARAM()+(token ? ('&user_token='+token) : '');
|
return API_VERSION_PARAM()+(token ? ('&user_token='+token) : '');
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// regexp should match the WHOLE segmented part
|
// regexp should match the WHOLE segmented part
|
||||||
export const PID_RE=/(^|[^\d\u20e3\ufe0e\ufe0f])([2-9]\d{4,5}|1\d{4,6})(?![\d\u20e3\ufe0e\ufe0f])/g;
|
// export const PID_RE=/(^|[^\d\u20e3\ufe0e\ufe0f])([2-9]\d{4,5}|1\d{4,6})(?![\d\u20e3\ufe0e\ufe0f])/g;
|
||||||
export const URL_PID_RE=/((?:https?:\/\/)?pkuhelper\.pku\.edu\.cn\/hole\/?#(?:#|%23)([2-9]\d{4,5}|1\d{4,6}))(?!\d|\u20e3|\ufe0e|\ufe0f)/g;
|
export const PID_RE=/(^|[^\d\u20e3\ufe0e\ufe0f])(#\d{1,7})(?![\d\u20e3\ufe0e\ufe0f])/g;
|
||||||
|
// TODO: fix this re
|
||||||
|
// export const URL_PID_RE=/((?:https?:\/\/)?thuhole\.tech\/?#(?:#|%23)([2-9]\d{4,5}|1\d{4,6}))(?!\d|\u20e3|\ufe0e|\ufe0f)/g;
|
||||||
|
export const URL_PID_RE=/((?:https?:\/\/)?thuhole\.tech\/?#(?:#|%23)(\d{1,7}))(?!\d|\u20e3|\ufe0e|\ufe0f)/g;
|
||||||
export const NICKNAME_RE=/(^|[^A-Za-z])((?:(?:Angry|Baby|Crazy|Diligent|Excited|Fat|Greedy|Hungry|Interesting|Jolly|Kind|Little|Magic|Naïve|Old|Powerful|Quiet|Rich|Superman|THU|Undefined|Valuable|Wifeless|Xiangbuchulai|Young|Zombie)\s)?(?:Alice|Bob|Carol|Dave|Eve|Francis|Grace|Hans|Isabella|Jason|Kate|Louis|Margaret|Nathan|Olivia|Paul|Queen|Richard|Susan|Thomas|Uma|Vivian|Winnie|Xander|Yasmine|Zach)|You Win(?: \d+)?|洞主)(?![A-Za-z])/gi;
|
export const NICKNAME_RE=/(^|[^A-Za-z])((?:(?:Angry|Baby|Crazy|Diligent|Excited|Fat|Greedy|Hungry|Interesting|Jolly|Kind|Little|Magic|Naïve|Old|Powerful|Quiet|Rich|Superman|THU|Undefined|Valuable|Wifeless|Xiangbuchulai|Young|Zombie)\s)?(?:Alice|Bob|Carol|Dave|Eve|Francis|Grace|Hans|Isabella|Jason|Kate|Louis|Margaret|Nathan|Olivia|Paul|Queen|Richard|Susan|Thomas|Uma|Vivian|Winnie|Xander|Yasmine|Zach)|You Win(?: \d+)?|洞主)(?![A-Za-z])/gi;
|
||||||
export const URL_RE=/(^|[^.@a-zA-Z0-9_])((?:https?:\/\/)?(?:(?:[\w-]+\.)+[a-zA-Z]{2,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?(?:\/[\w~!@#$%^&*()\-_=+[\]{};:,./?|]*)?)(?![a-zA-Z0-9])/gi;
|
export const URL_RE=/(^|[^.@a-zA-Z0-9_])((?:https?:\/\/)?(?:(?:[\w-]+\.)+[a-zA-Z]{2,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?(?:\/[\w~!@#$%^&*()\-_=+[\]{};:,./?|]*)?)(?![a-zA-Z0-9])/gi;
|
||||||
|
|
||||||
|
|||||||