文件消息类型请求MP3,MP4,docx,zip等文件流(包括添加loading,文件大小展示)

本文介绍了一个用于管理文件消息的React组件实现,支持多种文件类型的预览与下载,包括视频、音频、文档等,并通过不同的图标区分文件类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * @文件描述  会话管理界面右侧 ---- 文件消息
 * @创建人和时间 
 * @param {object} maxed - 视频音频跳转modul使用
 * 
*/
import React, { PureComponent } from 'react';
import { Row, Col, Card, Spin } from 'antd';
import { YoutubeOutlined, SoundOutlined, FolderOpenOutlined, FileUnknownOutlined, FileWordOutlined } from '@ant-design/icons';
import { Player } from 'video-react';
import ReactAudioPlayer from 'react-audio-player';
import { wechatV1 as v1 } from 'services/config';
import { getAccessToken } from 'utils/token';
import "../../../../../node_modules/video-react/dist/video-react.css";
import AudioLess from '../../../../assets/less/audio.less';

export default class File extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      files: {},
    }
  };

  // 点击卡片跳转modal
  spackChange = () => {
    const { item } = this.props;
    const { files } = this.state;
    const that = this;
    const token = getAccessToken();
    that.setState({ files: { ...files, [item.id]: { loading: true } } })
    if (files[item.id] && files[item.id].file) return;
    fetch(`${v1}/wechat/content/${item.id}/media`, {
      headers: { authorization: `Bearer ${token}` },
      responseType: 'blob',
    })
      .then(res => {
        return res.blob()
      }).then(res => {
        const reader = new FileReader();
        reader.readAsDataURL(res);
        reader.onload = (e) => {
          if (item.file_ext === "mp4" || item.file_ext === "mp3") {
            that.setState({ files: { ...files, [item.id]: { loading: false, file: e.target.result } } })
          } else {
            const a = document.createElement('a');
            const url = window.URL.createObjectURL(res);
            a.href = url;
            a.download = item.file_name;
            a.click();
            window.URL.revokeObjectURL(url);
            that.setState({ files: { ...files, [item.id]: { loading: false } } })
          }
        }
      })
  };

