# MComment 评论

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/mobile/comment/freepass)
- 平台：移动端
- 维护者：王斌
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[MComment]

## 代码演示

### 基础用法

直接引入组件进行使用

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils, MMoreOptionType, ReplyOption } from '@weapp/ui';

const { formatParentPath } = utils;

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onRefresh = () => {
    this.ref.current && this.ref.current.onRefresh();
  }

  render() {

    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"share"}
          objectModule="bcw"
          targetId="752714034012356609"
         
          wrappedComponentRef={this.ref}
        />
        <Button onClick={this.onRefresh} >刷新</Button>
      </div>
    )
  }
}

export default Basic;
```

### 带有点赞功能的评论组件

直接引入组件进行使用

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils, MMoreOptionType } from '@weapp/ui';

const { formatParentPath } = utils;

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onRefresh = () => {
    this.ref.current && this.ref.current.onRefresh();
  }

  render() {
    const moreOPtions: MMoreOptionType[] = [
      {
        content: '回复', optionType: 'reply', onClick: function (option: any) {
          console.log(option)
        }
      },
      { optionType: 'task', content: '转任务' },
      { content: '编辑', optionType: 'edit' },
      { content: '取消', optionType: 'cancel' }]

    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"document"}
          objectModule="doc"
         
          style={{ height: "100%" }}
          targetId="1362372473190223857"
          wrappedComponentRef={this.ref}
          moreOptions={moreOPtions}
          optionConfig={['task','reply','upvote','edit','more']}
        />
        <Button onClick={this.onRefresh} >刷新</Button>
      </div>
    )
  }
}

export default Basic;
```

### 日报模块特有的的点赞列表

通过voteListModule={'blog'}进行配置

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils ,MMoreOptionType} from '@weapp/ui';

const { formatParentPath } = utils;

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onRefresh = () => {
    this.ref.current && this.ref.current.onRefresh();
  }

  render() {
    const moreOPtions: MMoreOptionType[]= [
      {
        content: '回复', optionType: 'reply', onClick: function (option: any) {
          console.log(option)
        }
      },
      { optionType: 'task', content: '转任务' },
      { content: '编辑', optionType: 'edit' },
      { content: '取消', optionType: 'cancel' }]

    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"document"}
          objectModule="doc"
         
          style={{ height: "100%" }}
          targetId="1362372473190223857"
          wrappedComponentRef={this.ref}
          moreOptions={moreOPtions}
          voteListModule={'blog'}
        />
        <Button onClick={this.onRefresh} >刷新</Button>
      </div>
    )
  }
}

export default Basic;
```

### API的使用

各种API的使用方法

```jsx
import React from 'react';
import { Icon, MAvatar, MComment, MButton, ReplyOption } from '@weapp/ui';

interface StateType {
}

export default class Basic extends React.Component<any, StateType> {

  constructor(props: any) {
    super(props);
    this.state = {
    }
  }

  commentRef = React.createRef<any>();

  onClick = () => {
    this.setState({ key: "main" });
  }

  onChange = (value: string) => {
    this.setState({ key: value });
  }

  onSubmit = (value: string) => {
    console.log(value)
  }

  onReplySubmit = (value: string, data: ReplyOption) => {
    console.log(value)
  }

  onInputChange = (value: React.ReactText) => {
    this.setState({ value });
  }

  // 提交完成后清空文本框
  onEditSubmitted = () => {
    this.setState({ value: "" })
  }

  onReplyClick = (data: ReplyOption) => {
    console.log(data)
  }

  onRefresh = () => {
    this.commentRef.current && this.commentRef.current.refresh()
  }

  renderMore = () => {
    return (
      <div>
        这里是添加的更多内容
      </div>
    )
  }

  renderReplyHeader = (data: ReplyOption) => {
    return <span>回复内容</span>
  }

  renderEditOptions = () => {
    return [
      <Icon name="Icon-global-search" />,
      <Icon name="Icon-task" />,
    ]
  }

  renderItemFooterInfo = (data: ReplyOption) => {
    return <span style={{ paddingLeft: 10 }}>额外底部信息</span>
  }

  renderItemHeaderInfo = (data: ReplyOption) => {
    return <span>这是添加的header</span>
  }

  renderCommentContent = (data: ReplyOption) => {
    return <span>这是添加的comment</span>
  }

  getScrollContainer = (): HTMLElement => document.querySelector("[weId='_ee7t5o_g75igp_1nkm5j_zls063@21_elsk42_gk249j']") as HTMLElement;

  customAvatarUrl = (data: ReplyOption) => {
    if (data.id === "3572737175779873945") return "/api/file/preview?type=redirect&fileId=7832692480228392907"
    return null;
  }

  onReplyCancel = (data: ReplyOption, key: string) => {
    return new Promise<any>((resolve) => {
      resolve({})
    })
  }

  renderTop = (data?: ReplyOption) => {
    console.log(data)
    return (
      <div>
        自定义顶部内容，评论id({data?.id || ""})
      </div>
    )
  }

  renderContentFooter = (data: any) => {
    return `评论内容底部`
  }

  renderContentHeader = (data: any) => {
    return `评论内容顶部`
  }

  customAvatar = (com: React.ReactNode, data: ReplyOption) => {
    console.log(data)
    if (data.id === "3572806175025496006") {
      return (
        <MAvatar
          name={"替换头像"}
        />
      )
    }
    return com;
  }

