index.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import SvgIcon from '@/components/SvgIcon'
  2. import { iFile, iOSSData } from '@/types/file'
  3. import { apiGetFileList, apiSaveFileInfo, getSignature } from '@/utils/common/api'
  4. import consts from '@/utils/consts'
  5. import { dayjsFormat } from '@/utils/util'
  6. import { InboxOutlined } from '@ant-design/icons'
  7. import { message, Modal, Table, Upload } from 'antd'
  8. import { ColumnsType } from 'antd/lib/table'
  9. import { UploadChangeParam } from 'antd/lib/upload'
  10. import { UploadFile } from 'antd/lib/upload/interface'
  11. import React, { useEffect, useState } from 'react'
  12. import { ZhCloseButton } from '../Button'
  13. const { Dragger } = Upload
  14. interface iFileModalProps {
  15. dataId: string
  16. visible: boolean
  17. dataType: number
  18. onCancel: () => void
  19. showUpload?: boolean
  20. }
  21. interface iFileModalState {
  22. id: string
  23. filename: string
  24. filepath: string
  25. accountName: string
  26. createTime: string
  27. }
  28. export default function FileModal(props: iFileModalProps) {
  29. const { dataId = "", visible = false, onCancel, dataType = 1, showUpload = false } = props
  30. const [ files, setFiles ] = useState<Array<iFileModalState>>([])
  31. const [ total, setTotal ] = useState<number>(0)
  32. const [ OSSData, setOssData ] = useState<iOSSData>({
  33. dir: '',
  34. expire: '',
  35. host: '',
  36. accessId: '',
  37. policy: '',
  38. signature: ''
  39. })
  40. useEffect(() => {
  41. if (props.visible) {
  42. initOssData()
  43. initData()
  44. }
  45. }, [ visible ])
  46. const initData = async(pageNo: number = 1, pageSize: number = consts.PAGE_SIZE) => {
  47. // const { current: pageNo = 1, pageSize = consts.PAGESIZE } = pagination || {}
  48. const { code = -1, data = [], total = 0 } = await apiGetFileList(dataType, dataId, pageNo, pageSize)
  49. if (code === consts.RET_CODE.SUCCESS) {
  50. setFiles(data)
  51. setTotal(total)
  52. }
  53. }
  54. // 上传文件改变时的状态
  55. const onChange = async (info: UploadChangeParam) => {
  56. const { status } = info.file
  57. if (status !== 'uploading') {
  58. // console.log(info.file, info.fileList)
  59. }
  60. if (status === 'done') {
  61. // message.success(`${info.file.name} 上传成功!`)
  62. const newFileList: iFile[] = [
  63. {
  64. createTime: new Date(),
  65. filepath: info.file.url,
  66. filename: info.file.name
  67. }
  68. ]
  69. const { code = -1 } = await apiSaveFileInfo(newFileList, consts.DATA_TYPE.RETURN, dataId)
  70. if (code === consts.RET_CODE.SUCCESS) {
  71. initData()
  72. }
  73. } else if (status === 'error') {
  74. message.error(`${info.file.name} 上传失败!`)
  75. }
  76. }
  77. // 初始化、获取签名
  78. const initOssData = async () => {
  79. try {
  80. const { code = -1, data = {} } = await getSignature()
  81. if (code === consts.RET_CODE.SUCCESS) {
  82. setOssData({ ...OSSData, ...data })
  83. } else {
  84. message.error("获取签名失败,请联系管理员!")
  85. }
  86. } catch (error) {
  87. message.error(error)
  88. }
  89. }
  90. // 额外参数、oss签名
  91. const getExtraData = (file: UploadFile) => {
  92. return {
  93. key: file.url,
  94. OSSAccessKeyId: OSSData.accessId,
  95. policy: OSSData.policy,
  96. Signature: OSSData.signature
  97. }
  98. }
  99. const transformFile = (file: any) => {
  100. file.url = OSSData.dir + file.name
  101. return file
  102. }
  103. // 上传前的回调
  104. const beforeUpload = (file: any) => {
  105. const { UPLOAD_LIMIT } = consts
  106. const isLt30M = file.size / 1024 / 1024 < UPLOAD_LIMIT
  107. if (!isLt30M) {
  108. message.error("上传附件大小限制在30MB!")
  109. return false
  110. }
  111. const expire = parseInt(OSSData.expire) * 1000
  112. if (expire < Date.now()) {
  113. initOssData()
  114. return false
  115. }
  116. return true
  117. }
  118. // 移除文件
  119. const onRemove = (file: any) => {
  120. }
  121. const columns: ColumnsType<iFileModalState> = [
  122. {
  123. title: "文件名",
  124. dataIndex: "filepath",
  125. width: 287,
  126. onCell: () => {
  127. return {
  128. style: {
  129. maxWidth: 287,
  130. overflow: 'hidden',
  131. whiteSpace: 'nowrap',
  132. textOverflow:'ellipsis',
  133. cursor:'pointer'
  134. }
  135. }
  136. },
  137. // eslint-disable-next-line react/display-name
  138. render: (path: string, record: iFileModalState) => <a href={consts.OSS_PATH.REVIEW + path} target="_blank" rel="noopener noreferrer">{record.filename}</a>
  139. },
  140. {
  141. title: "上传人",
  142. dataIndex: "accountName"
  143. },
  144. {
  145. title: "上传时间",
  146. dataIndex: "createTime",
  147. // eslint-disable-next-line react/display-name
  148. render: text => <span>{dayjsFormat(text, "YYYY-MM-DD")}</span>
  149. },
  150. {
  151. title: "操作",
  152. align: "center",
  153. // eslint-disable-next-line react/display-name
  154. render: (_, record) => <a href={consts.OSS_PATH.DOWNLOAD + record.filepath} download><SvgIcon type="xxh-download"></SvgIcon></a>
  155. }
  156. ]
  157. return (
  158. <Modal
  159. title="附件"
  160. getContainer={false}
  161. visible={visible}
  162. onCancel={onCancel}
  163. footer={<ZhCloseButton onClick={() => onCancel()} size="small">关闭</ZhCloseButton>}
  164. >
  165. {
  166. showUpload ?
  167. <div className="pi-mg-bottom-10">
  168. <Dragger
  169. name="file"
  170. action={OSSData.host}
  171. multiple={true}
  172. onChange={onChange}
  173. beforeUpload={beforeUpload}
  174. data={getExtraData}
  175. transformFile={transformFile}
  176. showUploadList={false}
  177. // accept={consts.UPLOAD_WHITE}
  178. onRemove={onRemove}
  179. >
  180. <p className="ant-upload-drag-icon">
  181. <InboxOutlined />
  182. </p>
  183. <p className="ant-upload-text">把文件拖入指定区域,完成上传,同样支持点击上传。</p>
  184. <p className="ant-upload-hint">
  185. 支持单文件/多文件上传。附件大小最大为30MB!
  186. </p>
  187. </Dragger>
  188. </div>
  189. : ''
  190. }
  191. <Table
  192. dataSource={files}
  193. columns={columns}
  194. rowKey={record => record.id}
  195. bordered
  196. pagination={{
  197. hideOnSinglePage: true,
  198. size: "small",
  199. pageSize: consts.PAGE_SIZE,
  200. onChange: (page, pageSize) => initData(page, pageSize),
  201. total
  202. }}
  203. // onChange={(pagination) => initData(pagination)}
  204. ></Table>
  205. </Modal>
  206. )
  207. }