reactHooks+TS:富文本braft-editor常见用法

react富文本braft-editor使用

阅读文档推荐:https://www.yuque.com/braft-editor/be、https://braft.margox.cn/demos/code-highlighter、

1、安装

# 使用npm安装
npm install braft-editor --save

# 使用yarn安装
yarn add braft-editor

2、基本使用

第一步:引入braft-editor

//引入富文本编辑器
import BraftEditor from 'braft-editor'
// 引入编辑器样式
import 'braft-editor/dist/index.css'

第二步:使用富文本编辑器

import React, { useState, forwardRef } from 'react'
import BraftEditor from 'braft-editor'
// 引入编辑器样式
import 'braft-editor/dist/index.css'

function NoConMaintenance(props, ref) {
  //富文本组件内容
   const [editorState, setEditorState] = useState<any>(BraftEditor.createEditorState('<p></p>'))
  //富文本输出的HTML
  const [outputHTML, setOutputHTML] = useState<any>('<p></p>')

  /**
   * @Author: YuKi
   * @description: 处理富文本框显示数据
   * @param {Object} editorState 富文本框内容
   * @return {*}
   */
  const handleEditorState = (editorState) => {
    setEditorState(editorState) //必须要有这一步
    setOutputHTML(editorState.toHTML()) //获取富文本框里面的内容
  }

  return (
    <>
      <BraftEditor
        className="my-editor"
        value={editorState}
        onChange={handleEditorState}
        contentStyle={{
          height: 210,
          boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)',
          border: '1px solid black',
        }}
      />
      <div>输出内容</div>
      <div>{outputHTML}</div>
    </>
  )
}

export default forwardRef(NoConMaintenance)

在这里插入图片描述
注意事项

1、富文本绑定的值editorState,初始化不能为空,需要配合BraftEditor.createEditorState()为其赋值<p></p>

2、富文本必须有onChange事件,事件中的参数是当前富文本框内的值,需要手动绑定一下setEditorState(editorState)

3、自定义内置组件

富文本使用 controls 属性指定需要展示的控件,在reactHooks+Ts项目中需要给controls设置any类型

  render () {
      const controls:any = [
      'undo', 'redo', 'separator',
      'font-size', 'line-height', 'letter-spacing', 'separator',
      'text-color', 'bold', 'italic', 'underline', 'strike-through', 'separator',
      'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
      'headings', 'list-ul', 'list-ol', 'blockquote', 'code', 'separator',
      'link', 'separator', 'hr', 'separator',
      'media',
      'separator',
      'clear'
    ]

    return (
      <div className="editor-wrapper">
        <BraftEditor
          controls={controls}
        />
      </div>
    )
  }

4、在Ant Design表单中使用

结合antd官方文档->Form->校验其他组件,采用如下两个属性

1、valuePropName组件绑定的值,类似于Form.Item中的name