  render() {
    return (
      <div>
        <MComment
         
          wrappedComponentRef={this.commentRef}
          commentUrl="/api/doc/common/comment/commentPage"
          createUrl="/api/doc/common/comment/createComment"
          updataUrl="/api/doc/common/comment/updateComment"
          viewUrl="/api/doc/stream/readinfo.json"
          taskUrl="/api/task/task/transmit"
          // deleteRelevanceUrl="/api/doc/common/comment/deleteCommentRelevance.common"
          // commentCommentedUrl="/api/doc/common/comment/commentCommented"
          module={"document"}
          objectModule="doc"
          renderTop={this.renderTop}
          extendsActionConfig={[{
            id: "001",
            icon: "Icon--Instructions"
          }]}
          style={{ height: "100%" }}
          targetId="3573031474186044663"
          viewParams={{
            id: "1564647864693947289"
          }}
          usePosition={false}
          optionConfig={[
            "edit",
            {
              id: "reply",
              onClick: this.onReplyClick
            },
            "task",
          ]}
          updataParams={{
            // relevanceList: [],
            // subtargetId: "",
            // userIdIndex: "",
            // userIds: "",
            // commentRels: [],
          }}
          actionConfig={["upload", "emoticon", "associated", "at", "picture"]}
          customAvatar={this.customAvatar}
          renderCommentContent={this.renderCommentContent}
          getScrollContainer={this.getScrollContainer}
          renderReplyHeader={this.renderReplyHeader}
          renderContentFooter={this.renderContentFooter}
          renderContentHeader={this.renderContentHeader}
          renderItemFooterInfo={this.renderItemFooterInfo}
          renderItemHeaderInfo={this.renderItemHeaderInfo}
          customAvatarUrl={this.customAvatarUrl}
          paginationType="more"
          onReplySubmit={this.onReplySubmit}
          onEditSubmitted={this.onEditSubmitted}
          onReplyCancel={this.onReplyCancel}
          disableAt
          hasCommentSearch
          hasCommentSort
          hasEchart
          usePhrase
          useSignApprove
          useSignature
        />
        <MButton onClick={this.onRefresh}>刷新</MButton>
      </div>
    )
  }
}
```

### 添加评论

直接引入组件进行使用

```jsx
import React from 'react';
import { MComment, MButton } from '@weapp/ui';

const { MCommentEdit } = MComment;

class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onSubmit = (value: string) => {
    console.log(value)
  }

  onCancel = () => {
    console.log("cancel")
  }

  customRenderText = (com: any, data: any) => {
    return (
      <div>
        自定义顶部内容{data?.id}
        {com}
      </div>
    )
  }
  
  render() {
    return (
      <div>
        <MCommentEdit

         
          createUrl="/api/cowork/common/comment/createComment"
          onSubmit={this.onSubmit}
          onCancel={this.onCancel}
          module={"cowork"}
          // ref={}
          targetId="4341580164279439928"
          usePrivated
          usePhrase
          customActionConfigLength={3}
        />
      </div>
    )
  }
}

export default Basic;
```

### 评论列表

直接引入组件进行使用

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { MComment, utils } from '@weapp/ui';

const { formatParentPath } = utils;
const { MCommentMenu } = MComment;

interface PropsType extends RouteComponentProps{

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  render() {
    return (
      <div>
        <MCommentMenu
         
          defaultActiveKey={"main"}
          createUrl="/api/doc/common/comment/createComment"
          updataUrl="/api/doc/common/comment/updateComment"
          module={"document"}
          objectModule="doc"
          menu={[{
            id: "main",
            content: "评论",
            url: "/api/doc/common/comment/commentPage",
            urlParams: {"id":"1361715441145981309","module":"document","method":"others","loadCount":false}
          }, {
            id: "other",
            content: "其他评论",
            url: "/api/doc/common/comment/commentPage",
            urlParams: {"module":"document","method":"others","loadCount":false},
            showType: "card"
          }, {
            id: "test",
            content: "测试评论",
            url: "/api/doc/common/comment/commentPage",
          }]}
          targetId="4341580164279439928"
          path={this.path}
        />
      </div>
    )
  }
}

export default Basic;
```

### 查阅情况

直接引入组件进行使用

```jsx
import React from 'react';
import { MComment, MButton } from '@weapp/ui';

const { MCommentViewLog } = MComment;

class Basic extends React.Component<any, any> {

  render() {
    return (
      <div style={{position: "fixed", width: "100%", height: "100%"}}>
        <MCommentViewLog
         
          module="document"
          objectModule='doc'
          targetId="3572703178680554783"
          viewPagination
        />
      </div>
    )
  }
}

export default Basic;
```

### 滚动加载

组件不固定高度实现滚动加载的方法

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils } from '@weapp/ui';

const { formatParentPath } = utils;

interface PropsType extends RouteComponentProps{

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();
  containerRef = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onRefresh = () => {
    this.ref.current && this.ref.current.onRefresh();
  }

  // 获取外部滚动容器的dom
  getScrollContainer = (): HTMLElement => this.containerRef.current as HTMLElement;

  render() {
    return (
      <>
        <div ref={this.containerRef} style={{height: document.body.offsetHeight - 40, overflow: "auto"}}>
          <MComment
           
            commentUrl="/api/doc/common/comment/commentPage"
            createUrl="/api/doc/common/comment/createComment"
            updataUrl="/api/doc/common/comment/updateComment"
            module={"document"}
            getScrollContainer={this.getScrollContainer}
            targetId="4341580164279439928"
            path={this.path}
            paginationType="scroll"
            wrappedComponentRef={this.ref}
            // optionConfig={["delete"]}
          />
        </div>
        <Button onClick={this.onRefresh} >刷新</Button>
      </>
    )
  }
}

export default Basic;
```

### 折叠使用

直接引入组件进行使用

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils } from '@weapp/ui';

const { formatParentPath } = utils;
const { MCommentGroup } = MComment;

interface PropsType extends RouteComponentProps{

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  render() {
    return (
      <div style={{position: "fixed", width: "100%", height: "100%"}}>
        <MCommentGroup
                   
          // createUrl="/api/doc/common/comment/createComment"
          // updataUrl="/api/doc/common/comment/updateComment"
          module={"document"}
          objectModule="doc"
          groupData={[{
            id: "workflow",
            title: "流程模块",
            url: "/api/workflow/core/common/comment/unread.common",
            urlParams: {"pageNo":1,"pageSize":10,"module":"workflow","id":"6262928986144630834","method":"domainComment","loadCount":false},
            total: null,
          }, {
            id: "task",
            title: "任务模块",
            url: "/api/task/common/comment/atmeComment.common",
            urlParams: {"pageNo":1,"pageSize":10,"id":"6262928986144630834","module":"task","loadCount":true,"method":"atmeComment"}
          }, {
            id: "doc",
            title: "知识模块",
            url: "/api/doc/common/comment/atmeComment.common",
            urlParams: {"pageNo":1,"pageSize":10,"id":"6262928986144630834","module":"document","loadCount":true,"method":"atmeComment"}
          }]}
        />
      </div>
    )
  }
}

export default Basic;
```

### 评论使用富文本框

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { MComment } from '@weapp/ui';

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  render() {
    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"document"}
          objectModule="doc"
         
          style={{ height: "100%" }}
          targetId="1362372473190223855"
          useRichText
        />
      </div>
    )
  }
}

