forked from newthuhole/hole_thu_frontend
实现删除
This commit is contained in:
@@ -108,3 +108,5 @@
|
|||||||
.icon-eye-blocked:before {
|
.icon-eye-blocked:before {
|
||||||
content: "\e9d1";
|
content: "\e9d1";
|
||||||
}
|
}
|
||||||
|
.icon-trash:before {
|
||||||
|
content: "\1f5d1";
|
||||||
|
|||||||
153
src/Flows.js
153
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 {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{(
|
{(
|
||||||
<span className="box-header-name">{this.props.info.name}</span>
|
<span className="box-header-name">{info.name}</span>
|
||||||
|
)}
|
||||||
|
{!!do_delete && !!info.can_del && (
|
||||||
|
<span
|
||||||
|
className="clickable"
|
||||||
|
onClick={() => {
|
||||||
|
do_delete('cid', info.cid);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="icon icon-trash" />
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
<Time stamp={this.props.info.timestamp} short={false} />
|
|
||||||
|
|
||||||
<code className="box-id">{'$' + this.props.info.cid}</code>
|
<Time stamp={info.timestamp} short={false} />
|
||||||
|
|
||||||
|
<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}
|
{info.likenum}
|
||||||
<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}
|
{info.reply}
|
||||||
<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 && (
|
||||||
{props.info.cw !== null && (
|
<span
|
||||||
<span className="box-header-cw">{props.info.cw}</span>
|
className="clickable"
|
||||||
|
onClick={() => {
|
||||||
|
do_delete('pid', info.pid);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="icon icon-trash" />
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
<Time stamp={props.info.timestamp} short={!props.img_clickable} />
|
|
||||||
|
{info.cw !== null && (
|
||||||
|
<span className="box-header-cw">{info.cw}</span>
|
||||||
|
)}
|
||||||
|
<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,6 +1088,10 @@ 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);
|
||||||
|
});
|
||||||
|
localStorage['_LATEST_POST_ID'] = '' + max_id;
|
||||||
|
}
|
||||||
|
json.data.forEach((x) => {
|
||||||
if (x.comments) {
|
if (x.comments) {
|
||||||
let comment_json = {
|
let comment_json = {
|
||||||
'code': 0,
|
'code': 0,
|
||||||
@@ -1055,10 +1101,7 @@ export class Flow extends PureComponent {
|
|||||||
//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);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
localStorage['_LATEST_POST_ID'] = '' + max_id;
|
|
||||||
}
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user