Browse Source

实现删除

pull/6/head
hole-thu 5 years ago
parent
commit
bb008bc0fa
  1. 2
      public/static/fonts_7/icomoon.css
  2. 165
      src/Flows.js
  3. 2
      src/UserAction.js
  4. 20
      src/flows_api.js
  5. 2
      src/infrastructure/functions.js

2
public/static/fonts_7/icomoon.css

@ -108,3 +108,5 @@
.icon-eye-blocked:before { .icon-eye-blocked:before {
content: "\e9d1"; content: "\e9d1";
} }
.icon-trash:before {
content: "\1f5d1";

165
src/Flows.js

@ -93,26 +93,27 @@ class Reply extends PureComponent {
} }
render() { render() {
const author = this.props.info.name, const {info, color_picker, show_pid, do_filter_name, do_delete} = this.props;
replyText = this.props.info.text; const author = info.name,
replyText = info.text;
return ( return (
<div <div
className={'flow-reply box'} className={'flow-reply box'}
style={ style={
this.props.info._display_color info._display_color
? { ? {
'--box-bgcolor-light': this.props.info._display_color[0], '--box-bgcolor-light': info._display_color[0],
'--box-bgcolor-dark': this.props.info._display_color[1], '--box-bgcolor-dark': info._display_color[1],
} }
: null : null
} }
> >
<div className="box-header"> <div className="box-header">
{!!this.props.do_filter_name && ( {!!do_filter_name && (
<span <span
className="reply-header-badge clickable" className="reply-header-badge clickable"
onClick={() => { onClick={() => {
this.props.do_filter_name(this.props.info.name); do_filter_name(info.name);
}} }}
> >
<span className="icon icon-locate" /> <span className="icon icon-locate" />
@ -120,18 +121,29 @@ class Reply extends PureComponent {
)} )}
&nbsp; &nbsp;
{( {(
<span className="box-header-name">{this.props.info.name}</span> <span className="box-header-name">{info.name}</span>
)} )}
<Time stamp={this.props.info.timestamp} short={false} /> {!!do_delete && !!info.can_del && (
<span
className="clickable"
onClick={() => {
do_delete('cid', info.cid);
}}
>
<span className="icon icon-trash" />
</span>
)}
&nbsp;
<Time stamp={info.timestamp} short={false} />
&nbsp; &nbsp;
<code className="box-id">{'$' + this.props.info.cid}</code> <code className="box-id">{'$' + info.cid}</code>
</div> </div>
<div className="box-content"> <div className="box-content">
<HighlightedMarkdown <HighlightedMarkdown
author={author} author={author}
text={replyText} text={replyText}
color_picker={this.props.color_picker} color_picker={color_picker}
show_pid={this.props.show_pid} show_pid={show_pid}
/> />
</div> </div>
</div> </div>
@ -167,10 +179,10 @@ class FlowItem extends PureComponent {
} }
render() { render() {
let props = this.props; const {info, is_quote, cached, attention, can_del, do_filter_name, do_delete, timestamp, img_clickable, color_picker, show_pid} = this.props;
return ( return (
<div className={'flow-item' + (props.is_quote ? ' flow-item-quote' : '')}> <div className={'flow-item' + (is_quote ? ' flow-item-quote' : '')}>
{!!props.is_quote && ( {!!is_quote && (
<div className="quote-tip black-outline"> <div className="quote-tip black-outline">
<div> <div>
<span className="icon icon-quote" /> <span className="icon icon-quote" />
@ -182,96 +194,106 @@ class FlowItem extends PureComponent {
)} )}
<div className="box"> <div className="box">
{!!window.LATEST_POST_ID && {!!window.LATEST_POST_ID &&
parseInt(props.info.pid, 10) > window.LATEST_POST_ID && ( parseInt(info.pid, 10) > window.LATEST_POST_ID && (
<div className="flow-item-dot" /> <div className="flow-item-dot" />
)} )}
{!!this.props.attention && !this.props.cached && ( {!!attention && !cached && (
<div className="flow-item-dot" /> <div className="flow-item-dot" />
)} )}
<div className="box-header"> <div className="box-header">
{!!this.props.do_filter_name && ( {!!do_filter_name && (
<span <span
className="reply-header-badge clickable" className="reply-header-badge clickable"
onClick={() => { onClick={() => {
this.props.do_filter_name(DZ_NAME); do_filter_name(DZ_NAME);
}} }}
> >
<span className="icon icon-locate" /> <span className="icon icon-locate" />
</span> </span>
)} )}
{!!parseInt(props.info.likenum, 10) && ( {!!parseInt(info.likenum, 10) && (
<span className="box-header-badge"> <span className="box-header-badge">
{props.info.likenum}&nbsp; {info.likenum}&nbsp;
<span <span
className={ className={
'icon icon-' + (props.attention ? 'star-ok' : 'star') 'icon icon-' + (attention ? 'star-ok' : 'star')
} }
/> />
</span> </span>
)} )}
{!!parseInt(props.info.reply, 10) && ( {!!parseInt(info.reply, 10) && (
<span className="box-header-badge"> <span className="box-header-badge">
{props.info.reply}&nbsp; {info.reply}&nbsp;
<span className="icon icon-reply" /> <span className="icon icon-reply" />
</span> </span>
)} )}
<code className="box-id"> <code className="box-id">
<a <a
href={'##' + props.info.pid} href={'##' + info.pid}
onClick={this.copy_link.bind(this)} onClick={this.copy_link.bind(this)}
> >
#{props.info.pid} #{info.pid}
</a> </a>
</code> </code>
{!!do_delete && !!info.can_del && (
<span
className="clickable"
onClick={() => {
do_delete('pid', info.pid);
}}
>
<span className="icon icon-trash" />
</span>
)}
&nbsp; &nbsp;
{props.info.cw !== null && ( {info.cw !== null && (
<span className="box-header-cw">{props.info.cw}</span> <span className="box-header-cw">{info.cw}</span>
)} )}
<Time stamp={props.info.timestamp} short={!props.img_clickable} /> <Time stamp={info.timestamp} short={!img_clickable} />
</div> </div>
<div className="box-content"> <div className="box-content">
<HighlightedMarkdown <HighlightedMarkdown
text={props.info.text} text={info.text}
color_picker={props.color_picker} color_picker={color_picker}
show_pid={props.show_pid} show_pid={show_pid}
/> />
{props.info.type === 'image' && ( {info.type === 'image' && (
<p className="img"> <p className="img">
{props.img_clickable ? ( {img_clickable ? (
<a <a
className="no-underline" className="no-underline"
href={IMAGE_BASE + props.info.url} href={IMAGE_BASE + info.url}
target="_blank" target="_blank"
> >
<img <img
src={IMAGE_BASE + props.info.url} src={IMAGE_BASE + info.url}
onError={(e) => { onError={(e) => {
if (e.target.src === IMAGE_BASE + props.info.url) { if (e.target.src === IMAGE_BASE + info.url) {
e.target.src = IMAGE_BAK_BASE + props.info.url; e.target.src = IMAGE_BAK_BASE + info.url;
} }
}} }}
alt={IMAGE_BASE + props.info.url} alt={IMAGE_BASE + info.url}
/> />
</a> </a>
) : ( ) : (
<img <img
src={IMAGE_BASE + props.info.url} src={IMAGE_BASE + info.url}
onError={(e) => { onError={(e) => {
if (e.target.src === IMAGE_BASE + props.info.url) { if (e.target.src === IMAGE_BASE + info.url) {
e.target.src = IMAGE_BAK_BASE + props.info.url; e.target.src = IMAGE_BAK_BASE + info.url;
} }
}} }}
alt={IMAGE_BASE + props.info.url} alt={IMAGE_BASE + info.url}
/> />
)} )}
</p> </p>
)} )}
{/*{props.info.type==='audio' && <AudioWidget src={AUDIO_BASE+props.info.url} />}*/} {/*{info.type==='audio' && <AudioWidget src={AUDIO_BASE+info.url} />}*/}
</div> </div>
{!!(props.attention && props.info.variant.latest_reply) && ( {!!(attention && info.variant.latest_reply) && (
<p className="box-footer"> <p className="box-footer">
最新回复{' '} 最新回复{' '}
<Time stamp={props.info.variant.latest_reply} short={false} /> <Time stamp={info.variant.latest_reply} short={false} />
</p> </p>
)} )}
</div> </div>
@ -441,6 +463,24 @@ class FlowSidebar extends PureComponent {
} }
} }
make_do_delete(token) {
const do_delete = (type, id) => {
console.log('del', type, id, token);
let note = prompt(`将删除${type}=${id}, 备注:`);
if (note !== null) {
API.del(type, id, note, token)
.then((json) => {
alert('删除成功');
})
.catch((e) => {
alert('删除失败\n' + e);
console.error(e);
});
}
}
return do_delete;
}
render() { render() {
if (this.state.loading_status === 'loading') if (this.state.loading_status === 'loading')
return <p className="box box-tip">加载中</p>; return <p className="box box-tip">加载中</p>;
@ -484,6 +524,7 @@ class FlowSidebar extends PureComponent {
do_filter_name={ do_filter_name={
replies_cnt[DZ_NAME] > 1 ? this.set_filter_name.bind(this) : null replies_cnt[DZ_NAME] > 1 ? this.set_filter_name.bind(this) : null
} }
do_delete={this.make_do_delete(this.props.token)}
/> />
</ClickHandler> </ClickHandler>
); );
@ -598,6 +639,7 @@ class FlowSidebar extends PureComponent {
? this.set_filter_name.bind(this) ? this.set_filter_name.bind(this)
: null : null
} }
do_delete={this.make_do_delete(this.props.token)}
/> />
</ClickHandler> </ClickHandler>
</LazyLoad> </LazyLoad>
@ -1036,7 +1078,7 @@ export class Flow extends PureComponent {
if (page > this.state.loaded_pages + 1) throw new Error('bad page'); if (page > this.state.loaded_pages + 1) throw new Error('bad page');
if (page === this.state.loaded_pages + 1) { if (page === this.state.loaded_pages + 1) {
//console.log('fetching page', page); console.log('fetching page', page);
cache(); cache();
if (this.state.mode === 'list') { if (this.state.mode === 'list') {
API.get_list(page, this.props.token) API.get_list(page, this.props.token)
@ -1046,19 +1088,20 @@ export class Flow extends PureComponent {
let max_id = -1; let max_id = -1;
json.data.forEach((x) => { json.data.forEach((x) => {
if (parseInt(x.pid, 10) > max_id) max_id = parseInt(x.pid, 10); if (parseInt(x.pid, 10) > max_id) max_id = parseInt(x.pid, 10);
if (x.comments) {
let comment_json = {
'code': 0,
'attention': x.attention,
'data': x.comments
}
//console.log('My cache', comment_json, x.pid, x.reply)
cache().put(x.pid, parseInt(x.reply, 10), comment_json);
}
}); });
localStorage['_LATEST_POST_ID'] = '' + max_id; localStorage['_LATEST_POST_ID'] = '' + max_id;
} }
json.data.forEach((x) => {
if (x.comments) {
let comment_json = {
'code': 0,
'attention': x.attention,
'data': x.comments
}
//console.log('My cache', comment_json, x.pid, x.reply)
cache().put(x.pid, parseInt(x.reply, 10), comment_json);
}
});
this.setState((prev, props) => ({ this.setState((prev, props) => ({
chunks: { chunks: {
title: 'News Feed', title: 'News Feed',
@ -1105,10 +1148,10 @@ export class Flow extends PureComponent {
let x = json.data; let x = json.data;
if (x.comments) { if (x.comments) {
let comment_json = { let comment_json = {
'code': 0, code: 0,
'attention': x.attention, attention: x.attention,
'data': x.comments data: x.comments,
} };
//console.log('My cache', comment_json, x.pid, x.reply) //console.log('My cache', comment_json, x.pid, x.reply)
cache().put(x.pid, parseInt(x.reply, 10), comment_json); cache().put(x.pid, parseInt(x.reply, 10), comment_json);
} }

2
src/UserAction.js

@ -291,7 +291,7 @@ export class ReplyForm extends Component {
}) })
.catch((e) => { .catch((e) => {
console.error(e); console.error(e);
alert('回复失败'); alert('回复失败\n' + e);
this.setState({ this.setState({
loading_status: 'done', loading_status: 'done',
}); });

20
src/flows_api.js

@ -39,7 +39,7 @@ export const API = {
); );
let json = await handle_response(response); let json = await handle_response(response);
// Why delete then put ?? // Why delete then put ??
console.log('Put cache', json, pid, cache_version); //console.log('Put cache', json, pid, cache_version);
cache().put(pid, cache_version, json); cache().put(pid, cache_version, json);
json.data = parse_replies(json.data, color_picker); json.data = parse_replies(json.data, color_picker);
return json; return json;
@ -98,6 +98,24 @@ export const API = {
return handle_response(response, true); return handle_response(response, true);
}, },
del: async (type, id, note, token) => {
let data = new URLSearchParams();
data.append('type', type);
data.append('id', id);
data.append('note', note);
let response = await fetch(
API_BASE + '/delete' + token_param(token),
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: data,
},
);
return handle_response(response, true);
},
get_list: async (page, token) => { get_list: async (page, token) => {
let response = await fetch( let response = await fetch(
API_BASE + '/getlist' + token_param(token) + '&p=' + page, API_BASE + '/getlist' + token_param(token) + '&p=' + page,

2
src/infrastructure/functions.js

@ -1,5 +1,5 @@
export function get_json(res) { export function get_json(res) {
if(!res.ok) throw Error(`错误 ${res.status} ${res.statusText}`); if(!res.ok) throw Error(`${res.status} ${res.statusText}`);
return ( return (
res res
.text() .text()

Loading…
Cancel
Save