export default Basic;
```

### 单独使用点赞

```jsx
import React from 'react';
import { Button, MComment, MUpvote, MUpvoteList } from '@weapp/ui';

export default class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      upvote: false,
      voteUsers: [],
      isBolg: false,
    }
  }

  onUpvotedChange = (upvoted: boolean) => {
    this.setState({ upvote: upvoted });
  }

  setVoteUsersAndUpvoted = (voteUsers: any[], upvoted: boolean | undefined) => {
    this.setState({ voteUsers });
  }

  onClick = () => {
    this.setState({ isBolg: !this.state.isBolg });
  }

  render() {
    const { upvote, voteUsers, isBolg } = this.state;
    return (
      <div>
        <h3> 点赞状态需要外部保存并传入 </h3>
        <MUpvote
         
          module="doc"
          objectId="1362372473190223857"
          upvoted={upvote}
          onUpvotedChange={this.onUpvotedChange}
          setVoteUsersAndUpvoted={this.setVoteUsersAndUpvoted}
        />
        <div>
          <MUpvoteList
           
            objectId="1362372473190223857"
            voteUsers={voteUsers}
            module="doc"
            upvoted={upvote}
            voteListModule={isBolg ? "blog" : "normal"}
          />
        </div>
        <br />
        <br />
        <Button onClick={this.onClick}>是否展示日报点赞列表</Button>
      </div>
    )
  }
}
```

### 自定义评论操作按钮

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { MComment, ReplyOption, CommentOptionType } from '@weapp/ui';

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  onCustomClick = (data: ReplyOption) => {
    console.log(data)
  }

  customTopicConfig = (data: ReplyOption) => {
    // data 为 当前评论所有数据
    return {
      data: { mid: '123', type: '123', module: '123', minfo: '123', smid: data?.id }, callback: () => {
        console.log(this);
      }
    }
  }

  customOptionConfig = (data: ReplyOption, defaultOption: CommentOptionType[] = []) => {
    console.log({ data, defaultOption });
    return defaultOption;
  }

  render() {
    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"document"}
          objectModule="doc"
          style={{ height: "100%" }}
          targetId="1362372473190223857"
          // 方式一：
          // optionConfig={[
          //   "edit",
          //   "reply",
          //   "task",
          //   'topic',
          //   "upvote",
          //   {
          //     id: 'demo',
          //     iconName: "Icon-smiling-face",
          //     onClick: this.onCustomClick
          //   }
          // ]}
          // 方式二：
          optionConfig={this.customOptionConfig}
          // 方式一：
          // topicConfig={{ data: { mid: '123', type: '123', module: '123', minfo: '123' }, icon: 'Icon-Mac-client' }}
          // 方式二：
          topicConfig={this.customTopicConfig}
        />
      </div>
    )
  }
}

export default Basic;
```

### 自定义按钮

使用 actionConfig 在按钮栏增加自定义按钮，使用 extendsActionConfig 在更多弹窗里增加自定义按钮。

```jsx
import React from "react";
import { MComment } from "@weapp/ui";

const { MCommentEdit } = MComment;

class Basic extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    };
  }

  onSubmit = (value: string) => {
    console.log(value);
  };

  onCancel = () => {
    console.log("cancel");
  };
  renderTop = () => (
    <span>
      <span className="ui-m-comment-textarea-header-tag">手写签批</span>
      <span className="ui-m-comment-textarea-header-tag">电子签名</span>
    </span>
  );
  //   renderOption = () => <>
  //   <Icon name='Icon-lockin-o'/>
  //   <Icon name='Icon-N-Interface-Expiration-Notification'/>
  //   <Icon name='Icon-N-Blacklist-settings'/>
  // </>
  render() {
    return (
      <div>
        <MCommentEdit
         
          createUrl="/api/doc/common/comment/createComment"
          onSubmit={this.onSubmit}
          onCancel={this.onCancel}
          module={"document"}
          targetId="4341580164279439928"
          usePrivated
          usePhrase
          /** 自定义渲染，屏幕底部更多弹框中的按钮 */
          // 当有extendsActionConfig 默认将extendsActionConfig 的内容显示到加号按钮，并将icon显示到加号弹窗内
          extendsActionConfig={[
            {
              id: "1",
              icon: "Icon-Full-text-annotation",
              onClick: () => {
                console.log(1);
              },
              content: "全文批注",
            },
          ]}
          // 如果要显示到按纽栏，则可进行如下设置
          /** 选择，组件自带的评论框底部按钮 */
          actionConfig={[
            "at",
            {
              id: "more",
              icon: 'Icon-AND', //按钮栏显示
              onClick: this.onCancel,
              content: "自定义按钮",
              innerIcon:'Icon-Defaultemoji' //更多弹窗里显示
            },
            "upload",
            "emoticon",
            "recording",
            "voiceToText",
          ]}
          /** 自定义渲染，评论框底部按钮，如果自定义渲染的按钮超过5个，建议放到exTendsActionConfig里 */
          // custonRenderOptions={this.renderOption}
          /** 隐藏更多（➕）按钮 */
          // hiddenMoreBtn
          /** 自定义渲染评论输入框顶部按钮 */
          renderTop={this.renderTop}
        />
      </div>
    );
  }
}

export default Basic;
```

### 评论脱敏设置

评论脱敏设置,可将评论加密显示

```jsx
import React from 'react';
import { MComment, MButton, MMoreOptionType, MDialog, utils } from '@weapp/ui';

const { MCommentEdit } = MComment;
const { formatParentPath } = utils;

class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onSubmit = (value: string) => {
    console.log(value)
  }

  onCancel = () => {
    console.log("cancel")
  }

  toCommentList = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/list`);
  }

  backEdit = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.goBack();
  }

  customRenderText = (com: any, data: any) => {
    return (
      <div>
        自定义顶部内容{data?.id}
        {com}
      </div>
    )
  }

  render() {
    const moreOPtions: MMoreOptionType[] = [
      {
        content: '回复', optionType: 'reply', onClick: function (option: any) {
          console.log(option)
        }
      },
      { optionType: 'task', content: '转任务' },
      { content: '编辑', optionType: 'edit' },
      { content: '取消', optionType: 'cancel' }]
    let parentPath = formatParentPath(this.props as any)

    return (
      <div>
        <MCommentEdit
         
          createUrl="/api/cowork/common/comment/createComment"
          onSubmit={this.onSubmit}
          onCancel={this.onCancel}
          module={"cowork"}
          targetId="752714034012356609"
          usePrivated
          usePhrase
          useDesensitization
        />
        <MButton onClick={this.toCommentList} >查看评论列表</MButton>
        <MDialog
          destroyOnClose
          path={`${parentPath}/list`}
          isRouteLayout={true}
          title={"评论列表"}
        >
          <MButton onClick={this.backEdit} >返回编辑</MButton>
          <MComment
            module={"cowork"}
            objectModule="cowork"
            targetId="752714034012356609"
           
            style={{ height: "100%" }}
            moreOptions={moreOPtions}
            useDesensitization
          />
        </MDialog>
      </div>
    )
  }
}

