index.tsx 6.5 KB

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