Преглед на файлове

fix:评论样式统一修改;add:评论编辑功能

zhengyingya преди 5 години
родител
ревизия
b9eeb6a6d3
променени са 35 файла, в които са добавени 1042 реда и са изтрити 118 реда
  1. 164
    35
      lib/App.js
  2. 1
    1
      lib/App.js.map
  3. BIN
      lib/assert/icon_answer@2x.png
  4. BIN
      lib/assert/icon_delete.png
  5. BIN
      lib/assert/icon_like@2x.png
  6. 3
    0
      lib/components/CommentBox/index.js
  7. 1
    1
      lib/components/CommentBox/index.js.map
  8. 1
    1
      lib/components/ContentItem/AvatarHoverCard.js.map
  9. 39
    3
      lib/components/ContentItem/index.css
  10. 37
    24
      lib/components/ContentItem/index.js
  11. 1
    1
      lib/components/ContentItem/index.js.map
  12. 86
    0
      lib/components/EditComment/EditComment.css
  13. 227
    0
      lib/components/EditComment/EditComment.js
  14. 1
    0
      lib/components/EditComment/EditComment.js.map
  15. 4
    1
      lib/components/Editor/Upload.css
  16. 1
    1
      lib/components/Editor/Upload.js
  17. 1
    1
      lib/components/Editor/Upload.js.map
  18. 5
    3
      lib/components/Editor/index.js
  19. 1
    1
      lib/components/Editor/index.js.map
  20. 16
    2
      lib/index.js
  21. 1
    1
      lib/index.js.map
  22. 3
    3
      lib/version.json
  23. 116
    6
      src/App.js
  24. BIN
      src/assert/icon_answer@2x.png
  25. BIN
      src/assert/icon_delete.png
  26. BIN
      src/assert/icon_like@2x.png
  27. 3
    0
      src/components/CommentBox/index.js
  28. 39
    3
      src/components/ContentItem/index.css
  29. 34
    23
      src/components/ContentItem/index.js
  30. 86
    0
      src/components/EditComment/EditComment.css
  31. 142
    0
      src/components/EditComment/EditComment.js
  32. 4
    1
      src/components/Editor/Upload.css
  33. 1
    1
      src/components/Editor/Upload.js
  34. 8
    3
      src/components/Editor/index.js
  35. 16
    2
      src/index.js

+ 164
- 35
lib/App.js Целия файл

@@ -57,6 +57,10 @@ var _RenderText = require("./components/RenderText");
57 57
 
58 58
 var _RenderText2 = _interopRequireDefault(_RenderText);
59 59
 
60
+var _EditComment = require("./components/EditComment/EditComment");
61
+
62
+var _EditComment2 = _interopRequireDefault(_EditComment);
63
+
60 64
 var _lang = require("./lang");
61 65
 
62 66
 require("./App.css");
@@ -92,10 +96,18 @@ var App = function (_Component) {
92 96
       // 是否没有更多评论了
93 97
       isNoMoreComment: false,
94 98
       initDone: false,
95
-      locale: "zh-CN"
99
+      locale: "zh-CN",
100
+      editModalVisible: false,
101
+      action: "",
102
+      replyId: "",
103
+      commentId: "",
104
+      userId: "",
105
+      content: "",
106
+      replyPage: 1
96 107
     };
97 108
     _this.handleChangeLoading = _this.handleChangeLoading.bind(_this);
98 109
     _this.sCreateComment = _this.sCreateComment.bind(_this);
110
+    _this.sUpdateComment = _this.sUpdateComment.bind(_this);
99 111
     _this.sDeleteComment = _this.sDeleteComment.bind(_this);
100 112
     _this.sCommentFavor = _this.sCommentFavor.bind(_this);
101 113
     _this.sCreateReply = _this.sCreateReply.bind(_this);
@@ -104,7 +116,10 @@ var App = function (_Component) {
104 116
     _this.sGetComment = _this.sGetComment.bind(_this);
105 117
     _this.sReplyFavor = _this.sReplyFavor.bind(_this);
106 118
     _this.sGetReply = _this.sGetReply.bind(_this);
119
+    _this.sUpdateReply = _this.sUpdateReply.bind(_this);
107 120
     _this.sOssSts = _this.sOssSts.bind(_this);
121
+    _this.handleEdit = _this.handleEdit.bind(_this);
122
+    _this.handleClose = _this.handleClose.bind(_this);
108 123
     return _this;
109 124
   }
110 125
 
@@ -163,6 +178,32 @@ var App = function (_Component) {
163 178
         });
164 179
       });
165 180
     }