export default Basic;
```

### 自定义按钮底部渲染区域

使用 renderIconBottom 可以自定义渲染 Icon 底部的内容区域, 使用 renderAudioBottom 可以自定义渲染 Audio 底部的内容区域, 使用 renderAttachmentsTop 可以自定义渲染附件顶部的内容区域

```jsx
import React from 'react';
import { MComment, MButton, MMoreOptionType, MDialog, utils } from '@weapp/ui';

const { MCommentEdit } = MComment;
const { formatParentPath } = utils;

class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onSubmit = (value: string) => {
    console.log(value)
  }

  onCancel = () => {
    console.log("cancel")
  }

  toCommentList = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/list`);
  }

  backEdit = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.goBack();
  }

  customRenderText = (com: any, data: any) => {
    return (
      <div>
        自定义顶部内容{data?.id}
        {com}
      </div>
    )
  }

  renderIconBottom = () => (<div> renderIconBottom</div>)
  renderAudioBottom = () => (<div> renderAudioBottom</div>)
  renderAttachmentsTop = () => (<div> renderAttachmentsTop</div>)
  render() {
    const moreOPtions: MMoreOptionType[] = [
      {
        content: '回复', optionType: 'reply', onClick: function (option: any) {
          console.log(option)
        }
      },
      { optionType: 'task', content: '转任务' },
      { content: '编辑', optionType: 'edit' },
      { content: '取消', optionType: 'cancel' }]
    let parentPath = formatParentPath(this.props as any)

    return (
      <div>
        <MCommentEdit
         
          createUrl="/api/cowork/common/comment/createComment"
          onSubmit={this.onSubmit}
          onCancel={this.onCancel}
          module={"cowork"}
          targetId="752714034012356609"
          usePrivated
          usePhrase
          renderIconBottom={this.renderIconBottom}
          renderAudioBottom={this.renderAudioBottom}
          renderAttachmentsTop={this.renderAttachmentsTop}
        />
        <MButton onClick={this.toCommentList} >查看评论列表</MButton>
        <MDialog
          destroyOnClose
          path={`${parentPath}/list`}
          isRouteLayout={true}
          title={"评论列表"}
        >
          <MButton onClick={this.backEdit} >返回编辑</MButton>
          <MComment
            module={"cowork"}
            objectModule="cowork"
            targetId="752714034012356609"
           
            style={{ height: "100%" }}
            moreOptions={moreOPtions}
            renderIconBottom={this.renderIconBottom}
            renderAudioBottom={this.renderAudioBottom}
            renderAttachmentsTop={this.renderAttachmentsTop}

          />
        </MDialog>
      </div>
    )
  }
}

export default Basic;
```

### 图片上传和附件排序

使用 actionConfig 传入 picture 开启图片上传功能，使用 uploadProps 传入 sortable 开启附件排序功能。

```jsx
import React from 'react';
import { MComment, MButton, MMoreOptionType, MDialog, utils } from '@weapp/ui';

const { MCommentEdit } = MComment;
const { formatParentPath } = utils;

class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onSubmit = (value: string) => {
    console.log(value)
  }

  onCancel = () => {
    console.log("cancel")
  }

  toCommentList = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/list`);
  }

  backEdit = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.goBack();
  }

  render() {
    // const moreOPtions: MMoreOptionType[] = [
    //   {
    //     content: '回复', optionType: 'reply', onClick: function (option: any) {
    //       console.log(option)
    //     }
    //   },
    //   { optionType: 'task', content: '转任务' },
    //   { content: '编辑', optionType: 'edit' },
    //   { content: '取消', optionType: 'cancel' }]
    let parentPath = formatParentPath(this.props as any)

    return (
      <div>
        <MCommentEdit
         
          createUrl="/api/bcw/common/comment/createComment"
          onSubmit={this.onSubmit}
          onCancel={this.onCancel}
          module={"bcw"}
          targetId="752714034012356609"
          // 开启图片上传和附件拖拽排序
          actionConfig={["recording", "picture", "associated", "at", "emoticon", 'upload', 'voiceToText', 'address']}
          uploadProps={{ sortable: true }}
        />
        <MButton onClick={this.toCommentList} >查看评论列表</MButton>
        <MDialog
          destroyOnClose
          path={`${parentPath}/list`}
          isRouteLayout={true}
          title={"评论列表"}
        >
          <MButton onClick={this.backEdit} >返回编辑</MButton>
          <MComment
            module={"bcw"}
            objectModule="bcw"
            targetId="752714034012356609"
           
            style={{ height: "100%" }}
            // 开启图片上传和附件拖拽排序
            actionConfig={["recording", "picture", "associated", "at", "emoticon", 'upload', 'voiceToText', 'address']}
            uploadProps={{ sortable: true }}
          />
        </MDialog>
      </div>
    )
  }
}

export default Basic;
```

### 自定义请求

自定义请求

```jsx
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { Button, MComment, utils, MMoreOptionType, ReplyOption } from '@weapp/ui';
import { request, RequestOptionConfig } from '@weapp/utils';

const { formatParentPath } = utils;

interface PropsType extends RouteComponentProps {

}

interface StateType {
  key: string;
}

class Basic extends React.Component<PropsType, StateType> {

  path: string = formatParentPath(this.props);
  ref = React.createRef<any>();

  constructor(props: any) {
    super(props);
    this.state = {
      key: "",
    }
  }

  onRefresh = () => {
    this.ref.current && this.ref.current.onRefresh();
  }

  fetchData = (options: RequestOptionConfig) => {
    return request({
      ...options, headers: {
        ...options.headers,
        testHeaderId: '1',
      }
    });
  }