2、getValueFromEvent是可以把自定义组件中的onChange 的参数(如 event)转化为控件的值,必须有返回值,返回的值就是Form.Item`组件值。
在这里插入图片描述
使用如下:

import React, { useState,forwardRef } from 'react'
import { Form} from 'antd'
import BraftEditor from 'braft-editor'
// 引入编辑器样式
import 'braft-editor/dist/index.css'

function NoConMaintenance(props, ref) {
  //表单的ref
  const [aEForm] = Form.useForm()
  //富文本组件内容
  const [editorState, setEditorState] = useState<any>(BraftEditor.createEditorState('<p></p>'))

  /**
   * @Author: YuKi
   * @description: 把自定义组件中的onChange 的参数(如 event)转化为控件的值
   * @param {any} e
   * @return {*}
   */  
  const normFile = (e: any) => {
    return e.toHTML()
  }

  /**
   * @Author: YuKi
   * @description: 处理富文本框显示数据
   * @param {Object} editorState
   * @return {*}
   */
  const handleEditorState = (editorState) => {
    setEditorState(editorState)
  }

  return (
    <>
      <Form
        name="aEfrom"
        labelCol={{ span: 22 }}
        wrapperCol={{ span: 22 }}
        autoComplete="off"
        form={aEForm}
        layout="vertical"
      >
        <Form.Item
          name="richText"
          label="富文本"
          valuePropName="richText"
          getValueFromEvent={normFile}
          rules={[{ required: true }]}
        >
          <BraftEditor
            className="my-editor"
            value={editorState}
            onChange={handleEditorState}
            contentStyle={{
              height: 210,
              boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)',
              border: '1px solid black',
            }}
          />
        </Form.Item>
      </Form>
    </>
  )
}

export default forwardRef(NoConMaintenance)

在这里插入图片描述

ps:如果需要回显数据,第一步用BraftEditor.createEditorState()为富文本进行赋值。第二步用From表单的ref,为From组件赋值

setEditorState(BraftEditor.createEditorState(record.noticeContent))
  aEForm.setFieldsValue({
    richText: record.noticeContent,
  })

5、集成Ant Design上传组件

以上传图片为例,braft-editor自带媒体上传,它自己会把图片转成base64,但是所占体积太大了。

解决方法:结合Ant Design的上传组件,先把图片上传到服务器上,然后把图片链接放到富文本里面

第一步:利用controls把媒体上传,去掉。

  /* 富文本自定义架构 */
  const controls: any = ['undo','redo','separator','font-size','line-height','letter-spacing',
'separator','text-color','bold','italic','underline', 'strike-through',
'separator','superscript','subscript','remove-styles','emoji','separator','text-indent','text-align',
'separator','headings','list-ul','list-ol','blockquote','code','separator','link','separator','hr',
'separator',// 'media','separator', 'clear',
  ]

第二步:采富文本extendControls属性自定义上传组件

    /**
   * @Author: YuKi
   * @description: 富文本上传图片前的勾子
   * @param {any} option
   * @return {*}
   */
     const beforeUpload = (file: RcFile) => {
      const isJpgOrPng =
        file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg'
      if (!isJpgOrPng) {
        message.error('You can only upload JPG、PNG、gif file!')
        return Upload.LIST_IGNORE
      }
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isLt2M) {
        message.error('Image must smaller than 2MB!')
        return Upload.LIST_IGNORE
      }
      return isJpgOrPng && isLt2M
    }
  
    /**
     * @Author: YuKi
     * @description: 富文本自定义自己图片的上传实现
     * @param {any} option
     * @return {*}
     */
    const handleUpload = (option: any) => {
      const formData = new FormData()
      formData.append('blobContainerName', 'NOTICE_FILE')
      formData.append('fileList', option.file)
      fileUpload(formData).then((rep: any) => {
        setEditorState(
          ContentUtils.insertMedias(editorState, [
            {
              type: 'IMAGE',
              url:
                'https://alphatest.blob.core.windows.net/' +
                `${rep.data[0].blobContainerName}/${rep.data[0].fileSaveName}`,
            },
          ]),
        )
      })
    }
    
   /*富文本自定义上传组件 */
  const extendControls: any = [
    {
      key: 'antd-uploader',
      type: 'component',
      component: (
        <Upload accept="image/*" showUploadList={false} beforeUpload={beforeUpload} customRequest={handleUpload}>
          {/* 富文本里面显示的按钮 */}
          <Button className="control-item button upload-button" data-title="上传图片">
            <PlusOutlined />
          </Button>
        </Upload>
      ),
    },
  ]

完整代码如下:

/*
 * @Description: 菜单路由配置文件
 * @Autor:
 * @LastEditors: YuKi
 * @Date: 2022/10/27 13:24:33
 * @LastEditTime: 2023/01/06
 */
import React from 'react'
import Layout from '@/layout'
import Login from '@/pages/Login'
import { RouterType } from '@/router/router.type'
import NoPage from '@/pages/NoPage'

/* 静态页路由 */
export const noPermission: RouterType[] = [
  {
    path: '/login',
    component: Login,
    exact: true,
    key: '/login',
    isShow: false,
  },
  {
    path: '/404',
    component: Layout,
    children: [
      {
        key: '404',
        component: NoPage,
        isShow: false,
      },
    ],
  },
]
/* 动态页路由 */
const routers: RouterType[] = [
  {
    path: '/',
    component: Layout,
    redirect: '/index/index',
    exact: true,
    key: '/',
    isShow: false,
  },
  // 首页
  {
    path: '/index/index',
    key: '/index',
    isShow: true,
    name: '首页',
    permissions: ['index'],
    component: Layout,
    icon: 'HomeOutlined',
    languageKey: 'menu.home',
    hideChildrenInMenu: false,
    breadcrumbName: '首页',
    children: [
      {
        name: '首页',
        languageKey: 'menu.home',
        key: '/index/index',
        path: '/index/index',
        icon: 'HomeOutlined',
        exact: true,
        isShow: true,
        breadcrumbName: '首页',
        permissions: ['index:index'],
        component: React.lazy(() => import('@/pages/Index')),
      },
    ],
  },
  /* 个人设置 */
  {
    path: '/personSettings',
    key: '/personSettings',
    isShow: false,
    name: '个人设置',
    icon: 'UserOutlined',
    languageKey: 'menu.personSettings',
    permissions: ['personSettings'],
    component: Layout,
    hideChildrenInMenu: false,
    breadcrumbName: '个人设置',
    children: [
      {
        name: '个人设置',
        key: '/personSettings/index',
        path: '/personSettings/index',
        exact: true,
        icon: 'UserOutlined',
        languageKey: 'menu.personSettings',
        breadcrumbName: '个人设置',
        isShow: false,
        permissions: ['personSettings:index'],
        component: React.lazy(() => import('@/pages/PersonalSettings')),
      },
    ],
  },
  /* 安规维护 */
  {
    path: '/safetyManage',
    key: '/safetyManage',
    isShow: true,
    name: '安规维护',
    permissions: ['safetyManage'],
    component: Layout,
    icon: 'SaveOutlined',
    languageKey: 'menu.safetyManage',
    hideChildrenInMenu: false,
    breadcrumbName: '安规维护',
    children: [
      {
        name: '安规维护',
        languageKey: 'menu.safetyManage',
        path: '/safetyManage',
        key: '/safetyManage',
        icon: 'SaveOutlined',
        exact: true,
        isShow: true,
        breadcrumbName: '安规维护',
        permissions: ['safetyManage:index'],
        component: React.lazy(() => import('@/pages/SafetyManage')),
      },
    ],
  },
  /* App维护 */
  {
    path: '/AppMaintenance',
    key: '/AppMaintenance',
    name: 'App维护',
    component: Layout,
    isShow: true,
    languageKey: 'menu.AppMaintenance',
    breadcrumbName: 'App维护',
    permissions: ['AppMaintenance'],
    icon: 'AppstoreOutlined',
    children: [
      /* APP欢迎页面维护 */
      {
        path: '/AppMaintenance/AppWelcomeMaintence',
        key: '/AppMaintenance/AppWelcomeMaintence',
        component: React.lazy(() => import('@/pages/AppMaintenance/AppWelcomeMaintence')),
        exact: true,
        name: 'APP欢迎页面维护',
        languageKey: 'menu.AppWelcomeMaintence',
        isShow: true,
        breadcrumbName: 'APP欢迎页面维护',
        permissions: ['AppMaintenance:AppMaintenance:AppWelcomeMaintence'],
      },
      /* APP版本维护 */
      {
        path: '/AppMaintenance/AppVersionMaintenance',
        key: '/AppMaintenance/AppVersionMaintenance',
        component: React.lazy(() => import('@/pages/AppMaintenance/AppVersionMaintenance')),
        exact: true,
        name: 'APP版本维护',
        languageKey: 'menu.AppVersionMaintenance',
        isShow: true,
        breadcrumbName: 'APP版本维护',
        permissions: ['AppMaintenance:AppMaintenance:AppVersionMaintenance'],
      },
    ],
  },
  /* 公司联系信息维护 */
  {
    path: '/companyContactInfoMaintenance',
    key: '/companyContactInfoMaintenance',
    isShow: true,
    name: '公司联系信息维护',
    permissions: ['companyContactInfoMaintenance'],
    component: Layout,
    icon: 'SnippetsOutlined',
    languageKey: 'menu.companyContactInfoMaintenance',
    hideChildrenInMenu: false,
    breadcrumbName: '公司联系信息维护',
    children: [
      {
        name: '公司联系信息维护',
        languageKey: 'menu.companyContactInfoMaintenance',
        path: '/companyContactInfoMaintenance',
        key: '/companyContactInfoMaintenance',
        icon: 'SnippetsOutlined',
        exact: true,
        isShow: true,
        breadcrumbName: '公司联系信息维护',
        permissions: ['companyContactInfoMaintenance:index'],
        component: React.lazy(() => import('@/pages/CompanyContactInfoMaintenance')),
      },
    ],
  },
  /*邮件模板管理*/
  {
    path: '/emailTemplate',
    key: '/emailTemplate',
    isShow: true,
    name: ' 邮件内容模板管理',
    icon: 'UsergroupDeleteOutlined',
    permissions: ['emailTemplate'],
    languageKey: 'menu.emailTemplate',
    component: Layout,
    hideChildrenInMenu: false,
    breadcrumbName: ' 邮件内容模板管理',
    children: [
      {
        name: ' 邮件内容模板管理',
        icon: 'UsergroupDeleteOutlined',
        key: '/emailTemplate/index',
        path: '/emailTemplate/index',
        exact: true,
        isShow: true,
        languageKey: 'menu.emailTemplate',
        breadcrumbName: ' 邮件内容模板管理',
        permissions: ['emailTemplate:index'],
        component: React.lazy(() => import('@/pages/EmailTemplate')),
      },
    ],
  },

  /*邮件内容管理*/
  {
    path: '/emailContentTemplate',
    key: '/emailContentTemplate',
    isShow: false,
    name: ' 邮件内容管理',
    icon: 'UsergroupDeleteOutlined',
    permissions: ['emailContentTemplate'],
    languageKey: 'menu.emailContentTemplate',
    component: Layout,
    hideChildrenInMenu: false,
    breadcrumbName: ' 邮件内容管理',
    children: [
      {
        name: ' 邮件内容模板管理',
        icon: 'UsergroupDeleteOutlined',
        key: '/emailContentTemplate/index',
        path: '/emailContentTemplate/index',
        exact: true,
        isShow: false,
        languageKey: 'menu.emailContentTemplate',
        breadcrumbName: ' 邮件内容模板管理',
        permissions: ['emailContentTemplate:index'],
        component: React.lazy(() => import('@/pages/EmailTemplate/EmailContentTemplate')),
      },
    ],
  },

  /* SAP管理模块 */
  {
    path: '/sapManage',
    key: '/sapManage',
    name: 'SPA管理',
    component: Layout,
    isShow: true,
    languageKey: 'menu.SAPManage',
    breadcrumbName: 'SPA管理',
    permissions: ['sapManage'],
    icon: 'MessageOutlined',
    children: [
      /* SAP接口配置管理 */
      {
        path: '/sapManage/sapApiManage',
        key: '/sapManage/sapApiManage',
        component: React.lazy(() => import('@/pages/SAPMaintenance/apiMaintenance')),
        exact: true,
        name: 'SAP接口配置管理',
        languageKey: 'menu.sapApiManage',
        isShow: true,
        breadcrumbName: 'SAP接口配置管理',
        permissions: ['sapManage:sapApiManage'],
      },
      /* SAP参数维护 */
      {
        path: '/sapManage/sapParamMaintain',
        key: '/sapManage/sapParamMaintain',
        component: React.lazy(() => import('@/pages/SAPMaintenance/paramsMaintenance')),
        exact: true,
        name: 'SAP参数维护',
        languageKey: 'menu.sapParamMaintain',
        isShow: true,
        breadcrumbName: 'SAP参数维护',
        permissions: ['sapManage:sapParamMaintain'],
      },
      /* SAP参数类别维护 */
      {
        path: '/sapManage/sapParamCateMain',
        key: '/sapManage/sapParamCateMain',
        component: React.lazy(() => import('@/pages/SAPMaintenance/paramsCateMaintenance')),
        exact: true,
        name: 'SAP参数类别维护',
        languageKey: 'menu.sapParamCateMain',
        isShow: true,
        breadcrumbName: 'SAP参数类别维护',
        permissions: ['sapManage:sapParamCateMain'],
      },
    ],
  },
  /*语言维护*/
  {
    path: '/languageMaintain/index',
    key: '/languageMaintain',
    isShow: true,
    name: '语言维护',
    icon: 'UsergroupDeleteOutlined',
    permissions: ['languageMaintain'],
    languageKey: 'menu.emailTemplate',
    component: Layout,
    hideChildrenInMenu: true,
    breadcrumbName: '语言维护',
    children: [
      {
        name: '语言维护',
        icon: 'UsergroupDeleteOutlined',
        key: '/languageMaintain/index',
        path: '/languageMaintain/index',
        exact: true,
        isShow: true,
        languageKey: 'menu.languageMaintain',
        breadcrumbName: '语言维护',
        permissions: ['languageMaintain:index'],
        component: React.lazy(() => import('@/pages/LanguageMaintain')),
      },
    ],
  },
  /*太阳辐射显示维护*/
  {
    path: '/sunRadiation/index',
    key: '/sunRadiation',
    isShow: true,
    name: '太阳辐射显示维护',
    icon: 'UsergroupDeleteOutlined',
    permissions: ['sunRadiation'],
    languageKey: 'menu.sunRadiation',
    component: Layout,
    hideChildrenInMenu: true,
    breadcrumbName: '太阳辐射显示维护',
    children: [
      {
        name: '太阳辐射显示维护',
        icon: 'UsergroupDeleteOutlined',
        key: '/sunRadiation/index',
        path: '/sunRadiation/index',
        exact: true,
        isShow: true,
        languageKey: 'menu.sunRadiation',
        breadcrumbName: '太阳辐射显示维护',
        permissions: ['sunRadiation:index'],
        component: React.lazy(() => import('@/pages/SunRadiation/index')),
      },
    ],
  },
  /*第三方平台维护*/
  {
    path: '/platMaintenance/index',
    key: '/platMaintenance',
    isShow: true,
    name: '第三方平台维护',
    icon: 'UsergroupDeleteOutlined',
    permissions: ['platMaintenance'],
    languageKey: 'menu.platMaintenance',
    component: Layout,
    hideChildrenInMenu: true,
    breadcrumbName: '第三方平台维护',
    children: [
      {
        name: '第三方平台维护',
        icon: 'UsergroupDeleteOutlined',
        key: '/platMaintenance/index',
        path: '/platMaintenance/index',
        exact: true,
        isShow: true,
        languageKey: 'menu.platMaintenance',
        breadcrumbName: '第三方平台维护',
        permissions: ['platMaintenance:index'],
        component: React.lazy(() => import('@/pages/ThirdPlatMaintenance')),
      },
    ],
  },
  /* 站内消息维护 */
  {
    path: '/siteMesMaintenance',
    key: '/siteMesMaintenance',
    name: '站内消息维护',
    component: Layout,
    isShow: true,
    languageKey: 'menu.siteMesMaintenance',
    breadcrumbName: '站内消息维护',
    permissions: ['siteMesMaintenance'],
    icon: 'MessageOutlined',
    children: [
      /* 通知类型维护 */
      {
        path: '/siteMesMaintenance/templateMaintenance',
        key: '/siteMesMaintenance/templateMaintenance',
        component: React.lazy(() => import('@/pages/SiteMesMaintenance/TemplateMaintenance')),
        exact: true,
        name: '通知类型维护',
        languageKey: 'menu.templateMaintenance',
        isShow: true,
        breadcrumbName: '通知类型维护',
        permissions: ['siteMesMaintenance:templateMaintenance'],
      },
      /* 通知模板维护 */
      {
        path: '/siteMesMaintenance/typeMaintenance',
        key: '/siteMesMaintenance/typeMaintenance',
        component: React.lazy(() => import('@/pages/SiteMesMaintenance/TypeMaintenance')),
        exact: true,
        name: '通知模板维护',
        languageKey: 'menu.typeMaintenance',
        isShow: true,
        breadcrumbName: '通知模板维护',
        permissions: ['siteMesMaintenance:typeMaintenance'],
      },
    ],
  },
  /*通知对象维护*/
  {
    path: '/noObjMaintenance',
    key: '/noObjMaintenance',
    isShow: false,
    name: ' 通知对象维护',
    permissions: ['noObjMaintenance'],
    languageKey: 'menu.noObjMaintenance',
    component: Layout,
    hideChildrenInMenu: false,
    breadcrumbName: ' 通知对象维护',
    children: [
      {
        name: ' 通知对象维护',
        key: '/noObjMaintenance/index',
        path: '/noObjMaintenance/index',
        exact: true,
        isShow: false,
        languageKey: 'menu.noObjMaintenance',
        breadcrumbName: ' 通知对象维护',
        permissions: ['noObjMaintenance:index'],
        component: React.lazy(() => import('@/pages/SiteMesMaintenance/TypeMaintenance/components/NoObjMaintenance')),
      },
    ],
  },
  /*通知内容维护*/
  {
    path: '/noConMaintenance',
    key: '/noConMaintenance',
    isShow: false,
    name: ' 通知内容维护',
    permissions: ['noConMaintenance'],
    languageKey: 'menu.noConMaintenance',
    component: Layout,
    hideChildrenInMenu: false,
    breadcrumbName: ' 通知内容维护',
    children: [
      {
        name: ' 通知内容维护',
        key: '/noConMaintenance/index',
        path: '/noConMaintenance/index',
        exact: true,
        isShow: false,
        languageKey: 'menu.noConMaintenance',
        breadcrumbName: ' 通知内容维护',
        permissions: ['noConMaintenance:index'],
        component: React.lazy(() => import('@/pages/SiteMesMaintenance/TypeMaintenance/components/NoConMaintenance')),
      },
    ],
  },
  /* 用户协议维护 */
  {
    path: '/userAgreementMaintenance',
    key: '/userAgreementMaintenance',
    isShow: true,
    name: '用户协议维护',
    permissions: ['userAgreementMaintenance'],
    component: Layout,
    icon: 'SnippetsOutlined',
    languageKey: 'menu.userAgreementMaintenance',
    hideChildrenInMenu: false,
    breadcrumbName: '用户协议维护',
    children: [
      {
        name: '用户协议维护',
        languageKey: 'menu.userAgreementMaintenance',
        path: '/userAgreementMaintenance/index',
        key: '/userAgreementMaintenance/index',
        icon: 'SnippetsOutlined',
        exact: true,
        isShow: true,
        breadcrumbName: '用户协议维护',
        permissions: ['userAgreementMaintenance:index'],
        component: React.lazy(() => import('@/pages/UserAgreementMaintenance')),
      },
    ],
  },
  /* 字典维护 */
  {
    path: '/dictionaryMaintenance',
    key: '/dictionaryMaintenance',
    isShow: true,
    name: '字典维护',
    permissions: ['dictionaryMaintenance'],
    component: Layout,
    icon: 'SnippetsOutlined',
    languageKey: 'menu.dictionaryMaintenance',
    hideChildrenInMenu: false,
    breadcrumbName: '字典维护',
    children: [
      {
        name: '字典维护',
        languageKey: 'menu.dictionaryMaintenance',
        path: '/dictionaryMaintenance/index',
        key: '/dictionaryMaintenance/index',
        icon: 'SnippetsOutlined',
        exact: true,
        isShow: true,
        breadcrumbName: '字典维护',
        permissions: ['dictionaryMaintenance:index'],
        component: React.lazy(() => import('@/pages/DictionaryMaintenance')),
      },
      {
        name: '内容维护',
        languageKey: 'menu.contentRepair',
        path: '/dictionaryMaintenance/contentRepair/index',
        key: '/dictionaryMaintenance/contentRepair/index',
        icon: 'SnippetsOutlined',
        exact: true,
        isShow: false,
        breadcrumbName: '内容维护',
        permissions: ['contentRepair:index'],
        component: React.lazy(() => import('@/pages/DictionaryMaintenance/contentRepair')),
      },
    ],
  },
  ...noPermission,
]

export default routers

在这里插入图片描述

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值