upload.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <!-- 共通模块 上传组件 -->
  2. <template>
  3. <div>
  4. <el-upload action
  5. ref="uploadFile"
  6. class="upload-demo"
  7. :disabled="!editable"
  8. :on-preview="handlePreview"
  9. :on-remove="handleRemove"
  10. :on-success="successCallback"
  11. :before-upload="beforeAvatarUpload"
  12. :before-remove="beforeRemove"
  13. :file-list="fileList"
  14. :auto-upload="autoUpload"
  15. :show-file-list="showFile"
  16. list-type="picture"
  17. :http-request="uploadSectionFile"
  18. multiple>
  19. <template v-if="editable">
  20. <el-button size="small"
  21. type="primary">{{
  22. $t('upload.uploadButton')
  23. }}</el-button>
  24. <div slot="tip"
  25. class="el-upload__tip">
  26. {{ $t('upload.uploadText01') }}
  27. <br />
  28. {{ $t('upload.uploadText02') }}
  29. </div>
  30. </template>
  31. </el-upload>
  32. <!-- 放大图片 -->
  33. <div v-show="enlargeShow"
  34. class="enlarge"
  35. @click="shutDown">
  36. <div class="img_box">
  37. <img v-lazy="zoomInPicture" />
  38. </div>
  39. </div>
  40. </div>
  41. </template>
  42. <script>
  43. import Cookies from 'js-cookie'
  44. // import { getOssInterimCredentials } from '@/model/procurement/spare'
  45. import { EventBus } from 'base-core-lib'
  46. export default {
  47. name: 'Upload',
  48. props: {
  49. autoUpload: {
  50. // 表单ID
  51. type: Boolean,
  52. default: function () {
  53. return true
  54. }
  55. },
  56. appendixFileUrls: {
  57. // 表单ID
  58. type: Array,
  59. default: function () {
  60. return []
  61. }
  62. },
  63. detailId: {
  64. // 详细ID
  65. type: String,
  66. default: function () {
  67. return null
  68. }
  69. },
  70. modelId: {
  71. // 模块ID(同步数据用)
  72. type: String,
  73. default: function () {
  74. return null
  75. }
  76. },
  77. editable: {
  78. // 是否可编辑
  79. type: Boolean,
  80. default: function () {
  81. return true
  82. }
  83. },
  84. procurementName: {
  85. // 模块名称
  86. // 是否可编辑
  87. type: String,
  88. default: function () {
  89. return null
  90. }
  91. },
  92. frameName: {
  93. // 业务(画面)名称
  94. type: String,
  95. default: function () {
  96. return null
  97. }
  98. }
  99. },
  100. data () {
  101. return {
  102. showFile: true, // 是否显示已上传文件列表
  103. enlargeShow: false,
  104. zoomInPicture: '',
  105. fileList: [],
  106. fileIndex: 0,
  107. fileOssInfo: null,
  108. preventUpload: false,
  109. // eslint-disable-next-line vue/no-reserved-keys
  110. _appendixId: null,
  111. message: {}
  112. }
  113. },
  114. created () {
  115. if (this.appendixFileUrls) {
  116. this.getFileList()
  117. } else {
  118. this.showFile = true
  119. }
  120. },
  121. methods: {
  122. initUpload () {
  123. this.showFile = true
  124. this.enlargeShow = false
  125. this.zoomInPicture = ''
  126. this.fileList = []
  127. this.fileIndex = 0
  128. this.fileOssInfo = null
  129. this.preventUpload = false
  130. this.appendixId = null
  131. this.message = {}
  132. this.appendixFileUrls = []
  133. },
  134. // 确认上传
  135. submitUpload (billId, detailId) {
  136. this.billId = billId
  137. if (detailId) {
  138. this.detailId = detailId
  139. }
  140. },
  141. // 自定义文件上传
  142. uploadSectionFile (param) {
  143. // let ossInter = null
  144. // const oldFileName = param.file.name
  145. // const now = new Date()
  146. // const year = now.getFullYear()
  147. // let month = now.getMonth() + 1
  148. // let date = now.getDate()
  149. // month = month > 9 ? month.toString() : '0' + month
  150. // date = date > 9 ? date.toString() : '0' + date
  151. // // fileName 生成
  152. // // 生成规则 saas/1/finance/payment/2019/0620/d496c207-16ca-45ce-976d-4982be23571b.txt
  153. // const fileName = `saas/${localStorage.getItem('ws-pf_tenantId')}/${this.procurementName
  154. // }/${this.frameName}/${year}${month}${date}/${oldFileName}`
  155. // this.fileImage()
  156. // getOssInterimCredentials().then(response => {
  157. // ossInter = response.data
  158. // const loading = this.loading()
  159. // client(ossInter, Cookies.getJSON('ossAccessConfig'))
  160. // .put(fileName, param.file)
  161. // .then(result => {
  162. // // 关闭遮罩
  163. // loading.close()
  164. // // 阿里云传输成功
  165. // this.fileOssInfo = result
  166. // this.fileOssInfo.odName = param.file.name
  167. // this.message.fileName = fileName
  168. // this.message.fileOssInfo = this.fileOssInfo
  169. // this.getFileUrl(this.message.fileName)
  170. // this.$emit('getMessage', this.message)
  171. // EventBus.$emit('success', this.$t('showMessage.saveSuccessOss'))
  172. // })
  173. // })
  174. },
  175. /**
  176. * 注意 vue的v-bind(语法糖为:)会有延迟,请注意同步问题
  177. * @isDelay 是否延迟执行,默认延迟执行
  178. */
  179. getFileList (isDelay = true) {
  180. if (isDelay) {
  181. setTimeout(() => {
  182. this.getFileList(false)
  183. })
  184. return
  185. }
  186. // 初始化文件显示
  187. this.fileList = [] // 重置文件列表数组
  188. this.appendixId = '' // 重置变量 补丁代码
  189. const config = Cookies.getJSON('ossAccessConfig')
  190. if (Array.isArray(this.appendixFileUrls)) {
  191. for (const i in this.appendixFileUrls) {
  192. this.getFileUrl(this.appendixFileUrls[i].url)
  193. const str = this.regFileAfter(this.appendixFileUrls[i].name)
  194. if (str == 'png' || str == 'gif' || str == 'jpg' || str == 'jpeg') {
  195. this.appendixFileUrls[i].url =
  196. 'http://' +
  197. config.bucket +
  198. '.' +
  199. config.endpoint +
  200. '/' +
  201. this.appendixFileUrls[i].url +
  202. '?x-oss-process=image/resize,w_100,h_100/quality,q_80'
  203. } else {
  204. this.appendixFileUrls[i].url =
  205. 'http://' +
  206. config.bucket +
  207. '.' +
  208. config.endpoint +
  209. '/' +
  210. this.appendixFileUrls[i].url
  211. }
  212. this.fileList.push(this.appendixFileUrls[i])
  213. }
  214. } else {
  215. /* this.showFile = false*/
  216. this.getFileUrl(this.appendixFileUrls.url)
  217. const str = this.regFileAfter(this.appendixFileUrls.name)
  218. if (str == 'png' || str == 'gif' || str == 'jpg' || str == 'jpeg') {
  219. this.appendixFileUrls.url =
  220. 'http://' +
  221. config.bucket +
  222. '.' +
  223. config.endpoint +
  224. '/' +
  225. this.appendixFileUrls.url +
  226. '?x-oss-process=image/resize,w_100,h_100/quality,q_80'
  227. } else {
  228. this.appendixFileUrls.url =
  229. 'http://' +
  230. config.bucket +
  231. '.' +
  232. config.endpoint +
  233. '/' +
  234. this.appendixFileUrls.url
  235. }
  236. this.fileList.push(this.appendixFileUrls)
  237. }
  238. this.fileIndex = this.fileList.length
  239. this.fileImage()
  240. },
  241. fileImage () {
  242. this.$nextTick(function () {
  243. const element = document.getElementsByClassName(
  244. 'el-upload-list__item-name'
  245. )
  246. for (const i in element) {
  247. if (element.item(i) == null) {
  248. continue
  249. }
  250. const fileName = element.item(i).innerText
  251. element.item(i).title = fileName
  252. const regFileAfterClass =
  253. this.regFileAfter(fileName) + ' el-upload-list__item-thumbnail'
  254. element.item(i).previousSibling.className = regFileAfterClass
  255. }
  256. })
  257. },
  258. // 某个文件上传成功都会执行该方法
  259. successCallback (res, file, fileList) {
  260. if (res.data) {
  261. this.fileIndex++
  262. }
  263. if (fileList.length == this.fileIndex) {
  264. this.getFileList()
  265. }
  266. },
  267. set appendixId (val) {
  268. val = (val || '').replace(
  269. /x-oss-process=image\/resize,w_100,h_100\/quality,q_80/g,
  270. ''
  271. )
  272. this._appendixId = val
  273. },
  274. // eslint-disable-next-line vue/no-dupe-keys
  275. get appendixId () {
  276. return this._appendixId
  277. },
  278. // 上传文件url获取
  279. getFileUrl (msg) {
  280. if (!this.appendixId) {
  281. this.appendixId = msg
  282. } else {
  283. this.appendixId = this.appendixId + ',' + msg
  284. }
  285. },
  286. // 上传文件删除
  287. delFileUrl (msg) {
  288. if (this.appendixId !== null && this.appendixId !== '') {
  289. const urlList = this.appendixId.split(',')
  290. let urlSubStr = ''
  291. for (const i in urlList) {
  292. if (urlList[i].indexOf(msg) == -1) {
  293. if (urlSubStr == '') {
  294. urlSubStr = urlList[i]
  295. } else {
  296. urlSubStr = urlSubStr + ',' + urlList[i]
  297. }
  298. }
  299. }
  300. this.appendixId = urlSubStr
  301. } else {
  302. this.appendixId = ''
  303. }
  304. },
  305. // 文件列表移除文件时的钩子
  306. handleRemove (file, fileList) {
  307. if (this.preventUpload) {
  308. return
  309. }
  310. for (const i of fileList) {
  311. if (this.message.delName) {
  312. this.message.delName = this.message.delName + ',' + i.name
  313. } else {
  314. // 下载
  315. // window.location.href = file.url
  316. }
  317. }
  318. this.delFileUrl(file.name)
  319. this.$emit('delMessage', this.message)
  320. const ids = []
  321. ids.push(file.id)
  322. EventBus.$emit('success', this.$t('upload.message01'))
  323. },
  324. // 判断文件后缀名
  325. regFileAfter (item) {
  326. const d = /\.[^\\.]+$/.exec(item)
  327. if (d === null || d.length === 0) {
  328. return 'no'
  329. }
  330. return d
  331. .toString()
  332. .substring(1)
  333. .toLowerCase()
  334. },
  335. // 点击文件列表中已上传的文件时的钩子 点击附件预览
  336. handlePreview (file) {
  337. // 点击附件预览
  338. // 判断是图片不下载/显示
  339. const str = this.regFileAfter(file.name)
  340. if (str == 'png' || str == 'gif' || str == 'jpg' || str == 'jpeg') {
  341. this.zoomInPicture = (file.url || '').replace(
  342. /x-oss-process=image\/resize,w_100,h_100\/quality,q_80/g,
  343. ''
  344. )
  345. this.enlargeShow = true
  346. } else {
  347. // 下载
  348. window.location.href = file.url
  349. }
  350. },
  351. // 关闭图片
  352. shutDown () {
  353. this.enlargeShow = false
  354. },
  355. // 删除文件之前的钩子
  356. beforeRemove (file, fileList) {
  357. if (this.preventUpload) {
  358. return
  359. }
  360. return this.$confirm(
  361. this.$t('upload.message02') +
  362. `${file.name}` +
  363. this.$t('common.question')
  364. )
  365. },
  366. // 上传文件之前的钩子 判断文件类型是否合法
  367. beforeAvatarUpload (file) {
  368. this.preventUpload = false
  369. const type = this.regFileAfter(file.name)
  370. // this.companyId = 1
  371. // this.billId = 1
  372. this.fileName = file.name
  373. // this.modelId = 1
  374. // this.myData
  375. // 判断文件类型是否合法jpg、gif、png、xlsx、pdf、xls、doc、docx、jpeg、zip、rar
  376. if (
  377. type === 'jpg' ||
  378. type === 'gif' ||
  379. type === 'png' ||
  380. type === 'xlsx' ||
  381. type === 'pdf' ||
  382. type === 'xls' ||
  383. type === 'doc' ||
  384. type === 'docx' ||
  385. type === 'jpeg' ||
  386. type === 'zip' ||
  387. type === 'rar'
  388. ) {
  389. const isLt2M = file.size / 1024 / 1024 < 15
  390. if (!isLt2M) {
  391. EventBus.$emit('error', this.$t('upload.message03'))
  392. this.preventUpload = true
  393. return false
  394. }
  395. } else {
  396. EventBus.$emit('error', this.$t('upload.message04'))
  397. this.preventUpload = true
  398. return false
  399. }
  400. if (this.fileNameRepeat(file.name)) {
  401. EventBus.$emit('error', this.$t('showMessage.saveErrorOssName'))
  402. this.preventUpload = true
  403. return false
  404. }
  405. },
  406. // 文件名称重复验证
  407. fileNameRepeat (fileName) {
  408. if (this.appendixId != null) {
  409. const urlList = this.appendixId.split(',')
  410. for (const i in urlList) {
  411. if (urlList[i].indexOf(fileName) == -1) {
  412. return false
  413. } else {
  414. return true
  415. }
  416. }
  417. }
  418. },
  419. loading () {
  420. const loading = this.$loading({
  421. lock: true,
  422. text: 'Loading',
  423. spinner: 'el-icon-loading',
  424. background: 'rgba(0, 0, 0, 0.7)',
  425. target: document.querySelector('.div1')
  426. })
  427. return loading
  428. }
  429. }
  430. }
  431. </script>
  432. <style scoped lang="scss">
  433. .upload-demo {
  434. overflow: hidden;
  435. }
  436. .el-button--primary {
  437. border-radius: 20px;
  438. padding: 0px 25px;
  439. height: 32px;
  440. }
  441. /deep/ .el-upload-list--picture .el-upload-list__item {
  442. float: left;
  443. height: 120px;
  444. width: 106px !important;
  445. border: 1px solid #ccc;
  446. padding: 20px 10px 10px 90px;
  447. outline: 0;
  448. }
  449. /deep/ .el-upload-list--picture .el-upload-list__item-thumbnail {
  450. margin-left: -73px;
  451. }
  452. /deep/ .el-icon-document:before {
  453. opacity: 0;
  454. }
  455. /deep/ .el-upload-list--picture .el-upload-list__item-status-label {
  456. opacity: 0;
  457. }
  458. .el-upload__tip {
  459. color: #999;
  460. padding-left: 10px;
  461. line-height: 15px;
  462. margin-top: 0px;
  463. display: inline-block;
  464. vertical-align: -webkit-baseline-middle;
  465. // height: 39px;
  466. }
  467. /* 放大查看上传附件预览图 */
  468. .enlarge {
  469. position: fixed;
  470. left: 0;
  471. top: 0;
  472. background: rgba(0, 0, 0, 0.8);
  473. width: 100%;
  474. height: 100%;
  475. z-index: 1000;
  476. .img_box {
  477. padding-top: 8%;
  478. width: 70%;
  479. height: 70%;
  480. margin: 0 auto;
  481. img {
  482. display: block;
  483. margin: 0 auto;
  484. height: 100%;
  485. max-width: 100%;
  486. max-height: 100%;
  487. }
  488. }
  489. }
  490. /deep/ .el-icon-close-tip {
  491. opacity: 0;
  492. }
  493. /deep/ .el-list-leave-active {
  494. transition: all 0s;
  495. }
  496. /deep/ .el-list-enter-active {
  497. transition: all 0s;
  498. }
  499. </style>
  500. <style lang="scss" scoped>
  501. .el-upload-list--picture {
  502. .el-upload-list__item {
  503. width: 200px !important;
  504. float: left !important;
  505. margin: 8px !important;
  506. }
  507. .el-upload-list__item-thumbnail {
  508. background-size: contain;
  509. }
  510. }
  511. </style>