  render() {
    const moreOPtions: MMoreOptionType[] = [
      {
        content: '回复', optionType: 'reply', onClick: function (option: any) {
          console.log(option)
        }
      },
      { optionType: 'task', content: '转任务' },
      { content: '编辑', optionType: 'edit' },
      { content: '取消', optionType: 'cancel' }]

    return (
      <div style={{ position: "fixed", width: "100%", height: "100%" }}>
        <MComment
          module={"document"}
          objectModule="doc"
          targetId="752714034012356609"
         
          style={{ height: "100%" }}
          wrappedComponentRef={this.ref}
          moreOptions={moreOPtions}
          textToRichText
          fetchData={this.fetchData}
          uploadProps={{
            uploadParams: {
              a: "b"
            }
          }}
        />
        <Button onClick={this.onRefresh} >刷新</Button>
      </div>
    )
  }
}

export default Basic;
```

### 转为商机

添加转为商机功能

```jsx
import React, { ReactText } from 'react';
import { MComment, CommentOptionType, ReplyOption, MButton, MInput } from '@weapp/ui';

export default class Basic extends React.Component<any, any> {

  constructor(props: any) {
    super(props);
    this.state = {
      inputValue: "8516555326042660906",
      targetId: "8516555326042660906",
    }
  }
  handleValueChange = (value: ReactText) => {
    this.setState({ inputValue: value });
  }
  handleSearch = () => {
    this.setState({ targetId: this.state.inputValue });
  }

  customOptionConfig = (data: ReplyOption, defaultOption: CommentOptionType[] = []): CommentOptionType[] => {
    console.log({ data, defaultOption });
    return [...defaultOption, "salechance"];
  }
  render() {
    const { inputValue, targetId } = this.state;
    return (
      <div>
        <MInput
         
          value={inputValue}
          onChange={this.handleValueChange}
        />
        <MButton
         
          onClick={this.handleSearch}
        >
          切换评论
        </MButton>
        <MComment
         
          module={"customer"}
          objectModule="crm"
          targetId={targetId}
          key={targetId}
          optionConfig={this.customOptionConfig}
        />
      </div>
    )
  }
}
```

### 评论菜单自定义api

```jsx
import React, { ReactNode } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { MComment, MListData, MSpin, utils } from '@weapp/ui';

const { formatParentPath } = utils;
const { MCommentMenu } = MComment;

interface PropsType extends RouteComponentProps {

}

interface StateType {
    key: string;
    loading: boolean;
}

class CustomMenu extends React.Component<PropsType, StateType> {

    path: string = formatParentPath(this.props);

    constructor(props: any) {
        super(props);
        this.state = {
            key: "",
            loading: false
        }
    }

    onBeforeGetComment = (params: any) => {
        return new Promise((resolve, reject) => {
            this.setState({ loading: true })
            resolve(params)
        })
    }

    onAfterGetComment = (params: any) => {
        return new Promise((resolve, reject) => {
            this.setState({ loading: false })
            resolve(params)
        })
    }

    customRenderContent = (_: any, ele: ReactNode) => {
        const { loading } = this.state
        return <MSpin spinning={loading}>
            <div>这里是额外渲染的内容</div>
            {ele}
        </MSpin>
    }

    customRenderCardHeader = (rowData: MListData, index: number, ele: ReactNode) => {
        console.log(rowData)
        return <div>
            这里自定义渲染了头部{index}
        </div>
    }

    renderItemHeaderInfo = () => {
        return <div style={{ display: 'inline-block', paddingLeft: '10px', color: 'red' }}>
            这里是额外内容
        </div>
    }

    render() {
        return (
            <div>
                <MCommentMenu
                   
                    defaultActiveKey={"all"}
                    createUrl="/api/app/doc/common/comment/createComment"
                    updataUrl="/api/app/doc/common/comment/updateComment"
                    module={"document"}
                    objectModule="doc"
                    menu={[{
                        "id": "all",
                        "content": "全部",
                        "urlKey": "domainComment",
                        "otherParams": {
                            "loadCount": true,
                            "method": "domainComment",
                            "typeFilter": "all"
                        },
                        "url": "/api/app/doc/common/comment/domainComment.common",
                        "urlParams": {
                            "id": "5113583308244483201",
                            "module": "document",
                            "pageSize": 10,
                            "loadCount": true,
                            "method": "domainComment",
                            "typeFilter": "all"
                        },
                        //"total": 4,
                        "showType": "card"
                    }, {
                        "id": "mine",
                        "content": "我的评论",
                        "urlKey": "employeeComment",
                        "otherParams": {
                            "method": "employeeComment",
                            "typeFilter": "mine"
                        },
                        "url": "/api/app/doc/common/comment/employeeComment.common",
                        "urlParams": {
                            "id": "5113583308244483201",
                            "module": "document",
                            "pageSize": 10,
                            "method": "employeeComment",
                            "typeFilter": "mine"
                        },
                        //"total": 4,
                        "showType": "card"
                    }, {
                        "id": "reply",
                        "content": "回复我的",
                        "urlKey": "reply",
                        "otherParams": {
                            "loadCount": false,
                            "method": "reply"
                        },
                        "url": "/api/app/doc/common/comment/reply.common",
                        "urlParams": {
                            "id": "5113583308244483201",
                            "module": "document",
                            "pageSize": 10,
                            "loadCount": false,
                            "method": "reply"
                        },
                        //"total": 1,
                        "showType": "card"
                    }] as any}
                    //targetId="4341580164279439928"
                    path={this.path}
                    customRenderContent={this.customRenderContent}
                    onBeforeGetComment={this.onBeforeGetComment}
                    onAfterGetComment={this.onAfterGetComment}
                    paginationType='scroll'
                    listProps={{
                        loading: false
                    }}
                    renderItemHeaderInfo={this.renderItemHeaderInfo}
                    customRenderCardHeader={this.customRenderCardHeader}
                />
            </div>
        )
    }
}

