diff --git a/src/sass/metronic/customize.scss b/src/sass/metronic/customize.scss index 2e4e089..0841db9 100644 --- a/src/sass/metronic/customize.scss +++ b/src/sass/metronic/customize.scss @@ -60,6 +60,7 @@ cursor: default; background-color: #337ab7; border-color: #337ab7; + z-index: 5; } } &.disabled { diff --git a/src/scripts/actions/feedbackAction.js b/src/scripts/actions/feedbackAction.js index b22049c..2923d76 100644 --- a/src/scripts/actions/feedbackAction.js +++ b/src/scripts/actions/feedbackAction.js @@ -8,6 +8,8 @@ export const REPORT_DELETE_REPORT = 'REPORT_DELETE_REPORT' export const REPORT_TOGGLE_BLK = 'REPORT_TOGGLE_BLK' export const REPORT_TOGGLE_R18 = 'REPORT_TOGGLE_R18' +export const REPORT_REPLY_LOG = 'REPORT_REPLY_LOG' +export const FEEDBACK_REPLY_LOG = 'FEEDBACK_REPLY_LOG' export function deleteFeedback(id) { return (dispatch) => { @@ -78,6 +80,7 @@ export function toggleBlk(id) { block: true }) .end((err, res) => { + Toastr.success(`此帖子已屏蔽`) dispatch({ type: REPORT_TOGGLE_BLK, id @@ -93,10 +96,26 @@ export function toggleR18(id) { r18: true }) .end((err, res) => { + Toastr.success(`此帖子已设为十八禁`) dispatch({ type: REPORT_TOGGLE_R18, id }) }) } +} + +export function reportPushReply(id,log) { + return { + type:REPORT_REPLY_LOG, + id, + log + } +} +export function feedbackPushReply(id,log) { + return { + type:FEEDBACK_REPLY_LOG, + id, + log + } } \ No newline at end of file diff --git a/src/scripts/components/FeedbackList/FeedbackList.jsx b/src/scripts/components/FeedbackList/FeedbackList.jsx index b8f2fd1..8304b58 100644 --- a/src/scripts/components/FeedbackList/FeedbackList.jsx +++ b/src/scripts/components/FeedbackList/FeedbackList.jsx @@ -1,12 +1,10 @@ import React, { Component } from 'react' import { Link } from 'react-router-dom' -import Moment from 'moment' import ReactPaginate from 'react-paginate' -import { parsePage } from '../../widgets/parse' +import { dateFormat } from '../../widgets' -import { Row, Form, FormGroup, FormControl, Button, InputGroup, ButtonToolbar, Modal } from 'react-bootstrap' import Lightbox from 'react-images' - +import Request from 'superagent' export default class FeedbackList extends Component{ constructor(props) { super(props) @@ -14,6 +12,11 @@ export default class FeedbackList extends Component{ lightboxIsOpen:false, images:[], currentImage:0, + reportId:'', + reportContent:'您的举报已处理', + feedbackId:'', + feedbackContent:'', + logs:[] } this.deleteFeedback = (id) => confirm('Delete this Feedback?') && this.props.deleteFeedback(id) @@ -26,7 +29,16 @@ export default class FeedbackList extends Component{ this.setState({ lightboxIsOpen: true,images:imgs,currentImage:0}) } this.closeLightbox = () => this.setState({lightboxIsOpen:false,images:[]}) - + this.sendMsg = this._sendMsg.bind(this) + this.showReportModal = this._showReportModal.bind(this) + this.sendFeedbackMsg = this._sendFeedbackMsg.bind(this) + this.showFeedbackModal = this._showFeedbackModal.bind(this) + + this.showLogs = (logs) => { + this.setState({logs},() => { + $('#logsModal').modal('show') + }) + } } componentWillMount() { const { fPage,rPage } = this.props @@ -38,12 +50,76 @@ export default class FeedbackList extends Component{ this.props.getReport() } } + componentDidMount() { + $('#reportModal').on('hidden.bs.modal', (e) => { + this.setState({ + reportId:'' + }) + }) + $('#feedbackModal').on('hidden.bs.modal', (e) => { + this.setState({ + feedbackId:'', + feedbackContent:'' + }) + }) + $('#logsModal').on('hidden.bs.modal', (e) => { + this.setState({ + logs:[], + }) + }) + } formatUrl(images,caption) { images.map((image) => { image.src = image.url }) return images } + _sendMsg() { + const { reportId,reportContent } = this.state + Request.post(`/api/report/${reportId}/reply`) + .send({ + content:reportContent + }) + .end((err,res) => { + if(err) { + Toastr.error(`举报失败。`) + }else{ + this.props.reportPushReply(reportId,res.text) + Toastr.success(`举报 已通知~`) + $('#reportModal').modal('hide') + + } + + }) + } + _showReportModal(reportId) { + this.setState({reportId},() => { + $('#reportModal').modal('show') + }) + } + _showFeedbackModal(feedbackId,content) { + + this.setState({feedbackId,feedbackContent:`您的反馈 ${content} 已处理`},() => { + $('#feedbackModal').modal('show') + }) + } + _sendFeedbackMsg() { + const { feedbackId,feedbackContent } = this.state + Request.post(`/api/report/${feedbackId}/reply`) + .send({ + content:feedbackContent + }) + .end((err,res) => { + if(err) { + Toastr.error(`反馈失败。`) + }else{ + this.props.feedbackPushReply(feedbackId,res.text) + Toastr.success(`反馈 已通知~`) + $('#feedbackModal').modal('hide') + + } + }) + } render() { return(
@@ -67,7 +143,7 @@ export default class FeedbackList extends Component{
- + { this.props.reports.map((report) => { @@ -77,7 +153,7 @@ export default class FeedbackList extends Component{ - + + ) @@ -119,26 +201,25 @@ export default class FeedbackList extends Component{
ReporterReasonCreatedTypeThumbnailOperate
ReporterReasonCreatedTypeThumbnailStateOperate
{report.content}{Moment.unix(report.created / 1000).fromNow()}{dateFormat(report.created)} { report.targetType === 'post' ? @@ -98,19 +174,25 @@ export default class FeedbackList extends Component{ } - - this.props.deleteReport(report.id)}> - { - report.targetType === 'post' ? - this.props.toggleBlk(report.targetId)}> - : - } - { - report.targetType === 'post' ? - this.props.toggleR18(report.targetId)}> - : - } - + { + report.logs.length ? + this.showLogs(report.logs)} className="m-badge m-badge--accent m-badge--wide">已处理 + :未处理 + } + + { + report.targetType === 'post' ? + this.props.toggleBlk(report.targetId)}> + : + } + { + report.targetType === 'post' ? + this.props.toggleR18(report.targetId)}> + : + } + this.props.deleteReport(report.id)}> + this.showReportModal(report.id)}>
-
- «} - nextLabel={»} - breakLabel={...} - breakClassName={"break-me"} - pageCount={this.props.rPages} - marginPagesDisplayed={2} - pageRangeDisplayed={5} - onPageChange={obj => this.props.getReport(obj.selected)} - containerClassName={"pagination"} - subContainerClassName={"pages pagination"} - forcePage={this.props.rPage || 0} - activeClassName={"active"} /> -
+ «} + nextLabel={»} + breakLabel={...} + breakClassName={"break-me"} + pageCount={this.props.rPages} + marginPagesDisplayed={2} + pageRangeDisplayed={5} + onPageChange={obj => this.props.getReport(obj.selected)} + containerClassName={"pagination"} + subContainerClassName={"pages pagination"} + forcePage={this.props.rPage || 0} + activeClassName={"active"} + />
- + { this.props.feedbacks.map((feedback) => { @@ -154,10 +235,18 @@ export default class FeedbackList extends Component{ - + + ) @@ -195,6 +284,63 @@ export default class FeedbackList extends Component{ backdropClosesModal={true} showCloseButton={false} /> + + + ) } diff --git a/src/scripts/components/FeedbackList/index.js b/src/scripts/components/FeedbackList/index.js index 851e4b6..7cf7e8b 100644 --- a/src/scripts/components/FeedbackList/index.js +++ b/src/scripts/components/FeedbackList/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux' import FeedbackList from './FeedbackList' -import { getFeedback, deleteFeedback,getReport, deleteReport, toggleBlk,toggleR18 } from '../../actions/feedbackAction' +import { getFeedback, deleteFeedback,getReport, deleteReport, toggleBlk,toggleR18,reportPushReply,feedbackPushReply } from '../../actions/feedbackAction' import { setTouid } from '../../actions/adminAction' const mapActionCreators = { getFeedback, @@ -11,6 +11,8 @@ const mapActionCreators = { deleteReport, toggleBlk, toggleR18, + reportPushReply, + feedbackPushReply, setTouid, } diff --git a/src/scripts/metronic/popper.js b/src/scripts/metronic/popper.js deleted file mode 100644 index 63e30d6..0000000 --- a/src/scripts/metronic/popper.js +++ /dev/null @@ -1,5 +0,0 @@ -import Popper from 'popper.js' -import Toastr from 'toastr' - -window.Popper = Popper -window.Toastr = Toastr \ No newline at end of file diff --git a/src/scripts/reducers/feedbackReducer.js b/src/scripts/reducers/feedbackReducer.js index 31463e1..8cbf015 100644 --- a/src/scripts/reducers/feedbackReducer.js +++ b/src/scripts/reducers/feedbackReducer.js @@ -1,7 +1,7 @@ import Immutable from 'immutable' import { - FEEDBACK_RECEIVE_DATA, FEEDBACK_DELETE_FEEDBACK, - REPORT_RECEIVE_DATA, REPORT_DELETE_REPORT, REPORT_TOGGLE_BLK,REPORT_TOGGLE_R18 + FEEDBACK_RECEIVE_DATA, FEEDBACK_DELETE_FEEDBACK, FEEDBACK_REPLY_LOG, + REPORT_RECEIVE_DATA, REPORT_DELETE_REPORT, REPORT_TOGGLE_BLK,REPORT_TOGGLE_R18,REPORT_REPLY_LOG } from '../actions/feedbackAction' export default (state = Immutable.fromJS({ @@ -51,6 +51,30 @@ export default (state = Immutable.fromJS({ } ) }) + case REPORT_REPLY_LOG: + return state.updateIn(['reports'], (reports) => { + return reports.update( + reports.findIndex((item) => { + return item.get('id') === action.id + }), (item) => { + return item.updateIn(['logs'], (logs) => { + return logs.push(Immutable.fromJS(action.log)) + }) + } + ) + }) + case FEEDBACK_REPLY_LOG: + return state.updateIn(['feedbacks'], (feedbacks) => { + return feedbacks.update( + feedbacks.findIndex((item) => { + return item.get('id') === action.id + }), (item) => { + return item.updateIn(['logs'], (logs) => { + return logs.push(Immutable.fromJS(action.log)) + }) + } + ) + }) default: return state } diff --git a/src/scripts/widgets/index.js b/src/scripts/widgets/index.js index 53df311..30e7df6 100644 --- a/src/scripts/widgets/index.js +++ b/src/scripts/widgets/index.js @@ -1,13 +1,22 @@ import Moment from 'moment' - +import { parse } from 'qs' Moment.locale('zh-cn') export const dateFormat = (time) => { - return Moment(time).format("D MMM, H:mm A") + return Moment(time).format("MMM Do, H:mm A") } export const dateFromNow = (time) => { return Moment(time).fromNow() -} \ No newline at end of file +} + +export const parsePage = (str) => { + const page = parse(str.substr(1)).page + if(page){ + return parseInt(page) + }else{ + return 0 + } +} diff --git a/src/scripts/widgets/plugin.js b/src/scripts/widgets/plugin.js new file mode 100644 index 0000000..17bdadc --- /dev/null +++ b/src/scripts/widgets/plugin.js @@ -0,0 +1,3 @@ +import Toastr from 'toastr' + +window.Toastr = Toastr \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index f25ee1b..a454b91 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,11 +10,8 @@ module.exports = { ], vendor: [ 'jquery', - // 'popper', - path.resolve(__dirname, 'src/scripts/metronic/popper.js'), + path.resolve(__dirname, 'src/scripts/widgets/plugin.js'), 'bootstrap/dist/js/bootstrap.js', - // 'admin-lte/dist/js/app.js' - // path.resolve(__dirname, 'src/scripts/metronic/app.js') path.resolve(__dirname, 'src/scripts/metronic/scripts.bundle.js') ] }, @@ -69,6 +66,7 @@ module.exports = { $: "jquery", jQuery: "jquery", "window.jQuery": "jquery", + Popper: ['popper.js', 'default'], }), ], devServer: { diff --git a/webpack.production.config.js b/webpack.production.config.js index 4b4eaad..b7d864b 100644 --- a/webpack.production.config.js +++ b/webpack.production.config.js @@ -13,14 +13,11 @@ const config = { entry: { app: path.resolve(__dirname, 'src/scripts/main.js'), vendor: [ - 'jquery', - // 'popper', - path.resolve(__dirname, 'src/scripts/metronic/popper.js'), - 'bootstrap/dist/js/bootstrap.js', - // 'admin-lte/dist/js/app.js' - // path.resolve(__dirname, 'src/scripts/metronic/app.js') - path.resolve(__dirname, 'src/scripts/metronic/scripts.bundle.js') - ] + 'jquery', + path.resolve(__dirname, 'src/scripts/widgets/plugin.js'), + 'bootstrap/dist/js/bootstrap.js', + path.resolve(__dirname, 'src/scripts/metronic/scripts.bundle.js') + ] }, output: { path: path.resolve(__dirname, 'dist'), @@ -73,6 +70,7 @@ const config = { $: "jquery", jQuery: "jquery", "window.jQuery": "jquery", + Popper: ['popper.js', 'default'], }), new CopyWebpackPlugin([{ from: path.resolve(__dirname, "src/index.html"),
UserContentCreateduserAgent
UserContentCreateduserAgentState
{feedback.content}{Moment.unix(feedback.created / 1000).fromNow()}{dateFormat(feedback.created)} {feedback.userAgent||''} + { + feedback.logs.length ? + this.showLogs(feedback.logs)} className="m-badge m-badge--accent m-badge--wide">已处理 + :未处理 + } + this.deleteFeedback(feedback.id)} className="btn btn-sm"> + this.showFeedbackModal(feedback.id,feedback.content)}>