181
+  }, {
182
+    key: "handleEdit",
183
+    value: function handleEdit(_ref) {
184
+      var replyId = _ref.replyId,
185
+          commentId = _ref.commentId,
186
+          userId = _ref.userId,
187
+          content = _ref.content,
188
+          replyPage = _ref.replyPage;
189
+
190
+      this.setState({
191
+        editModalVisible: true,
192
+        action: content.replies ? "comment" : content.reply ? "replyToReply" : "reply",
193
+        replyId: replyId,
194
+        commentId: commentId,
195
+        userId: userId,
196
+        content: content,
197
+        replyPage: replyPage
198
+      });
199
+    }
200
+  }, {
201
+    key: "handleClose",
202
+    value: function handleClose() {
203
+      this.setState({
204
+        editModalVisible: false
205
+      });
206
+    }
166 207
   }, {
167 208
     key: "error",
168 209
     value: function error(msg) {
@@ -216,9 +257,9 @@ var App = function (_Component) {
216 257
     value: function sGetComment() {
217 258
       var _this3 = this;
218 259
 
219
-      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
220
-          _ref$page = _ref.page,
221
-          page = _ref$page === undefined ? 1 : _ref$page;
260
+      var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
261
+          _ref2$page = _ref2.page,
262
+          page = _ref2$page === undefined ? 1 : _ref2$page;
222 263
 
223 264
       var pageType = this.props.pageType;
224 265
 
@@ -278,10 +319,10 @@ var App = function (_Component) {
278 319
     value: function sGetReply() {
279 320
       var _this4 = this;
280 321
 
281
-      var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
282
-          commentId = _ref2.commentId,
283
-          _ref2$page = _ref2.page,
284
-          page = _ref2$page === undefined ? 1 : _ref2$page;
322
+      var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
323
+          commentId = _ref3.commentId,
324
+          _ref3$page = _ref3.page,
325
+          page = _ref3$page === undefined ? 1 : _ref3$page;
285 326
 
286 327
       this.handleChangeLoading("sGetReply", true);
287 328
       var _props2 = this.props,
@@ -330,8 +371,8 @@ var App = function (_Component) {
330 371
     value: function sCreateComment() {
331 372
       var _this5 = this;
332 373
 
333
-      var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
334
-          content = _ref3.content;
374
+      var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
375
+          content = _ref4.content;
335 376
 
336 377
       var cb = arguments[1];
337 378
 
@@ -407,7 +448,45 @@ var App = function (_Component) {
407 448
         _this6.handleChangeLoading("sDeleteComment", false);
408 449
       });
409 450
     }
451
+    /**
452
+     * 更新评论
453
+     * @param {object} {content} comment content
454
+     */
410 455
 
456
+  }, {
457
+    key: "sUpdateComment",
458
+    value: function sUpdateComment(_ref5) {
459
+      var _this7 = this;
460
+
461
+      var commentId = _ref5.commentId,
462
+          content = _ref5.content;
463
+
464
+      this.handleChangeLoading("sUpdateComment", true);
465
+      var API = this.props.API;
466
+
467
+      this.axios(API + "/comments/" + commentId, {
468
+        method: "post",
469
+        data: {
470
+          content: content
471
+        },
472
+        withCredentials: true
473
+      }).then(function () {
474
+        var list = _this7.state.list;
475
+
476
+        list = list.map(function (it) {
477
+          if (it.id === commentId) {
478
+            return _extends({}, it, {
479
+              content: content
480
+            });
481
+          }
482
+          return it;
483
+        });
484
+        _this7.props.onUpdateComment("comment");
485
+        _this7.setState({ list: list });
486
+      }).catch(this.errorHandler).finally(function () {
487
+        _this7.handleChangeLoading("sUpdateComment", false);
488
+      });
489
+    }
411 490
     /**
412 491
      * 添加回复
413 492
      * 回复评论/回复回复
@@ -417,7 +496,7 @@ var App = function (_Component) {
417 496
   }, {
418 497
     key: "sCreateReply",
419 498
     value: function sCreateReply(data, cb) {
420
-      var _this7 = this;
499
+      var _this8 = this;
421 500
 
422 501
       if (!data.content) return this.error(_reactIntlUniversal2.default.get("message.replyNoNull"));
423 502
       this.handleChangeLoading("sCreateReply", true);
@@ -428,14 +507,14 @@ var App = function (_Component) {
428 507
         data: data,
429 508
         withCredentials: true
430 509
       }).then(function (response) {
431
-        if (_this7.props.showAlertReply) {
510
+        if (_this8.props.showAlertReply) {
432 511
           _message3.default.success(_reactIntlUniversal2.default.get("message.replySuccess"));
433 512
         }
434 513
         if ((0, _helper.isFunction)(cb)) cb(response.data);
435 514
         // 将数据写入到 list 中
436 515
         // 临时插入
437 516
         // 等到获取数据之后,删除临时数据
438
-        var list = _this7.state.list.map(function (item) {
517
+        var list = _this8.state.list.map(function (item) {
439 518
           if (item.id === data.comment_id) {
440 519
             if (!item.replies) item.replies = [];
441 520
             item.replies.push(_extends({}, response.data, {
@@ -445,9 +524,9 @@ var App = function (_Component) {
445 524
           }
446 525
           return item;
447 526
         });
448
-        _this7.setState({ list: list });
527
+        _this8.setState({ list: list });
449 528
       }).catch(this.errorHandler).finally(function () {
450
-        _this7.handleChangeLoading("sCreateReply", false);
529
+        _this8.handleChangeLoading("sCreateReply", false);
451 530
       });
452 531
     }
453 532
 
@@ -460,7 +539,7 @@ var App = function (_Component) {
460 539
   }, {
461 540
     key: "sDeleteReply",
462 541
     value: function sDeleteReply(replyId, commentId) {
463
-      var _this8 = this;
542
+      var _this9 = this;
464 543
 
465 544
       this.handleChangeLoading("sDeleteReply", true);
466 545
       var API = this.props.API;
@@ -470,7 +549,7 @@ var App = function (_Component) {
470 549
         withCredentials: true
471 550
       }).then(function () {
472 551
         var deletedItem = null;
473
-        var list = _this8.state.list.map(function (item) {
552
+        var list = _this9.state.list.map(function (item) {
474 553
           if (item.id === commentId) {
475 554
             var replies = item.replies.filter(function (item) {
476 555
               return item.id !== replyId;
@@ -483,13 +562,47 @@ var App = function (_Component) {
483 562
           }
484 563
           return item;
485 564
         });
486
-        _this8.setState({ list: list });
487
-        _this8.props.onDelete(_constant.COMMENT_TYPE.REPLY, deletedItem);
565
+        _this9.setState({ list: list });
566
+        _this9.props.onDelete(_constant.COMMENT_TYPE.REPLY, deletedItem);
488 567
       }).catch(this.errorHandler).finally(function () {
489
-        _this8.handleChangeLoading("sDeleteReply", false);
568
+        _this9.handleChangeLoading("sDeleteReply", false);
490 569
       });
491 570
     }
571
+    /**
572
+     * 更新回复
573
+     * 回复评论/回复回复
574
+     * @param {object} data { comment_id, content, reply_id }
575
+     */
576
+
577
+  }, {
578
+    key: "sUpdateReply",
579
+    value: function sUpdateReply(_ref6) {
580
+      var _this10 = this;
581
+
582
+      var commentId = _ref6.commentId,
583
+          content = _ref6.content,
584
+          replyId = _ref6.replyId,
585
+          replyPage = _ref6.replyPage;
492 586
 
587
+      this.handleChangeLoading("sUpdateReply", true);
588
+      var API = this.props.API;
589
+
590
+      this.axios(API + "/replies/" + replyId, {
591
+        method: "post",
592
+        data: {
593
+          comment_id: commentId,
594
+          content: content
595
+        },
596
+        withCredentials: true
597
+      }).then(function () {
598
+        for (var i = 1; i <= replyPage; i++) {
599
+          _this10.sGetReply({ commentId: commentId, page: i });
600
+        }
601
+        _this10.props.onUpdateComment("reply");
602
+      }).catch(this.errorHandler).finally(function () {
603
+        _this10.handleChangeLoading("sUpdateReply", false);
604
+      });
605
+    }
493 606
     /**
494 607
      * 评论 点赞/取消点赞
495 608
      * @param {string} commentId { commentId }
@@ -499,7 +612,7 @@ var App = function (_Component) {
499 612
   }, {
500 613
     key: "sCommentFavor",
501 614
     value: function sCommentFavor(commentId, favored) {
502
-      var _this9 = this;
615
+      var _this11 = this;
503 616
 
504 617
       this.handleChangeLoading("sCommentFavor", true);
505 618
       var API = this.props.API;
@@ -508,20 +621,20 @@ var App = function (_Component) {
508 621
         method: favored ? "delete" : "put",
509 622
         withCredentials: true
510 623
       }).then(function (response) {
511
-        if (_this9.props.showAlertFavor) {
624
+        if (_this11.props.showAlertFavor) {
512 625
           _message3.default.success(favored ? _reactIntlUniversal2.default.get("message.cancelLickSuccess") : _reactIntlUniversal2.default.get("message.likeSuccess"));
513 626
         }
514 627
         // 更新 list 中的该项数据的 favored
515
-        var list = _this9.state.list.map(function (item) {
628
+        var list = _this11.state.list.map(function (item) {
516 629
           if (item.id === commentId) {
517 630
             item.favored = !favored;
518 631
             item.favor_count += favored ? -1 : 1;
519 632
           }
520 633
           return item;
521 634
         });
522
-        _this9.setState({ list: list });
635
+        _this11.setState({ list: list });
523 636
       }).catch(this.errorHandler).finally(function () {
524
-        _this9.handleChangeLoading("sCommentFavor", false);
637
+        _this11.handleChangeLoading("sCommentFavor", false);
525 638
       });
526 639
     }
527 640
 
@@ -535,7 +648,7 @@ var App = function (_Component) {
535 648
   }, {
536 649
     key: "sReplyFavor",
537 650
     value: function sReplyFavor(replyId, commentId, favored) {
538
-      var _this10 = this;
651
+      var _this12 = this;
539 652
 
540 653
       this.handleChangeLoading("sReplyFavor", true);
541 654
       var API = this.props.API;
@@ -549,7 +662,7 @@ var App = function (_Component) {
549 662
       }).then(function (response) {
550 663
         _message3.default.success(favored ? _reactIntlUniversal2.default.get("message.cancelLickSuccess") : _reactIntlUniversal2.default.get("message.likeSuccess"));
551 664
         // 更新 list 中的该项数据的 favored
552
-        var list = _this10.state.list.map(function (item) {
665
+        var list = _this12.state.list.map(function (item) {
553 666
           if (item.id === commentId) {
554 667
             item.replies = item.replies.map(function (r) {
555 668
               if (r.id === replyId) {
@@ -564,9 +677,9 @@ var App = function (_Component) {
564 677
           }
565 678
           return item;
566 679
         });
567
-        _this10.setState({ list: list });
680
+        _this12.setState({ list: list });
568 681
       }).catch(this.errorHandler).finally(function () {
569
-        _this10.handleChangeLoading("sReplyFavor", false);
682
+        _this12.handleChangeLoading("sReplyFavor", false);
570 683
       });
571 684
     }
572 685
 
@@ -577,15 +690,15 @@ var App = function (_Component) {
577 690
   }, {
578 691
     key: "sOssSts",
579 692
     value: function sOssSts() {
580
-      var _this11 = this;
693
+      var _this13 = this;
581 694
 
582 695
       this.handleChangeLoading("sOssSts", true);
583 696
       var API = this.props.API;
584 697
 
585 698
       this.axios.get(API + "/oss/sts").then(function (response) {
586
-        _this11.setState({ oss: _extends({}, response.data) });
699
+        _this13.setState({ oss: _extends({}, response.data) });
587 700
       }).catch(this.errorHandler).finally(function () {
588
-        _this11.handleChangeLoading("sOssSts", false);
701
+        _this13.handleChangeLoading("sOssSts", false);
589 702
       });
590 703
     }
591 704
   }, {
@@ -601,9 +714,11 @@ var App = function (_Component) {
601 714
         sGetReply: this.sGetReply,
602 715
         sOssSts: this.sOssSts,
603 716
         sDeleteComment: this.sDeleteComment,
604
-        sDeleteReply: this.sDeleteReply
717
+        sDeleteReply: this.sDeleteReply,
718
+        sUpdateReply: this.sUpdateReply,
719
+        sUpdateComment: this.sUpdateComment,
720
+        handleEdit: this.handleEdit
605 721
       });
606
-
607 722
       return this.state.initDone && _react2.default.createElement(
608 723
         _Comment.CommentContext.Provider,
609 724
         { value: value },
@@ -616,7 +731,17 @@ var App = function (_Component) {
616 731
             { style: { marginTop: 20 } },
617 732
             _react2.default.createElement(_CommentList2.default, null)
618 733
           )
619
-        )
734
+        ),
735
+        this.state.editModalVisible && _react2.default.createElement(_EditComment2.default, {
736
+          visible: this.state.editModalVisible,
737
+          action: this.state.action,
738
+          replyId: this.state.replyId,
739
+          replyPage: this.state.replyPage,
740
+          commentId: this.state.commentId,
741
+          userId: this.state.content.user_id,
742
+          content: this.state.content,
743
+          handleClose: this.handleClose
744
+        })
620 745
       );
621 746
     }
622 747
   }]);
@@ -643,6 +768,7 @@ App.propTypes = {
643 768
   onPageChange: _propTypes2.default.func, // 页码变化回调
644 769
   onGetMoreBtnClick: _propTypes2.default.func, // 点击查看更多按钮回调
645 770
   onDelete: _propTypes2.default.func,
771
+  onUpdateComment: _propTypes2.default.func,
646 772
   locales: _propTypes2.default.string, //  传入的语言环境, en-US/zh-CN
647 773
   onCountChange: _propTypes2.default.func // 评论数量变更时的回调
648 774
 };
@@ -656,11 +782,14 @@ App.defaultProps = {
656 782
   showAlertReply: false,
657 783
   showAlertFavor: false,
658 784
   showError: true,
785
+  showEdit: false,
659 786
   pageType: "more",
660 787
   limit: _constant.LIMIT,
661 788
   onGetMoreBtnClick: function onGetMoreBtnClick() {},
662 789
   onPageChange: function onPageChange(page) {},
663 790
   onDelete: function onDelete() {},
791
+  onUpdateComment: function onUpdateComment() {},
792
+  onReforeUpdateComment: function onReforeUpdateComment() {},
664 793
   onCountChange: function onCountChange() {}
665 794
 };
666 795
 

+ 1
- 1
lib/App.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


BIN
lib/assert/icon_answer@2x.png Целия файл


BIN
lib/assert/icon_delete.png Целия файл


BIN
lib/assert/icon_like@2x.png Целия файл


+ 3
- 0
lib/components/CommentBox/index.js Целия файл

@@ -116,6 +116,7 @@ var CommentBox = function (_Component) {
116 116
                 content: item,
117 117
                 user_id: item.user_id,
118 118
                 action: "replyToReply" // 回复的回复
119
+                , page: _this2.state.page
119 120
               }), _react2.default.createElement(
120 121
                 "div",
121 122
                 { className: "comment-more-box", key: "show_more_button" },
@@ -147,6 +148,7 @@ var CommentBox = function (_Component) {
147 148
               key: item.id,
148 149
               content: item,
149 150
               action: "replyToReply" // 评论的回复
151
+              , page: _this2.state.page
150 152
             });
151 153
           })
152 154
         );
@@ -171,6 +173,7 @@ var CommentBox = function (_Component) {
171 173
           commentId: content.id,
172 174
           user_id: user_id,
173 175
           action: "reply" // 评论的回复
176
+          , page: this.state.page
174 177
         }),
175 178
         this.renderReplies(content.replies, content.reply_count, content.isNoMoreReply)
176 179
       );

+ 1
- 1
lib/components/CommentBox/index.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 1
- 1
lib/components/ContentItem/AvatarHoverCard.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 39
- 3
lib/components/ContentItem/index.css Целия файл

@@ -34,7 +34,10 @@
34 34
 }
35 35
 
36 36
 .comment-item-bottom {
37
+  display: flex;
38
+  justify-content: flex-end;
37 39
   margin: 20px auto;
40
+  line-height: 18px;
38 41
 }
39 42
 
40 43
 .comment-item-bottom-left {
@@ -43,11 +46,44 @@
43 46
 }
44 47
 
45 48
 .comment-item-bottom-right {
46
-  float: right;
47
-  margin-left: 5px;
48 49
   cursor: pointer;
49 50
 }
50
-
51
+.comment-item-divider {
52
+  width: 2px;
53
+  height: 24px;
54
+  background: #c6c6c6;
55
+  margin-top: -2px;
56
+}
57
+.comment-item-delete,
58
+.comment-item-edit,
59
+.comment-item-like {
60
+  display: inline-block;
61
+  background: url(../../assert/icon_delete.png);
62
+  width: 18px;
63
+  height: 18px;
64
+  background-size: 100% 100%;
65
+  cursor: pointer;
66
+}
67
+.comment-item-delete {
68
+  margin-right: 18px;
69
+}
70
+.comment-item-edit {
71
+  background: url(../../assert/icon_answer@2x.png);
72
+  background-size: 100% 100%;
73
+  margin-right: 18px;
74
+  margin-left: 10px;
75
+}
76
+.comment-item-like {
77
+  background: url(../../assert/icon_like@2x.png);
78
+  background-size: 100% 100%;
79
+  margin-left: 15px;
80
+  margin-right: 2px;
81
+}
82
+.comment-item-reply {
83
+  margin-left: 20px;
84
+  cursor: pointer;
85
+  color: red;
86
+}
51 87
 .comment-favor {
52 88
   font-size: 20px;
53 89
 }

+ 37
- 24
lib/components/ContentItem/index.js Целия файл

@@ -195,10 +195,12 @@ var CommentItem = function (_Component) {
195 195
           showReply = _props.showReply,
196 196
           onShowReply = _props.onShowReply,
197 197
           app = _props.app,
198
-          user_id = _props.user_id;
198
+          user_id = _props.user_id,
199
+          page = _props.page;
199 200
       var _props$app = this.props.app,
200 201
           locale = _props$app.locale,
201
-          showHoverCard = _props$app.showHoverCard;
202
+          showHoverCard = _props$app.showHoverCard,
203
+          showEdit = _props$app.showEdit;
202 204
       var showInput = this.state.showInput;
203 205
 
204 206
 
@@ -350,6 +352,19 @@ var CommentItem = function (_Component) {
350 352
                 showReply ? _react2.default.createElement(_icon2.default, { type: "up" }) : _react2.default.createElement(_icon2.default, { type: "down" })
351 353
               )
352 354
             ) : null,
355
+            showEdit && _react2.default.createElement("i", {
356
+              className: "comment-item-edit",
357
+              onClick: function onClick() {
358
+                return _this2.props.app.handleEdit({
359
+                  action: action,
360
+                  replyId: replyId,
361
+                  commentId: commentId,
362
+                  userId: content.user_id,
363
+                  content: content,
364
+                  replyPage: page
365
+                });
366
+              }
367
+            }),
353 368
             app.userId === content.user_id && _react2.default.createElement(
354 369
               _popconfirm2.default,
355 370
               {
@@ -365,22 +380,9 @@ var CommentItem = function (_Component) {
365 380
                 okText: _reactIntlUniversal2.default.get("popConfirm.ok"),
366 381
                 cancelText: _reactIntlUniversal2.default.get("popConfirm.cancel")
367 382
               },
368
-              _react2.default.createElement(
369
-                "a",
370
-                { className: "comment-item-bottom-right" },
371
-                "\xA0 ",
372
-                _reactIntlUniversal2.default.get("popConfirm.delete")
373
-              )
374
-            ),
375
-            _react2.default.createElement(
376
-              "a",
377
-              {
378
-                onClick: this.handleToggleInput,
379
-                className: "comment-item-bottom-right"
380
-              },
381
-              "\xA0 ",
382
-              _reactIntlUniversal2.default.get("comment.reply")
383
+              _react2.default.createElement("i", { className: "comment-item-delete" })
383 384
             ),
385
+            _react2.default.createElement("span", { className: "comment-item-divider" }),
384 386
             _react2.default.createElement(
385 387
               "div",
386 388
               {
@@ -395,13 +397,22 @@ var CommentItem = function (_Component) {
395 397
                 },
396 398
                 style: { color: "" + IconColor }
397 399
               },
398
-              _react2.default.createElement(_icon2.default, {
399
-                type: "like-o",
400
-                className: content.favored ? "comment-favor comment-favored" : "comment-favor",
401
-                style: { color: "" + IconColor }
402
-              }),
400
+              _react2.default.createElement("i", { className: "comment-item-like" })
401
+            ),
402
+            _react2.default.createElement(
403
+              "span",
404
+              null,
403 405
               "\xA0",
404 406
               content.favor_count
407
+            ),
408
+            _react2.default.createElement(
409
+              "div",
410
+              {
411
+                onClick: this.handleToggleInput,
412
+                className: "comment-item-reply"
413
+              },
414
+              "\xA0 ",
415
+              _reactIntlUniversal2.default.get("comment.reply")
405 416
             )
406 417
           )
407 418
         ),
@@ -426,12 +437,14 @@ CommentItem.propTypes = {
426 437
   // reply 评论的回复
427 438
   // replyToReply 回复的回复
428 439
   action: _propTypes2.default.oneOf(["comment", "reply", "replyToReply"]),
429
-  onShowReply: _propTypes2.default.func
440
+  onShowReply: _propTypes2.default.func,
441
+  showEdit: _propTypes2.default.bool
430 442
 };
431 443
 
432 444
 CommentItem.defaultProps = {
433 445
   action: "comment",
434
-  onShowReply: function onShowReply() {}
446
+  onShowReply: function onShowReply() {},
447
+  showEdit: false
435 448
 };
436 449
 
437 450
 exports.default = (0, _Comment2.default)(CommentItem);

+ 1
- 1
lib/components/ContentItem/index.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 86
- 0
lib/components/EditComment/EditComment.css Целия файл

@@ -0,0 +1,86 @@
1
+.editCommetModal .ant-modal,
2
+.editCommetModal .ant-modal-content {
3
+  width: 608px !important;
4
+  height: 276px;
5
+}
6
+.editCommetModal .ant-modal-body {
7
+  padding: 0;
8
+}
9
+
10
+.editCommetModal .title {
11
+  font-size: 18px;
12
+  color: #4a4a4a;
13
+  padding: 20px 0 0 28px;
14
+}
15
+.editCommetModal .comment-editor {
16
+  border: none;
17
+  padding: 16px 24px;
18
+}
19
+.editCommetModal .comment-editor-toolbar {
20
+  display: none;
21
+}
22
+.editCommetModal .comment-editor:hover,
23
+.editCommetModal .comment-editor:focus {
24
+  border: none;
25
+  outline: none;
26
+  box-shadow: none;
27
+}
28
+.editCommetModal textarea.ant-input {
29
+  border: 1px solid #e1e1e1;
30
+  border-radius: 3px;
31
+  resize: none;
32
+  height: 132px !important;
33
+}
34
+.editCommetModal textarea.ant-input:hover {
35
+  border: 1px solid #e1e1e1;
36
+  border-radius: 3px;
37
+}
38
+.editCommetModal textarea.ant-input:hover,
39
+.editCommetModal textarea.ant-input:focus {
40
+  border-color: #40a9ff;
41
+}
42
+.editCommetModal .comment-toolbar {
43
+  display: flex;
44
+  justify-content: flex-end;
45
+  margin-top: 30px;
46
+}
47
+.editCommetModal .comment-toolbar-left {
48
+  display: flex;
49
+  align-items: center;
50
+  height: 36px;
51
+  margin: 0;
52
+}
53
+.editCommetModal .comment-toolbar-right {
54
+  height: 36px;
55
+  margin: 0;
56
+  margin-left: 20px;
57
+}
58
+.editCommetModal .comment-toolbar-right .ant-btn {
59
+  height: 36px;
60
+}
61
+
62
+.expression-btn-wrap,
63
+.picture-btn-wrap {
64
+  float: left;
65
+  cursor: pointer;
66
+}
67
+.expression-btn-wrap .icon,
68
+.picture-btn-wrap .icon {
69
+  float: left;
70
+  color: #ffa405;
71
+  font-size: 24px !important;
72
+  margin: 0 !important;
73
+}
74
+.expression-btn-wrap .text,
75
+.picture-btn-wrap .text {
76
+  float: left;
77
+  font-size: 16px;
78
+  color: #393939;
79
+  margin-left: 8px;
80
+}
81
+.picture-btn-wrap {
82
+  margin-left: 28px;
83
+}
84
+.picture-btn-wrap .icon {
85
+  color: rgba(113, 193, 53, 1);
86
+}

+ 227
- 0
lib/components/EditComment/EditComment.js Целия файл

@@ -0,0 +1,227 @@
1
+"use strict";
2
+
3
+Object.defineProperty(exports, "__esModule", {
4
+  value: true
5
+});
6
+
7
+var _modal = require("antd/es/modal");
8
+
9
+var _modal2 = _interopRequireDefault(_modal);
10
+
11
+var _icon = require("antd/es/icon");
12
+
13
+var _icon2 = _interopRequireDefault(_icon);
14
+
15
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
16
+
17
+require("antd/es/modal/style/css");
18
+
19
+require("antd/es/icon/style/css");
20
+
21
+var _react = require("react");
22
+
23
+var _react2 = _interopRequireDefault(_react);
24
+
25
+var _propTypes = require("prop-types");
26
+
27
+var _propTypes2 = _interopRequireDefault(_propTypes);
28
+
29
+var _reactIntlUniversal = require("react-intl-universal");
30
+
31
+var _reactIntlUniversal2 = _interopRequireDefault(_reactIntlUniversal);
32
+
33
+var _CommentInput = require("../CommentInput");
34
+
35
+var _CommentInput2 = _interopRequireDefault(_CommentInput);
36
+
37
+var _Editor = require("../Editor");
38
+
39
+var _Editor2 = _interopRequireDefault(_Editor);
40
+
41
+var _constant = require("../../constant");
42
+
43
+require("./EditComment.css");
44
+
45
+var _Comment = require("../../Comment");
46
+
47
+var _Comment2 = _interopRequireDefault(_Comment);
48
+
49
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
50
+
51
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
52
+
53
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
54
+
55
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
56
+
57
+var EditComment = function (_React$Component) {
58
+  _inherits(EditComment, _React$Component);
59
+
60
+  function EditComment(props) {
61
+    _classCallCheck(this, EditComment);
62
+
63
+    var _this = _possibleConstructorReturn(this, (EditComment.__proto__ || Object.getPrototypeOf(EditComment)).call(this, props));
64
+
65
+    _this.handleSubmit = _this.handleSubmit.bind(_this);
66
+    _this.state = {
67
+      value: _this.getInitValue(props).value,
68
+      fileList: _this.getInitValue(props).fileList
69
+    };
70
+    return _this;
71
+  }
72
+
73
+  _createClass(EditComment, [{
74
+    key: "handleSubmit",
75
+    value: function handleSubmit(_ref) {
76
+      var _ref$text = _ref.text,
77
+          text = _ref$text === undefined ? "" : _ref$text,
78
+          _ref$files = _ref.files,
79
+          files = _ref$files === undefined ? [] : _ref$files;
80
+      var fileList = this.state.fileList;
81
+      var _props = this.props,
82
+          app = _props.app,
83
+          action = _props.action,
84
+          commentId = _props.commentId,
85
+          replyId = _props.replyId,
86
+          replyPage = _props.replyPage;
87
+
88
+      var value = text;
89
+      app.onBeforeUpdateComment();
90
+      if (fileList && fileList.length) {
91
+        value += _constant.IMAGE_SPLIT;
92
+        fileList.forEach(function (file) {
93
+          value += file.thumbUrl + ",";
94
+        });
95
+      }
96
+      if (value.substr(-1) === ",") {
97
+        value = value.slice(0, -1);
98
+      }
99
+      if (action === "comment") {
100
+        app.sUpdateComment({ commentId: commentId, content: value });
101
+      } else {
102
+        app.sUpdateReply({ commentId: commentId, content: value, replyId: replyId, replyPage: replyPage });
103
+      }
104
+      this.props.handleClose();
105
+    }
106
+  }, {
107
+    key: "getInitValue",
108
+    value: function getInitValue(props) {
109
+      var content = props.content;
110
+
111
+      var newContent = content.content;
112
+      var images = "";
113
+      if (newContent.indexOf(_constant.IMAGE_SPLIT) !== -1) {
114
+        newContent = newContent.split(_constant.IMAGE_SPLIT);
115
+        images = newContent.pop();
116
+        newContent = newContent.join("");
117
+      }
118
+      var fileList = [];
119
+      if (images !== "") {
120
+        fileList = images.split(",");
121
+        fileList = fileList.map(function (item, index) {
122
+          return {
123
+            thumbUrl: item,
124
+            uid: index
125
+          };
126
+        });
127
+      }
128
+      var value = this.renderTextWithReply(newContent, content);
129
+      return { value: value, fileList: fileList };
130
+    }
131
+  }, {
132
+    key: "getEmojiToolIcon",
133
+    value: function getEmojiToolIcon() {
134
+      return _react2.default.createElement(
135
+        "div",
136
+        { className: "expression-btn-wrap" },
137
+        _react2.default.createElement(_icon2.default, { type: "smile", className: "icon" }),
138
+        _react2.default.createElement(
139
+          "span",
140
+          { className: "text" },
141
+          _reactIntlUniversal2.default.get("bilingually.emoji")
142
+        )
143
+      );
144
+    }
145
+  }, {
146
+    key: "getImageToolIcon",
147
+    value: function getImageToolIcon() {
148
+      return _react2.default.createElement(
149
+        "div",
150
+        { className: "picture-btn-wrap" },
151
+        _react2.default.createElement(_icon2.default, { type: "picture", className: "icon" }),
152
+        _react2.default.createElement(
153
+          "span",
154
+          { className: "text" },
155
+          _reactIntlUniversal2.default.get("bilingually.pic")
156
+        )
157
+      );
158
+    }
159
+  }, {
160
+    key: "renderTextWithReply",
161
+    value: function renderTextWithReply(text, content) {
162
+      var newText = text;
163
+      // const { reply } = content;
164
+      // if (reply) {
165
+      //   newText = `${newText} //@${reply.user_name} ${reply.content}`;
166
+      //   if (reply.reply) {
167
+      //     return this.renderTextWithReply(newText, reply);
168
+      //   }
169
+      // }
170
+      return newText;
171
+    }
172
+  }, {
173
+    key: "render",
174
+    value: function render() {
175
+      var _this2 = this;
176
+
177
+      return _react2.default.createElement(
178
+        _modal2.default,
179
+        {
180
+          visible: true,
181
+          footer: null,
182
+          wrapClassName: "editCommetModal",
183
+          onCancel: this.props.handleClose
184
+        },
185
+        _react2.default.createElement(
186
+          "div",
187
+          { className: "title" },
188
+          _reactIntlUniversal2.default.get("bilingually.imgtxt.edit_imgtxt")
189
+        ),
190
+        _react2.default.createElement(_CommentInput2.default, {
191
+          content: _react2.default.createElement(_Editor2.default, {
192
+            maxUpload: 9,
193
+            autoFocus: true
194
+            // {...this.props.editorProps}
195
+            , action: this.props.action,
196
+            replyId: this.props.replyId,
197
+            commentId: this.props.commentId,
198
+            userId: this.props.content.user_id,
199
+            fileList: this.state.fileList,
200
+            value: this.state.value,
201
+            onChange: function onChange(value) {
202
+              _this2.setState({
203
+                value: value
204
+              });
205
+            },
206
+            handleChangeFileList: function handleChangeFileList(fileList) {
207
+              _this2.setState({
208
+                fileList: fileList
209
+              });
210
+            },
211
+            onSubmit: this.handleSubmit,
212
+            emojiToolIcon: this.getEmojiToolIcon(),
213
+            imageToolIcon: this.getImageToolIcon(),
214
+            emojiPopoverPlacement: "bottom",
215
+            uploadPopoverPlacement: "bottom",
216
+            btnSubmitText: _reactIntlUniversal2.default.get("bilingually.imgtxt.update")
217
+          })
218
+        })
219
+      );
220
+    }
221
+  }]);
222
+
223
+  return EditComment;
224
+}(_react2.default.Component);
225
+
226
+exports.default = (0, _Comment2.default)(EditComment);
227
+//# sourceMappingURL=EditComment.js.map

+ 1
- 0
lib/components/EditComment/EditComment.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 4
- 1
lib/components/Editor/Upload.css Целия файл

@@ -7,7 +7,9 @@
7 7
   margin-top: 8px;
8 8
   color: #666;
9 9
 }
10
-
10
+.upload-img-preview {
11
+  z-index: 10000 !important;
12
+}
11 13
 .upload-img-preview .ant-modal-close {
12 14
   top: -10px;
13 15
   right: -15px;
@@ -22,6 +24,7 @@
22 24
 .ant-upload-list-item-info {
23 25
   display: flex;
24 26
   align-items: center;
27
+  justify-content: center;
25 28
 }
26 29
 
27 30
 .upload-close-icon {

+ 1
- 1
lib/components/Editor/Upload.js Целия файл

@@ -237,7 +237,7 @@ var App = function (_React$Component) {
237 237
         _react2.default.createElement(
238 238
           _modal2.default,
239 239
           {
240
-            className: "upload-img-preview",
240
+            wrapClassName: "upload-img-preview",
241 241
             visible: previewVisible,
242 242
             footer: null,
243 243
             onCancel: this.handleCancel

+ 1
- 1
lib/components/Editor/Upload.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 5
- 3
lib/components/Editor/index.js Целия файл

@@ -86,9 +86,9 @@ var Editor = function (_React$Component) {
86 86
 
87 87
     _this.state = {
88 88
       showUpload: false,
89
-      value: "", // 编辑器里面的值
89
+      value: props.value, // 编辑器里面的值
90 90
 
91
-      fileList: [], // 图片列表
91
+      fileList: props.fileList, // 图片列表
92 92
       fileMap: {} // 已经上传的图片路径和 uid 的映射 { uid: path }
93 93
     };
94 94
     _this.handleChange = _this.handleChange.bind(_this);
@@ -302,7 +302,7 @@ var Editor = function (_React$Component) {
302 302
       var placeholder = this.props.placeholder || _reactIntlUniversal2.default.get("editor.placeholder");
303 303
       var btnSubmitText = this.props.btnSubmitText || _reactIntlUniversal2.default.get("editor.SubmitBtn");
304 304
       var handleSubmit = this.handleSubmit;
305
-      var disabledSubmit = btnDisabled || !this.props.value && !this.state.value && !this.state.fileList.length;
305
+      var disabledSubmit = btnDisabled || !this.props.value && !this.state.value && !this.props.fileList.length && !this.state.fileList.length;
306 306
       var inputValue = value || this.state.value;
307 307
       var uploadFileList = fileList || this.state.fileList;
308 308
       return _react2.default.createElement(
@@ -484,6 +484,8 @@ Editor.defaultProps = {
484 484
   uploadPopoverPlacement: "bottomLeft",
485 485
   uploadOverlayClassName: "",
486 486
   maxUpload: 1,
487
+  value: "",
488
+  fileList: [],
487 489
   // btnSubmitText: "发表",
488 490
   btnLoading: false,
489 491
   btnDisabled: false,

+ 1
- 1
lib/components/Editor/index.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 16
- 2
lib/index.js Целия файл

@@ -35,7 +35,8 @@ var Index = function (_React$Component) {
35 35
     var _this = _possibleConstructorReturn(this, (Index.__proto__ || Object.getPrototypeOf(Index)).call(this, props));
36 36
 
37 37
     _this.state = {
38
-      fileList: []
38
+      fileList: [],
39
+      value: ""
39 40
     };
40 41
     return _this;
41 42
   }
@@ -58,7 +59,14 @@ var Index = function (_React$Component) {
58 59
           autoFocus: true
59 60
         }, this.props.editorProps, {
60 61
           fileList: this.state.fileList,
62
+          value: this.state.value,
63
+          onChange: function onChange(value) {
64
+            _this2.setState({
65
+              value: value
66
+            });
67
+          },
61 68
           handleChangeFileList: function handleChangeFileList(fileList) {
69
+            console.log(fileList);
62 70
             _this2.setState({
63 71
               fileList: fileList
64 72
             });
@@ -136,6 +144,7 @@ if (process.env.NODE_ENV !== "production") {
136 144
       }
137 145
     },
138 146
     showHoverCard: true,
147
+    showEdit: true,
139 148
     userAvaClick: function userAvaClick(id) {
140 149
       console.log("userAvaClick", id);
141 150
     },
@@ -154,13 +163,18 @@ if (process.env.NODE_ENV !== "production") {
154 163
         resolve();
155 164
       });
156 165
     },
157
-
158 166
     onCountChange: function onCountChange(c) {
159 167
       console.log(c);
160 168
     },
161 169
     onDelete: function onDelete(type, data) {
162 170
       console.log(type, data);
163 171
     },
172
+    onUpdateComment: function onUpdateComment(type, data) {
173
+      console.log("onUpdateComment", type);
174
+    },
175
+    onBeforeUpdateComment: function onBeforeUpdateComment() {
176
+      console.log("onBeforeUpdateComment");
177
+    },
164 178
     editorProps: {
165 179
       onCommentSuccess: function onCommentSuccess(data) {
166 180
         console.log(data);

+ 1
- 1
lib/index.js.map
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 3
- 3
lib/version.json Целия файл

@@ -1,8 +1,8 @@
1 1
 {
2 2
     "name":       "comment",
3
-    "buildDate":  1563590515482,
3
+    "buildDate":  1564144081929,
4 4
     "version":    "1.0.4",
5
-    "numCommits": 169,
6
-    "hash":       "d78b943",
5
+    "numCommits": 172,
6
+    "hash":       "aef6d87",
7 7
     "dirty":      true
8 8
 }

+ 116
- 6
src/App.js Целия файл

@@ -1,6 +1,6 @@
1 1
 import React, { Component } from "react";
2 2
 import PropTypes from "prop-types";
3
-import { message } from "antd";
3
+import { message, Modal, Icon } from "antd";
4 4
 import axios from "axios";
5 5
 import Cookies from "js-cookie";
6 6
 import intl from "react-intl-universal";
@@ -11,6 +11,7 @@ import CommentInput from "./components/CommentInput";
11 11
 import CommentList from "./components/CommentList";
12 12
 import Editor from "./components/Editor";
13 13
 import RenderText from "./components/RenderText";
14
+import EditComment from "./components/EditComment/EditComment";
14 15
 import { SUPPORT_LOCALES, LOCALES_RESPONSE } from "./lang";
15 16
 import "./App.css";
16 17
 
@@ -30,10 +31,18 @@ class App extends Component {
30 31
       // 是否没有更多评论了
31 32
       isNoMoreComment: false,
32 33
       initDone: false,
33
-      locale: "zh-CN"
34
+      locale: "zh-CN",
35
+      editModalVisible: false,
36
+      action: "",
37
+      replyId: "",
38
+      commentId: "",
39
+      userId: "",
40
+      content: "",
41
+      replyPage: 1
34 42
     };
35 43
     this.handleChangeLoading = this.handleChangeLoading.bind(this);
36 44
     this.sCreateComment = this.sCreateComment.bind(this);
45
+    this.sUpdateComment = this.sUpdateComment.bind(this);
37 46
     this.sDeleteComment = this.sDeleteComment.bind(this);
38 47
     this.sCommentFavor = this.sCommentFavor.bind(this);
39 48
     this.sCreateReply = this.sCreateReply.bind(this);
@@ -42,7 +51,10 @@ class App extends Component {
42 51
     this.sGetComment = this.sGetComment.bind(this);
43 52
     this.sReplyFavor = this.sReplyFavor.bind(this);
44 53
     this.sGetReply = this.sGetReply.bind(this);
54
+    this.sUpdateReply = this.sUpdateReply.bind(this);
45 55
     this.sOssSts = this.sOssSts.bind(this);
56
+    this.handleEdit = this.handleEdit.bind(this);
57
+    this.handleClose = this.handleClose.bind(this);
46 58
   }
47 59
 
48 60
   componentWillMount() {
@@ -102,6 +114,28 @@ class App extends Component {
102 114
       });
103 115
   }
104 116
 
117
+  handleEdit({ replyId, commentId, userId, content, replyPage }) {
118
+    this.setState({
119
+      editModalVisible: true,
120
+      action: content.replies
121
+        ? "comment"
122
+        : content.reply
123
+        ? "replyToReply"
124
+        : "reply",
125
+      replyId,
126
+      commentId,
127
+      userId,
128
+      content,
129
+      replyPage
130
+    });
131
+  }
132
+
133
+  handleClose() {
134
+    this.setState({
135
+      editModalVisible: false
136
+    });
137
+  }
138
+
105 139
   error(msg, info = {}) {
106 140
     if (this.props.showError) {
107 141
       message.error(msg);
@@ -287,7 +321,39 @@ class App extends Component {
287 321
         this.handleChangeLoading("sDeleteComment", false);
288 322
       });
289 323
   }
290
-
324
+  /**
325
+   * 更新评论
326
+   * @param {object} {content} comment content
327
+   */
328
+  sUpdateComment({ commentId, content }) {
329
+    this.handleChangeLoading("sUpdateComment", true);
330
+    const { API } = this.props;
331
+    this.axios(`${API}/comments/${commentId}`, {
332
+      method: "post",
333
+      data: {
334
+        content
335
+      },
336
+      withCredentials: true
337
+    })
338
+      .then(() => {
339
+        let { list } = this.state;
340
+        list = list.map(it => {
341
+          if (it.id === commentId) {
342
+            return {
343
+              ...it,
344
+              content
345
+            };
346
+          }
347
+          return it;
348
+        });
349
+        this.props.onUpdateComment("comment");
350
+        this.setState({ list });
351
+      })
352
+      .catch(this.errorHandler)
353
+      .finally(() => {
354
+        this.handleChangeLoading("sUpdateComment", false);
355
+      });
356
+  }
291 357
   /**
292 358
    * 添加回复
293 359
    * 回复评论/回复回复
@@ -360,7 +426,33 @@ class App extends Component {
360 426
         this.handleChangeLoading("sDeleteReply", false);
361 427
       });
362 428
   }
363
-
429
+  /**
430
+   * 更新回复
431
+   * 回复评论/回复回复
432
+   * @param {object} data { comment_id, content, reply_id }
433
+   */
434
+  sUpdateReply({ commentId, content, replyId, replyPage }) {
435
+    this.handleChangeLoading("sUpdateReply", true);
436
+    const { API } = this.props;
437
+    this.axios(`${API}/replies/${replyId}`, {
438
+      method: "post",
439
+      data: {
440
+        comment_id: commentId,
441
+        content
442
+      },
443
+      withCredentials: true
444
+    })
445
+      .then(() => {
446
+        for (let i = 1; i <= replyPage; i++) {
447
+          this.sGetReply({ commentId, page: i });
448
+        }
449
+        this.props.onUpdateComment("reply");
450
+      })
451
+      .catch(this.errorHandler)
452
+      .finally(() => {
453
+        this.handleChangeLoading("sUpdateReply", false);
454
+      });
455
+  }
364 456
   /**
365 457
    * 评论 点赞/取消点赞
366 458
    * @param {string} commentId { commentId }
@@ -473,9 +565,11 @@ class App extends Component {
473 565
       sGetReply: this.sGetReply,
474 566
       sOssSts: this.sOssSts,
475 567
       sDeleteComment: this.sDeleteComment,
476
-      sDeleteReply: this.sDeleteReply
568
+      sDeleteReply: this.sDeleteReply,
569
+      sUpdateReply: this.sUpdateReply,
570
+      sUpdateComment: this.sUpdateComment,
571
+      handleEdit: this.handleEdit
477 572
     };
478
-
479 573
     return (
480 574
       this.state.initDone && (
481 575
         <CommentContext.Provider value={value}>
@@ -489,6 +583,18 @@ class App extends Component {
489 583
               </div>
490 584
             )}
491 585
           </div>
586
+          {this.state.editModalVisible && (
587
+            <EditComment
588
+              visible={this.state.editModalVisible}
589
+              action={this.state.action}
590
+              replyId={this.state.replyId}
591
+              replyPage={this.state.replyPage}
592
+              commentId={this.state.commentId}
593
+              userId={this.state.content.user_id}
594
+              content={this.state.content}
595
+              handleClose={this.handleClose}
596
+            />
597
+          )}
492 598
         </CommentContext.Provider>
493 599
       )
494 600
     );
@@ -514,6 +620,7 @@ App.propTypes = {
514 620
   onPageChange: PropTypes.func, // 页码变化回调
515 621
   onGetMoreBtnClick: PropTypes.func, // 点击查看更多按钮回调
516 622
   onDelete: PropTypes.func,
623
+  onUpdateComment: PropTypes.func,
517 624
   locales: PropTypes.string, //  传入的语言环境, en-US/zh-CN
518 625
   onCountChange: PropTypes.func // 评论数量变更时的回调
519 626
 };
@@ -527,11 +634,14 @@ App.defaultProps = {
527 634
   showAlertReply: false,
528 635
   showAlertFavor: false,
529 636
   showError: true,
637
+  showEdit: false,
530 638
   pageType: "more",
531 639
   limit: LIMIT,
532 640
   onGetMoreBtnClick: () => {},
533 641
   onPageChange: page => {},
534 642
   onDelete: () => {},
643
+  onUpdateComment: () => {},
644
+  onReforeUpdateComment: () => {},
535 645
   onCountChange: () => {}
536 646
 };
537 647
 

BIN
src/assert/icon_answer@2x.png Целия файл


BIN
src/assert/icon_delete.png Целия файл


BIN
src/assert/icon_like@2x.png Целия файл


+ 3
- 0
src/components/CommentBox/index.js Целия файл

@@ -60,6 +60,7 @@ class CommentBox extends Component {
60 60
                   content={item}
61 61
                   user_id={item.user_id}
62 62
                   action="replyToReply" // 回复的回复
63
+                  page={this.state.page}
63 64
                 />,
64 65
                 <div className="comment-more-box" key="show_more_button">
65 66
                   {!isNoMoreReply && replyCount !== len && (
@@ -87,6 +88,7 @@ class CommentBox extends Component {
87 88
                 key={item.id}
88 89
                 content={item}
89 90
                 action="replyToReply" // 评论的回复
91
+                page={this.state.page}
90 92
               />
91 93
             );
92 94
           })}
@@ -108,6 +110,7 @@ class CommentBox extends Component {
108 110
           commentId={content.id}
109 111
           user_id={user_id}
110 112
           action="reply" // 评论的回复
113
+          page={this.state.page}
111 114
         />
112 115
         {this.renderReplies(
113 116
           content.replies,

+ 39
- 3
src/components/ContentItem/index.css Целия файл

@@ -34,7 +34,10 @@
34 34
 }
35 35
 
36 36
 .comment-item-bottom {
37
+  display: flex;
38
+  justify-content: flex-end;
37 39
   margin: 20px auto;
40
+  line-height: 18px;
38 41
 }
39 42
 
40 43
 .comment-item-bottom-left {
@@ -43,11 +46,44 @@
43 46
 }
44 47
 
45 48
 .comment-item-bottom-right {
46
-  float: right;
47
-  margin-left: 5px;
48 49
   cursor: pointer;
49 50
 }
50
-
51
+.comment-item-divider {
52
+  width: 2px;
53
+  height: 24px;
54
+  background: #c6c6c6;
55
+  margin-top: -2px;
56
+}
57
+.comment-item-delete,
58
+.comment-item-edit,
59
+.comment-item-like {
60
+  display: inline-block;
61
+  background: url(../../assert/icon_delete.png);
62
+  width: 18px;
63
+  height: 18px;
64
+  background-size: 100% 100%;
65
+  cursor: pointer;
66
+}
67
+.comment-item-delete {
68
+  margin-right: 18px;
69
+}
70
+.comment-item-edit {
71
+  background: url(../../assert/icon_answer@2x.png);
72
+  background-size: 100% 100%;
73
+  margin-right: 18px;
74
+  margin-left: 10px;
75
+}
76
+.comment-item-like {
77
+  background: url(../../assert/icon_like@2x.png);
78
+  background-size: 100% 100%;
79
+  margin-left: 15px;
80
+  margin-right: 2px;
81
+}
82
+.comment-item-reply {
83
+  margin-left: 20px;
84
+  cursor: pointer;
85
+  color: red;
86
+}
51 87
 .comment-favor {
52 88
   font-size: 20px;
53 89
 }

+ 34
- 23
src/components/ContentItem/index.js Целия файл

@@ -100,10 +100,10 @@ class CommentItem extends Component {
100 100
       showReply,
101 101
       onShowReply,
102 102
       app,
103
-      user_id
103
+      user_id,
104
+      page
104 105
     } = this.props;
105
-
106
-    const { locale, showHoverCard } = this.props.app;
106
+    const { locale, showHoverCard, showEdit } = this.props.app;
107 107
     const { showInput } = this.state;
108 108
 
109 109
     let newContent = content.content;
@@ -262,6 +262,21 @@ class CommentItem extends Component {
262 262
                 </a>
263 263
               </div>
264 264
             ) : null}
265
+            {showEdit && (
266
+              <i
267
+                className="comment-item-edit"
268
+                onClick={() =>
269
+                  this.props.app.handleEdit({
270
+                    action,
271
+                    replyId,
272
+                    commentId,
273
+                    userId: content.user_id,
274
+                    content,
275
+                    replyPage: page
276
+                  })
277
+                }
278
+              />
279
+            )}
265 280
             {app.userId === content.user_id && (
266 281
               <Popconfirm
267 282
                 // title="确定要删除吗?"
@@ -276,17 +291,13 @@ class CommentItem extends Component {
276 291
                 okText={intl.get("popConfirm.ok")}
277 292
                 cancelText={intl.get("popConfirm.cancel")}
278 293
               >
279
-                <a className="comment-item-bottom-right">
294
+                {/* <a className="comment-item-bottom-right">
280 295
                   &nbsp; {intl.get("popConfirm.delete")}
281
-                </a>
296
+                </a> */}
297
+                <i className="comment-item-delete" />
282 298
               </Popconfirm>
283 299
             )}
284
-            <a
285
-              onClick={this.handleToggleInput}
286
-              className="comment-item-bottom-right"
287
-            >
288
-              &nbsp; {intl.get("comment.reply")}
289
-            </a>
300
+            <span className="comment-item-divider" />
290 301
             <div
291 302
               className="comment-item-bottom-right"
292 303
               onClick={() => {
@@ -299,16 +310,14 @@ class CommentItem extends Component {
299 310
               }}
300 311
               style={{ color: `${IconColor}` }}
301 312
             >
302
-              <Icon
303
-                type="like-o"
304
-                className={
305
-                  content.favored
306
-                    ? "comment-favor comment-favored"
307
-                    : "comment-favor"
308
-                }
309
-                style={{ color: `${IconColor}` }}
310
-              />
311
-              &nbsp;{content.favor_count}
313
+              <i className="comment-item-like" />
314
+            </div>
315
+            <span>&nbsp;{content.favor_count}</span>
316
+            <div
317
+              onClick={this.handleToggleInput}
318
+              className="comment-item-reply"
319
+            >
320
+              &nbsp; {intl.get("comment.reply")}
312 321
             </div>
313 322
           </div>
314 323
         </div>
@@ -334,12 +343,14 @@ CommentItem.propTypes = {
334 343
   // reply 评论的回复
335 344
   // replyToReply 回复的回复
336 345
   action: PropTypes.oneOf(["comment", "reply", "replyToReply"]),
337
-  onShowReply: PropTypes.func
346
+  onShowReply: PropTypes.func,
347
+  showEdit: PropTypes.bool
338 348
 };
339 349
 
340 350
 CommentItem.defaultProps = {
341 351
   action: "comment",
342
-  onShowReply: () => {}
352
+  onShowReply: () => {},
353
+  showEdit: false
343 354
 };
344 355
 
345 356
 export default Comment(CommentItem);

+ 86
- 0
src/components/EditComment/EditComment.css Целия файл

@@ -0,0 +1,86 @@
1
+.editCommetModal .ant-modal,
2
+.editCommetModal .ant-modal-content {
3
+  width: 608px !important;
4
+  height: 276px;
5
+}
6
+.editCommetModal .ant-modal-body {
7
+  padding: 0;
8
+}
9
+
10
+.editCommetModal .title {
11
+  font-size: 18px;
12
+  color: #4a4a4a;
13
+  padding: 20px 0 0 28px;
14
+}
15
+.editCommetModal .comment-editor {
16
+  border: none;
17
+  padding: 16px 24px;
18
+}
19
+.editCommetModal .comment-editor-toolbar {
20
+  display: none;
21
+}
22
+.editCommetModal .comment-editor:hover,
23
+.editCommetModal .comment-editor:focus {
24
+  border: none;
25
+  outline: none;
26
+  box-shadow: none;
27
+}
28
+.editCommetModal textarea.ant-input {
29
+  border: 1px solid #e1e1e1;
30
+  border-radius: 3px;
31
+  resize: none;
32
+  height: 132px !important;
33
+}
34
+.editCommetModal textarea.ant-input:hover {
35
+  border: 1px solid #e1e1e1;
36
+  border-radius: 3px;
37
+}
38
+.editCommetModal textarea.ant-input:hover,
39
+.editCommetModal textarea.ant-input:focus {
40
+  border-color: #40a9ff;
41
+}
42
+.editCommetModal .comment-toolbar {
43
+  display: flex;
44
+  justify-content: flex-end;
45
+  margin-top: 30px;
46
+}
47
+.editCommetModal .comment-toolbar-left {
48
+  display: flex;
49
+  align-items: center;
50
+  height: 36px;
51
+  margin: 0;
52
+}
53
+.editCommetModal .comment-toolbar-right {
54
+  height: 36px;
55
+  margin: 0;
56
+  margin-left: 20px;
57
+}
58
+.editCommetModal .comment-toolbar-right .ant-btn {
59
+  height: 36px;
60
+}
61
+
62
+.expression-btn-wrap,
63
+.picture-btn-wrap {
64
+  float: left;
65
+  cursor: pointer;
66
+}
67
+.expression-btn-wrap .icon,
68
+.picture-btn-wrap .icon {
69
+  float: left;
70
+  color: #ffa405;
71
+  font-size: 24px !important;
72
+  margin: 0 !important;
73
+}
74
+.expression-btn-wrap .text,
75
+.picture-btn-wrap .text {
76
+  float: left;
77
+  font-size: 16px;
78
+  color: #393939;
79
+  margin-left: 8px;
80
+}
81
+.picture-btn-wrap {
82
+  margin-left: 28px;
83
+}
84
+.picture-btn-wrap .icon {
85
+  color: rgba(113, 193, 53, 1);
86
+}

+ 142
- 0
src/components/EditComment/EditComment.js Целия файл

@@ -0,0 +1,142 @@
1
+import React from "react";
2
+import PropTypes from "prop-types";
3
+import { Modal, Icon } from "antd";
4
+import intl from "react-intl-universal";
5
+import CommentInput from "../CommentInput";
6
+import Editor from "../Editor";
7
+import { IMAGE_SPLIT } from "../../constant";
8
+import "./EditComment.css";
9
+import Comment from "../../Comment";
10
+class EditComment extends React.Component {
11
+  constructor(props) {
12
+    super(props);
13
+    this.handleSubmit = this.handleSubmit.bind(this);
14
+    this.state = {
15
+      value: this.getInitValue(props).value,
16
+      fileList: this.getInitValue(props).fileList
17
+    };
18
+  }
19
+
20
+  handleSubmit({ text = "", files = [] }) {
21
+    const { fileList } = this.state;
22
+    const { app, action, commentId, replyId, replyPage } = this.props;
23
+    let value = text;
24
+    app.onBeforeUpdateComment();
25
+    if (fileList && fileList.length) {
26
+      value += IMAGE_SPLIT;
27
+      fileList.forEach(file => {
28
+        value += `${file.thumbUrl},`;
29
+      });
30
+    }
31
+    if (value.substr(-1) === ",") {
32
+      value = value.slice(0, -1);
33
+    }
34
+    if (action === "comment") {
35
+      app.sUpdateComment({ commentId, content: value });
36
+    } else {
37
+      app.sUpdateReply({ commentId, content: value, replyId, replyPage });
38
+    }
39
+    this.props.handleClose();
40
+  }
41
+
42
+  getInitValue(props) {
43
+    const { content } = props;
44
+    let newContent = content.content;
45
+    let images = "";
46
+    if (newContent.indexOf(IMAGE_SPLIT) !== -1) {
47
+      newContent = newContent.split(IMAGE_SPLIT);
48
+      images = newContent.pop();
49
+      newContent = newContent.join("");
50
+    }
51
+    let fileList = [];
52
+    if (images !== "") {
53
+      fileList = images.split(",");
54
+      fileList = fileList.map((item, index) => {
55
+        return {
56
+          thumbUrl: item,
57
+          uid: index
58
+        };
59
+      });
60
+    }
61
+    const value = this.renderTextWithReply(newContent, content);
62
+    return { value, fileList };
63
+  }
64
+
65
+  getEmojiToolIcon() {
66
+    return (
67
+      <div className="expression-btn-wrap">
68
+        <Icon type="smile" className="icon" />
69
+        <span className="text">{intl.get("bilingually.emoji")}</span>
70
+      </div>
71
+    );
72
+  }
73
+
74
+  getImageToolIcon() {
75
+    return (
76
+      <div className="picture-btn-wrap">
77
+        <Icon type="picture" className="icon" />
78
+        <span className="text">{intl.get("bilingually.pic")}</span>
79
+      </div>
80
+    );
81
+  }
82
+
83
+  renderTextWithReply(text, content) {
84
+    let newText = text;
85
+    // const { reply } = content;
86
+    // if (reply) {
87
+    //   newText = `${newText} //@${reply.user_name} ${reply.content}`;
88
+    //   if (reply.reply) {
89
+    //     return this.renderTextWithReply(newText, reply);
90
+    //   }
91
+    // }
92
+    return newText;
93
+  }
94
+
95
+  render() {
96
+    return (
97
+      <Modal
98
+        visible={true}
99
+        footer={null}
100
+        wrapClassName="editCommetModal"
101
+        onCancel={this.props.handleClose}
102
+      >
103
+        <div className="title">
104
+          {intl.get("bilingually.imgtxt.edit_imgtxt")}
105
+        </div>
106
+        <CommentInput
107
+          content={
108
+            <Editor
109
+              maxUpload={9}
110
+              autoFocus
111
+              // {...this.props.editorProps}
112
+              action={this.props.action}
113
+              replyId={this.props.replyId}
114
+              commentId={this.props.commentId}
115
+              userId={this.props.content.user_id}
116
+              fileList={this.state.fileList}
117
+              value={this.state.value}
118
+              onChange={value => {
119
+                this.setState({
120
+                  value
121
+                });
122
+              }}
123
+              handleChangeFileList={fileList => {
124
+                this.setState({
125
+                  fileList
126
+                });
127
+              }}
128
+              onSubmit={this.handleSubmit}
129
+              emojiToolIcon={this.getEmojiToolIcon()}
130
+              imageToolIcon={this.getImageToolIcon()}
131
+              emojiPopoverPlacement="bottom"
132
+              uploadPopoverPlacement="bottom"
133
+              btnSubmitText={intl.get("bilingually.imgtxt.update")}
134
+            />
135
+          }
136
+        />
137
+      </Modal>
138
+    );
139
+  }
140
+}
141
+
142
+export default Comment(EditComment);

+ 4
- 1
src/components/Editor/Upload.css Целия файл

@@ -7,7 +7,9 @@
7 7
   margin-top: 8px;
8 8
   color: #666;
9 9
 }
10
-
10
+.upload-img-preview {
11
+  z-index: 10000 !important;
12
+}
11 13
 .upload-img-preview .ant-modal-close {
12 14
   top: -10px;
13 15
   right: -15px;
@@ -22,6 +24,7 @@
22 24
 .ant-upload-list-item-info {
23 25
   display: flex;
24 26
   align-items: center;
27
+  justify-content: center;
25 28
 }
26 29
 
27 30
 .upload-close-icon {

+ 1
- 1
src/components/Editor/Upload.js Целия файл

@@ -153,7 +153,7 @@ class App extends React.Component {
153 153
           );
154 154
         })}
155 155
         <Modal
156
-          className="upload-img-preview"
156
+          wrapClassName="upload-img-preview"
157 157
           visible={previewVisible}
158 158
           footer={null}
159 159
           onCancel={this.handleCancel}

+ 8
- 3
src/components/Editor/index.js Целия файл

@@ -16,9 +16,9 @@ class Editor extends React.Component {
16 16
     super(props);
17 17
     this.state = {
18 18
       showUpload: false,
19
-      value: "", // 编辑器里面的值
19
+      value: props.value, // 编辑器里面的值
20 20
 
21
-      fileList: [], // 图片列表
21
+      fileList: props.fileList, // 图片列表
22 22
       fileMap: {} // 已经上传的图片路径和 uid 的映射 { uid: path }
23 23
     };
24 24
     this.handleChange = this.handleChange.bind(this);
@@ -204,7 +204,10 @@ class Editor extends React.Component {
204 204
     const handleSubmit = this.handleSubmit;
205 205
     const disabledSubmit =
206 206
       btnDisabled ||
207
-      (!this.props.value && !this.state.value && !this.state.fileList.length);
207
+      (!this.props.value &&
208
+        !this.state.value &&
209
+        !this.props.fileList.length &&
210
+        !this.state.fileList.length);
208 211
     const inputValue = value || this.state.value;
209 212
     const uploadFileList = fileList || this.state.fileList;
210 213
     return (
@@ -395,6 +398,8 @@ Editor.defaultProps = {
395 398
   uploadPopoverPlacement: "bottomLeft",
396 399
   uploadOverlayClassName: "",
397 400
   maxUpload: 1,
401
+  value: "",
402
+  fileList: [],
398 403
   // btnSubmitText: "发表",
399 404
   btnLoading: false,
400 405
   btnDisabled: false,

+ 16
- 2
src/index.js Целия файл

@@ -7,7 +7,8 @@ class Index extends React.Component {
7 7
   constructor(props) {
8 8
     super(props);
9 9
     this.state = {
10
-      fileList: []
10
+      fileList: [],
11
+      value: ""
11 12
     };
12 13
   }
13 14
 
@@ -25,7 +26,14 @@ class Index extends React.Component {
25 26
           autoFocus
26 27
           {...this.props.editorProps}
27 28
           fileList={this.state.fileList}
29
+          value={this.state.value}
30
+          onChange={value => {
31
+            this.setState({
32
+              value
33
+            });
34
+          }}
28 35
           handleChangeFileList={fileList => {
36
+            console.log(fileList);
29 37
             this.setState({
30 38
               fileList
31 39
             });
@@ -101,6 +109,7 @@ if (process.env.NODE_ENV !== "production") {
101 109
       }
102 110
     },
103 111
     showHoverCard: true,
112
+    showEdit: true,
104 113
     userAvaClick: id => {
105 114
       console.log("userAvaClick", id);
106 115
     },
@@ -119,13 +128,18 @@ if (process.env.NODE_ENV !== "production") {
119 128
         resolve();
120 129
       });
121 130
     },
122
-
123 131
     onCountChange: c => {
124 132
       console.log(c);
125 133
     },
126 134
     onDelete: (type, data) => {
127 135
       console.log(type, data);
128 136
     },
137
+    onUpdateComment: (type, data) => {
138
+      console.log("onUpdateComment", type);
139
+    },
140
+    onBeforeUpdateComment: () => {
141
+      console.log("onBeforeUpdateComment");
142
+    },
129 143
     editorProps: {
130 144
       onCommentSuccess: data => {
131 145
         console.log(data);