export default CustomMenu;
```

## API

### 参数说明如下：

#### MComment

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| module | 模块标识 | string | 否 |  |
| hasHeader | 是否渲染头部 | string | 否 |  |
| title | 自定义 title | string | 否 |  |
| commentUrl | 评论列表接口 | string | 否 |  |
| commentParams | 评论列表接口参数 | AnyObj | 否 |  |
| actionConfig | 文本框底部事件配置项 | MCommentAction[] | 否 | [`upload`, `at`, `emoticon`, `associated`, `address`, `recording`, `voiceToText` ] |
| moreOptions | 更多选项的底部菜单配置 | MMoreOptionType[] | 否 |  |
| createUrl | 创建评论接口 | string | 否 |  |
| createParams | 创建评论接口参数 | AnyObj | 否 |  |
| updataUrl | 更新接口 URL | string | 否 |  |
| updataParams | 更新接口的参数 | AnyObj | 否 |  |
| chartUrl | 统计数据列表接口 | string | 否 |  |
| chartParams | 统计数据接口参数 | AnyObj | 否 |  |
| hasSearch | 是否使用搜索 | boolean | 否 |  |
| hasCommentSearch | 是否使用新版搜索 | boolean | 否 |  |
| hasEchart | 是否使用图表绘制 | boolean | 否 |  |
| quoteEllipsis | 是否启用引用省略（只显示一行） | boolean | 否 |  |
| targetId | 评论唯一 id | string | 否 |  |
| onPageChange | 分页切换事件 | (current: number, pageSize: number) => void | 否 |  |
| onReplySubmitted | 回复评论提交完成回调 | () => void | 否 |  |
| onUpdated | 更新评论提交完成回调 | () => void | 否 |  |
| path | 页面路由（不设置会默认获取当前路由） | string | 否 | 当前页面路由 |
| paginationType | 分页类型 | ListPaginationType | 否 |  |
| paginationProps | 分页组件 props | PaginationProps \| false | 否 | false |
| onReplySubmit | 回复事件 | (value: string, data: ReplyOption) => void | 否 |  |
| onUpdata | 更新事件 | (value: string, data: ReplyOption) => void | 否 |  |
| optionConfig | 每条回复内容下方 option 按钮设置 | CommentOptionType[] \| ((data:ReplyOption, defaultOption?: CommentOptionType[]) => CommentOptionType[]) | 否 | [`delete`, `reply`, `edit`, `task`, `upvote`,`more`] |
|  |  |  |  |  |
| labelOption | 渲染更多数据配置值 | CommentLabel[] | 否 |  |
| renderItemHeaderInfo | 渲染列表更多标题内容 | (data: ReplyOption) => React.ReactNode | 否 |  |
| renderItemFooterInfo | 渲染列表更多标题内容 | (data: ReplyOption) => React.ReactNode | 否 |  |
| getScrollContainer | 滚动容器定位(组件外部容器滚动时使用，内部 List 滚动请使用 listProps 传递滚动 api，下列数据同) | () => HTMLElement | 否 |  |
| onEndReachedThreshold | 触发滚动事件时距离容器底部的像素的值 | number | 否 |  |
| scrollEventThrottle | 滚动事件触发间隔(毫秒) | number | 否 |  |
| onScroll | 滚动事件回调 | () => void | 否 |  |
| deleteRelevanceUrl | 删除评论事项关联接口 | string | 否 |  |
| customAvatarUrl | 自定义头像展示地址(返回 null 则使用接口默认头像) | string \| null | 否 |  |
| customAvatar | 自定义头像(自定义头像的优先级在自定义头像地址之前) | (com: React.ReactNode, data: ReplyOption) => React.ReactNode | 否 |  |
| commentCommentedUrl | 回复列表接口 | string | 否 |  |
| commentCommentedParams | 回复列表参数 | AnyObj \| ((data?: ReplyOption) => AnyObj) | 否 |  |
| showEmpty | 无数据时是否显示`空` | boolean | 否 | true |
| objectModule | 模块接口路由 | string | 否 | `bcw` |
| showEmpty | 评论为空时是否展示 Empty 组件 | boolean | 否 | true |
| extendsActionConfig | 自定义配置评论编辑图标按钮 | MCommentActionObj[] | 否 |  |
| custonRenderOptions | 自定义渲染文本框图标按钮(优先级在 extendsActionConfig 之上，传入 custonRenderOptions 后就不会渲染 extendsActionConfig 控制的内容) | () => React.ReactNode | 否 | true |
| customRenderEmpty | 自定义空数据状态 | (() => ReactNode) \| ReactNode | 否 |  |
| showSource | 是否展示评论来源 | boolean | 否 | true |
| onBeforeGetComment | 获取评论数据前触发 | (params?: AnyObj) => Promise<any \| void> | 否 |  |
| onAfterGetComment | 获取评论数据更新数据前触发 | (result: RequestResult) => Promise<any \| void> | 否 |  |
| onBeforeCreate | 创建评论接口 | (params?: AnyObj, replyData?: ReplyOption, fullParams?: AnyObj) => Promise<any \| void> | 否 |  |
| onAfterCreate | 评论提交或回复后更新数据前触发 | (result: RequestResult, replyData?: ReplyOption) => Promise<any \| void> | 否 |  |
| onBeforeUpdate | 评论更新前触发 | (params?: AnyObj, updateData?: ReplyOption, fullParams?: AnyObj) => Promise<any \| void> | 否 |  |
| onAfterUpdate | 评论更新后更新数据前触发 | (result: RequestResult, updateData?: ReplyOption) => Promise<any \| void> | 否 |  |
| uploadProps | 评论内部附件上传 Props | MUploadProps \| ((data: ReplyOption) => MUploadProps) | 否 |  |
| editTextProps | 透传给 MEditText 组件的额外参数，也支持 `(type, data) => props` 动态返回，不同场景可分别处理新增、回复、编辑、引用 | Partial \| ((type: 'add' \| 'reply' \| 'edit' \| 'quote', data?: ReplyOption) => Partial) | 否 |  |
| onReplyCancel | 评论编辑或回复去掉按钮回调 | (data: ReplyOption, type: string) => Promise | 否 |  |
| usePosition | 是否使用默认定位功能 | boolean | 否 | true(企业微信中默认为 false) |
| textAutoFocus | 文本框是否自动焦点 | boolean | 否 | true |
| voteListModule | 点赞列表渲染的模块标识 | MVoteListModuleType | 否 | `normal` |
| onDelete | 评论删除回调 | (data?: ReplyOption) => void | 否 |  |
| onDeleted | 评论删除成功回调 | (data?: ReplyOption) => void | 否 |  |
| renderReplyContent | 渲染评论回复区域内容 | (data: ReplyOption) => React.ReactNode | 否 |  |
| hasSort | 是否使用排序 | boolean | 否 |  |
| hasCommentSort | 是否使用新排序 | boolean | 否 |  |
| sortBy | 排序方式 | `desc` \| `asc` | 否 |  |
| onSortChange | 排序修改事件 | (sortBy: `desc` \| `asc`) => void | 否 |  |
| mapProps | 地图组件props | MMapProps | 否 |  |
| useSkeleton | 是否开启骨架屏 | boolean | 否 | true(开启) |
| atBrowserProps | 评论@参数控制 | MBrowserProps | 否 |  |
| layout | 评论展示类型 | `content` \| `floor`(按内容/楼层展示) | 否 | `content`(按内容展示) |
| usePrivated | 是否开启私密评论功能 | boolean | 否 |  |
| renderTop | 文本框顶部自定义渲染 | (data?: ReplyOption) => React.ReactNode | 否 |  |
| customRenderText | 文本框自定义渲染 | (com: ReactNode, data?: ReplyOption) => React.ReactNode | 否 |  |
| usePhrase | 使用常用批示语 | boolean | 否 |  |
| renderContentFooter | 自定义评论回复区域底部内容 | (data: ReplyOption) => ReactNode | 否 |  |
| renderContentHeader | 自定义评论内容区域顶部内容 | (data: ReplyOption) => ReactNode | 否 |  |
| queryChildrenUrl | 查询子回复接口 | string | 否 |  |
| queryChildrenParams | 查询子回复参数 | AnyObj | 否 |  |
| showTime | 是否显示评论底部时间 | boolean | 否 | true |
| quoteRenderProps | 引用区域自定义渲染内容 | ItemRenderObjType | 否 |  |
| deleteUrl | 删除接口URL | string | 否 |  |
| deleteParams | 删除接口的参数 | AnyObj | 否 |  |
| useDesensitization | 开启脱敏设置 | boolean | 否 | false |
| renderIconBottom | 自定义按钮底部渲染区域 | () => ReactNode | 否 |  |
| renderAudioBottom | 自定义录音底部渲染区域 | () => ReactNode | 否 |  |
| renderAttachmentsTop | 自定义附件顶部渲染区域 | () => ReactNode | 否 | image.png |
| hiddenMoreBtn | 隐藏更多➕按钮（为true时，强制隐藏，为false时，强制显示，默认根据actionConfig的数量判断，数量大于5显示更多➕按钮） | boolean | 否 |  |
| topicConfig | 话题设置参数（需要转话题功能时 必填 ） | TopicConfigParams | 否 |  |
| fetchData | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
| disableAt | 禁用输入框@人员功能 | boolean | 否 |  |
| associativeProps | 创建评论事项关联按钮prosp | BrowserProps | 否 |  |
| fileOptionBlacklist | 评论附件操作按钮黑名单 | string[] | 否 |  |
| useSignApprove | 使用手写签批 | boolean | 否 |  |
| useSignature | 使用电子签名 | boolean | 否 |  |
| renderCustomMoreContent | 渲染评论中间(评论内容和事项关联中间区域，在renderCommentContent之下) | (data: ReplyOption) => React.ReactNode | 否 |  |
| renderItemHeaderMore | 渲染头部自定义内容(用户名右侧) renderMoreTop之前 | (data: ReplyOption) => React.ReactNode | 否 |  |
| renderItemHeaderBelow | 渲染头部自定义内容 位于header底部 | (data: ReplyOption) => React.ReactNode | 否 |  |
| templateId | 模板标识（支持EB评论）(1 - 9) | string | 否 |  |
| sourceConfig | 来源显示设置 | `['PC', 'nonPC']` \| `['PC']` \| `['nonPC']`\| `[]` | 否 |  |
| useFullParams | 接口是否使用完整参数模式（用于onBeforeCreate、onBeforeUpdate口子等） | boolean | 否 |  |
| customActionConfigLength | 自定义评论编辑输入框底部按钮组展示数据 | number \| ((actionConfig: MCommentAction[]) => number) | 否 |  |
##### MCommentActionObj

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| id | 数据唯一值 | string | 是 |  |
| icon | Icon 组件的 name | IconNames | 是 |  |
| onClick | 点击事件 | onClick?: () => void; | 否 |  |
| content | 文字 | onClick?: () => void; | 否 |  |
| innerIcon | 更多弹窗要使用的彩色icon | IconNames | 否 |  |
```ts
type MCommentAction = MCommentActionType | MCommentActionObj
type MCommentActionType =
  | "at" /*@人员*/
  | "emoticon" /*表情*/
  | "associated" /*事项关联*/
  | "upload" /*附件上传*/
  | "address" /*获取地址*/
  | "recording" /*录音*/
  | "voiceToText"; /*语音转文字*/
  | "more"; /*更多*/
  | "picture"; /*图片*/
  | "voice"; /*语音*/
  | "desensitization"; /*脱敏*/