// 显示内存大小设置
  conver = (limit) => {
    let size = "";
    if (limit < 0.1 * 1024) { // 如果小于0.1KB转化成B  
      size = `${limit.toFixed(2)}B`;
    } else if (limit < 0.1 * 1024 * 1024) {// 如果小于0.1MB转化成KB  
      size = `${(limit / 1024).toFixed(2)}KB`;
    } else if (limit < 0.1 * 1024 * 1024 * 1024) { // 如果小于0.1GB转化成MB  
      size = `${(limit / (1024 * 1024)).toFixed(2)}MB`;
    } else { // 其他转化成GB  
      size = `${(limit / (1024 * 1024 * 1024)).toFixed(2)}GB`;
    }

    const sizestr = size;
    const len = sizestr.indexOf(".");
    const dec = sizestr.substr(len + 1, 2);
    if (dec === "00") {// 当小数点后为00时 去掉小数部分  
      return sizestr.substring(0, len) + sizestr.substr(len + 3, 2);
    }
    return sizestr;
  }

  render() {
    const { files } = this.state;
    // console.log(maxed);
    const { item } = this.props;
    return (
      <>
        {
          item.file_ext === "mp4" || item.file_ext === "mp3"
            ? (
              <>
                {
                  files[item.id] && files[item.id].file ? (
                    item.file_ext === "mp4"
                      ? (
                        <div className={AudioLess.player}>
                          <Player videoId="video-1" controls autoPlay style={{ fontSize: `${item.file_size}` }} fluid={false}>
                            <source src={files[item.id].file} />
                          </Player>
                        </div>
                      )
                      : item.file_ext === "mp3" ? <ReactAudioPlayer src={files[item.id].file} autoPlay={false} controls style={{ outline: 'none' }} />
                        : null
                  ) : (
                    <Spin spinning={files[item.id] ? files[item.id].loading : false}>
                      <Card size="small" style={{ width: 220, height: 100 }} hoverable onClick={this.spackChange}>
                        <Row>
                          <Col span={18} style={{ fontSize: 14, marginTop: 2, whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{item.file_name}</Col>
                          <Col span={6} style={{ float: "right" }}>
                            {
                              item.file_ext === "mp4"
                                ? (
                                  <YoutubeOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                                )
                                : item.file_ext === "mp3"
                                  ? <SoundOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                                  : null
                            }
                          </Col>
                        </Row>
                        <div style={{ color: 'rgba(0, 0, 0, 0.45)' }}>
                          {this.conver(Number(item.file_size))}
                        </div>
                      </Card>
                    </Spin>
                  )
                }
              </>
            )
            : item.file_ext === "docx" || item.file_ext === "zip" || item.file_ext === "bed"
              ? (
                <Spin spinning={files[item.id] ? files[item.id].loading : false}>
                  <Card size="small" style={{ width: 220, height: 100 }} hoverable onClick={this.spackChange}>
                    <Row>
                      <Col span={18} style={{ fontSize: 14, marginTop: 2, whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{item.file_name}</Col>
                      <Col span={6} style={{ float: "right" }}>
                        {
                          item.file_ext === "zip" || item.file_ext === "bed"
                            ? <FolderOpenOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                            : item.file_ext === "docx"
                              ? <FileWordOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                              : <FileUnknownOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                        }
                      </Col>
                      <div style={{ color: 'rgba(0, 0, 0, 0.45)' }}>
                        {this.conver(Number(item.file_size))}
                      </div>
                    </Row>
                  </Card>
                </Spin>
              )
              : null
        }



        {/* <Card size="small" style={{ width: 220, height: 100 }} hoverable onClick={() => this.spackChange(true, { title: `${item.r_title}`, time: `${item.r_starttime}` })}>
          <Row>
            <Col span={18} style={{ fontSize: 14, marginTop: 2, whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{item.file_name}</Col>
            <Col span={6} style={{ float: "right" }}>
              <img alt="" src={file} style={{ width: 37, height: 46 }} />
              {
                item.file_ext === "mp4"
                  ? <YoutubeOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                  : item.file_ext === "mp3"
                    ? <SoundOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                    : item.file_ext === "zip" || item.file_ext === "bed"
                      ? <FolderOpenOutlined style={{ fontSize: 35, color: "#7878bf" }} />
                      : item.file_ext === "docx"
                        ? <a rel="noreferrer" download={`${item.file_name}.${item.file_ext}`} href={img}><FileWordOutlined style={{ fontSize: 35, color: "#7878bf" }} /></a>
                        : <FileUnknownOutlined style={{ fontSize: 35, color: "#7878bf" }} />
              }
            </Col>

          </Row>
        </Card> */}
        {/* <Modal
          visible={maxed.isVisible}
          onCancel={() => this.spackChange()}
          footer={null}
          className={AudioLess.antm}
        >
          {
            item.file_ext === "mp4"
              ? <div className={AudioLess.player}><Player videoId="video-1" controls autoPlay style={{ fontSize: `${item.file_size}` }} fluid={false}><source src={`${v1}/wechat/content/${item.id}/media`} /></Player></div>
              : item.file_ext === "mp3" ? <ReactAudioPlayer src={`${v1}/wechat/content/${item.id}/media`} autoPlay={false} controls style={{ outline: 'none' }} />
                : item.file_ext === "zip" ? <a rel="noreferrer" target='_blank' download={`${item.file_name}.${item.file_ext}`} href={img}>zip文件</a>
                  : item.file_ext === "docx" ? <a rel="noreferrer" download={`${item.file_name}.${item.file_ext}`} href={img}>docx文档</a>
                    : item.file_ext === "bed" ? <a rel="noreferrer" target='_blank' href={data.url}>bed结尾的</a>
                      : <a rel="noreferrer" target='_blank' href={data.url}>该文件未授权</a>
          }
        </Modal> */}
      </>
    )
  }
}

1.页面结构搭建: 首页:设计一个简洁的导航栏,包含 “录入试题”“管理试题”“导出试题” 等主要功能入口。 录入试题页面: 1.使用 Vue.js 的组件化思想,为每种题型(单选题、判断题、填空题、编程题、简答题)创建单独的录入表单组件。例如,单选题表单包含题目内容输入框、多个选项输入框、正确答案选择框、答案解析输入框等。 2.表单使用 Element - UI 的表单组件进行布局和样式设计,确保输入框、选择框等元素排列整齐,具有良好的视觉效果。并且为每个输入框添加必要的表单验证,如题目内容不能为空、单选题选项至少有两个等。 管理试题页面: 1.设计一个表格,展示所有已录入试题的关键信息,如题型、题目内容、创建时间等。使用 Element - UI 的表格组件实现,该组件支持排序、筛选等功能,方便用户查找特定试题。 2.为每一行数据添加操作按钮,包括 “查看详情”“编辑”“删除”。点击 “查看详情” 按钮弹出对话框,展示该试题的完整信息,包括所有选项、正确答案、答案解析等;“编辑” 按钮则跳转到对应的录入表单页面,并预先填充好该试题的已有数据,方便用户修改;“删除” 按钮点击后弹出确认框,确认后从数据库中删除该试题(这里只是前端触发删除操作,实际删除需与后端交互,后续前后端集成时实现)。 导出试题页面: 1.创建一个简单的页面,包含导出格式选择(Word 和 Excel)以及导出范围选择(全部试题或自定义筛选条件后的试题)的功能。提供一个按钮,点击后根据用户选择的格式和范围进行试题导出。 2.交互逻辑实现: 录入功能:用户在录入表单中输入数据并点击 “提交” 按钮后,使用 JavaScript 收集表单数据,进行前端验证(如格式是否正确、必填项是否填写等)。验证通过后,将数据以合适的格式(如 JSON)暂存(实际发送到后端保存将在前后端集成时完成),并弹出提示框告知用户录入成功。 增删查改功能: 1.查询:在管理试题页面的表格上方添加搜索框,用户输入关键词后,通过 JavaScript 过滤表格数据,实时展示符合条件的试题。同时,利用表格自带的排序和筛选功能,实现多条件查询。 2.新增:点击 “录入试题” 导航进入录入页面,用户录入数据提交后,在管理试题页面的表格中实时更新显示新录入的试题(模拟数据更新,实际更新需与后端交互)。 3.修改:用户在编辑页面修改数据并提交后,同样在管理试题页面实时更新该试题的显示信息(模拟数据更新)。 4.删除:点击 “删除” 按钮并确认后,从管理试题页面的表格中移除该试题记录(模拟数据删除)。 导出功能: 1.Excel 导出:用户在导出试题页面选择 Excel 格式并点击导出按钮后,使用 XLSX.js 库将暂存的试题数据(或从后端获取的最新数据,前后端集成后实现)转换为 Excel 文件格式,并触发浏览器下载。 2.Word 导出:选择 Word 格式并点击导出按钮后,利用 Docxtemplater 库结合预先设计好的 Word 模板,将试题数据填充到模板中生成 Word 文件。通过调用 Pandoc 工具将生成的临时文件转换为最终的 Word 文件,并触发浏览器下载。
最新发布
04-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值