type TopicConfigParams = AnyObj | ((data: ReplyOption) => AnyObj)
```

#### MCommentMenu 请参考 pc 端文档

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| usePosition | 是否使用默认定位功能 | boolean | 否 | true |
| fetchData | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
| listProps | 评论列表props | ListProps | 否 |  |
| customRenderContent | 自定义内容 | (_: any, ele: ReactNode, data?: ReplyOption) => React.ReactNode | 否 |  |
| customRenderCardHeader | card模式下，自定义header | (rowData: MListData, rowIndex: number, ele: ReactNode) => ReactNode | 否 |  |
#### MCommment 和 MCommentMenu 组件手动刷新数据需要通过 wrappedComponentRef 获取 ref 值然后调用 refresh 方法

## MComment.MCommentEdit

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| module | 模块 id | string | 否 | `share` |
| targetId | 评论唯一 id | string | 否 |  |
| createUrl | 创建评论接口，不传则不自动调用接口，需要手动调用 | string | 否 |  |
| createParams | 创建评论所需参数 | AnyObj | 否 |  |
| onSubmit | 点击创建按钮的回调 | (value: string, otherParams: AnyObj, attachments: string) => void | 否 |  |
| onCancel | 点击返回按钮的回调 | () => void | 否 |  |
| onChange | 文本改变事件 | (value: string) => void | 否 |  |
| onCreated | 创建接口调用成功的回调 | data: ReplyOption) => void | 否 |  |
| value | 文本内容受控 | string | 否 |  |
| defaultValue | 默认文本内容 | string | 否 |  |
| mTextareaProps | 多行文本框 props | MTextareaProps | 否 |  |
| path | 组件路由地址 | string | 否 |  |
| renderExtraConent | 渲染添加评论更多内容 | () => React.ReactNode | 否 |  |
| uploadData | 默认上传内容 | UploadData[] | 否 |  |
| hasButton | 是否显示提交和取消按钮 | boolean | 否 | true |
| needRequired | 是否需要必填校验 | boolean | 否 | true |
| extendsActionConfig | 自定义配置评论编辑图标按钮 | MCommentActionObj[] | 否 |  |
| custonRenderOptions | 自定义渲染文本框图标按钮(优先级在 extendsActionConfig 之上，传入 custonRenderOptions 后就不会渲染 extendsActionConfig 控制的内容) | () => React.ReactNode | 否 | true |
| usePosition | 是否使用默认定位功能 | boolean | 否 | true |
| textAutoFocus | 文本框是否自动焦点 | boolean | 否 | true |
| renderTop | 文本框顶部自定义渲染 | () => React.ReactNode | 否 |  |
| useDesensitization | 开启脱敏设置 | boolean | 否 | false |
| renderIconBottom | 自定义按钮底部渲染区域 | () => ReactNode | 否 |  |
| renderAudioBottom | 自定义录音底部渲染区域 | () => ReactNode | 否 |  |
| renderAttachmentsTop | 自定义附件顶部渲染区域 | () => ReactNode | 否 |  |
| hiddenMoreBtn | 隐藏更多➕按钮（为true时，强制隐藏，为false时，强制显示，默认根据actionConfig的数量判断，数量大于5显示更多➕按钮） | boolean | 否 |  |
| fetchData | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
| disableAt | 禁用输入框@人员功能 | boolean | 否 |  |
| associativeProps | 创建评论事项关联按钮prosp | BrowserProps | 否 |  |
| customActionConfigLength | 自定义评论编辑输入框底部按钮组展示数据 | number \| ((actionConfig: MCommentAction[]) => number) | 否 |  |
手动执行提交操作需要通过 ref 调用 MCommentEdit 组件的 startSubmit 方法

## MComment.MCommentGroup

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| activeKey | 选中项的 id | string | 否 |  |
| defaultActiveKey | 默认选中 id | string | 否 |  |
| groupData | 子项对应的配置项 | MCommentGroupData[] | 否 |  |
| collapseprops | MICollapse 组件 Props | MICollapseProps | 否 |  |
| onChange | 选中项改变的回调 | (value: string) => void | 否 |  |
| extendsActionConfig | 自定义配置评论编辑图标按钮 | MCommentActionObj[] | 否 |  |
| custonRenderOptions | 自定义渲染文本框图标按钮(优先级在 extendsActionConfig 之上，传入 custonRenderOptions 后就不会渲染 extendsActionConfig 控制的内容) | () => React.ReactNode | 否 | true |
| showSource | 是否展示评论来源 | boolean | 否 | true |
| uploadProps | 评论内部附件上传 Props | MUploadProps \| ((data: ReplyOption) => MUploadProps) | 否 |  |
| onReplyCancel | 评论编辑或回复去掉按钮回调 | (data: ReplyOption, type: string) => Promise | 否 |  |
| usePosition | 是否使用默认定位功能 | boolean | 否 | true |
| textAutoFocus | 文本框是否自动焦点 | boolean | 否 | true |
| renderReplyContent | 渲染评论回复区域内容 | (data: ReplyOption) => React.ReactNode | 否 |  |
| fetchData | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
| disableAt | 禁用输入框@人员功能 | boolean | 否 |  |
其余属性参考 MComment 组件

##### MCommentGroupData

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| url | 获取数据的接口 | string | 否 |  |
| urlParams | 获取数据接口参数 | AnyObj | 否 |  |
| panelProps | MCollapse.Panel 的 props 参数 | MICollapsePanelProps | 否 |  |
| total | 数据总数(传 null 时默认不显示内容，占开后显示接口获取到数据总数) | number \| null | 否 | 0 |
## MComment.MCommentViewLog

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| pageProps | 分页 props(参考分页组件) | PaginationProps | 否 |  |
| url | 日志接口 | string | 否 |  |
| urlParams | 日志接口参数 | AnyObj | 否 |  |
| path | 页面地址(不传会默认通过 props 获取) | string | 否 |  |
| module | 模块 id | string | 否 |  |
| targetId | 评论 id | string | 否 |  |
| hasPullToRefresh | 是否添加下拉刷新 | boolean | 否 | true |
| onCancel | 取消按钮事件 | () => void | 否 |  |
| hasButton | 是否显示底部按钮 | boolean | 否 | false |
| viewPagination | 查阅情况是否添加分页 | boolean | 否 | false |
| disabledHrmCard | 禁止点击头像打开人员卡片 | boolean | 否 |  |
| fetchDataApi | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
| showLogType | 显示查阅情况分类 | boolean | 否 | true |
## MComment.MUpvoe

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| module | 模块接口拼接路由 | string | 否 |  |
| objectId | 点赞唯一 id | string | 否 |  |
| upvoted | 点赞状态 | boolean | 否 |  |
| upvoteCount | 点赞人数 | number | 否 |  |
| defaultUpvoteCount | 默认点赞人数 | number | 否 | 0 |
| defaultUpvoted | 默认点赞状态 | boolean | 否 | false |
| onUpvotedChange | 点赞状态改变事件 | (upvoted: boolean) => void | 否 |  |
| onUpvotedClick | 点赞按钮点击事件 | () => void | 否 |  |
| setVoteUsersAndUpvoted | 设置 voteUser 和 upvoted 的回调函数 | (voteUsers: any[], upvoted: boolean) => void | 否 |  |
| fetchData | 自定义请求数据 | (options: RequestOptionConfig) => RequestPromise | 否 |  |
## MComment.MUpvoeList

| 参数 | 说明 | 类型 | 是否必填 | 默认 |
| --- | --- | --- | --- | --- |
| module | 模块接口拼接路由 | string | 否 |  |
| objectId | 点赞唯一 id | string | 否 |  |
| upvoted | 点赞状态 | boolean | 否 |  |
| voteUsers | 点赞人员列表(通过 MUpvote 的 setVoteUsersAndUpvoted 方法获取或者直接通过后台接口获取) | AnyObj | 否 | [] |
| voteListModule | 点赞列表展示样式 | `blog` \| `normal` | 否 | `normal` |
