JUpload.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. <template>
  2. <div :id="containerId" style="position: relative">
  3. <!-- ---------------------------- begin 图片左右换位置 ------------------------------------- -->
  4. <div
  5. class="movety-container"
  6. :style="{ top: top + 'px', left: left + 'px', display: moveDisplay }"
  7. style="padding: 0 8px; position: absolute; z-index: 91; height: 32px; width: 104px; text-align: center"
  8. >
  9. <div
  10. :id="containerId + '-mover'"
  11. :class="showMoverTask ? 'uploadty-mover-mask' : 'movety-opt'"
  12. style="margin-top: 12px"
  13. >
  14. <a @click="moveLast" style="margin: 0 5px"><a-icon type="arrow-left" style="color: #fff; font-size: 16px" /></a>
  15. <a @click="moveNext" style="margin: 0 5px"
  16. ><a-icon type="arrow-right" style="color: #fff; font-size: 16px"
  17. /></a>
  18. </div>
  19. </div>
  20. <!-- ---------------------------- end 图片左右换位置 ------------------------------------- -->
  21. <a-upload
  22. name="file"
  23. :multiple="true"
  24. :action="uploadAction"
  25. :headers="headers"
  26. :data="{ biz: bizPath }"
  27. :fileList="fileList"
  28. :beforeUpload="beforeUpload"
  29. @change="handleChange"
  30. :disabled="disabled"
  31. :returnUrl="returnUrl"
  32. :listType="complistType"
  33. @preview="handlePreview"
  34. :class="{ 'uploadty-disabled': disabled }"
  35. >
  36. <template>
  37. <div v-if="isImageComp">
  38. <a-icon type="plus" />
  39. <div class="ant-upload-text">{{ text }}</div>
  40. </div>
  41. <a-button v-else-if="buttonVisible" :type="btnType">
  42. <a-icon v-if="isIcon" type="upload" />{{ text }}
  43. </a-button>
  44. </template>
  45. </a-upload>
  46. <a-modal :visible="previewVisible" :width="1000" :footer="null" @cancel="handleCancel">
  47. <img alt="example" style="width: 100%" :src="previewImage" />
  48. </a-modal>
  49. </div>
  50. </template>
  51. <script>
  52. import Vue from 'vue'
  53. import { ACCESS_TOKEN } from '@/store/mutation-types'
  54. import { getFileAccessHttpUrl } from '@/api/manage'
  55. import { fileSizeLimit } from '@/api/api'
  56. const FILE_TYPE_ALL = 'all'
  57. const FILE_TYPE_IMG = 'image'
  58. const FILE_TYPE_TXT = 'file'
  59. const uidGenerator = () => {
  60. return '-' + parseInt(Math.random() * 10000 + 1, 10)
  61. }
  62. const getFileName = (path) => {
  63. if (path.lastIndexOf('\\') >= 0) {
  64. let reg = new RegExp('\\\\', 'g')
  65. path = path.replace(reg, '/')
  66. }
  67. return path.substring(path.lastIndexOf('/') + 1)
  68. }
  69. export default {
  70. name: 'JUpload',
  71. data() {
  72. return {
  73. uploadAction: window._CONFIG['domianURL'] + '/systemConfig/upload',
  74. headers: {},
  75. fileList: [],
  76. newFileList: [],
  77. uploadGoOn: true,
  78. previewVisible: false,
  79. //---------------------------- begin 图片左右换位置 -------------------------------------
  80. previewImage: '',
  81. containerId: '',
  82. top: '',
  83. left: '',
  84. moveDisplay: 'none',
  85. showMoverTask: false,
  86. moverHold: false,
  87. currentImg: '',
  88. //---------------------------- end 图片左右换位置 -------------------------------------
  89. sizeLimit: 0,
  90. }
  91. },
  92. props: {
  93. text: {
  94. type: String,
  95. required: false,
  96. default: '点击上传',
  97. },
  98. btnType: {
  99. type: String,
  100. required: false,
  101. default: 'default',
  102. },
  103. isIcon: {
  104. type: Boolean,
  105. required: false,
  106. default: true,
  107. },
  108. fileType: {
  109. type: String,
  110. required: false,
  111. default: FILE_TYPE_ALL,
  112. },
  113. /*这个属性用于控制文件上传的业务路径*/
  114. bizPath: {
  115. type: String,
  116. required: false,
  117. default: 'temp',
  118. },
  119. value: {
  120. type: [String, Array],
  121. required: false,
  122. },
  123. // update-begin- --- author:wangshuai ------ date:20190929 ---- for:Jupload组件增加是否能够点击
  124. disabled: {
  125. type: Boolean,
  126. required: false,
  127. default: false,
  128. },
  129. // update-end- --- author:wangshuai ------ date:20190929 ---- for:Jupload组件增加是否能够点击
  130. //此属性被废弃了
  131. triggerChange: {
  132. type: Boolean,
  133. required: false,
  134. default: false,
  135. },
  136. /**
  137. * update -- author:lvdandan -- date:20190219 -- for:Jupload组件增加是否返回url,
  138. * true:仅返回url
  139. * false:返回fileName filePath fileSize
  140. */
  141. returnUrl: {
  142. type: Boolean,
  143. required: false,
  144. default: true,
  145. },
  146. number: {
  147. type: Number,
  148. required: false,
  149. default: 0,
  150. },
  151. buttonVisible: {
  152. type: Boolean,
  153. required: false,
  154. default: true,
  155. },
  156. },
  157. watch: {
  158. value: {
  159. immediate: true,
  160. handler() {
  161. let val = this.value
  162. if (val instanceof Array) {
  163. if (this.returnUrl) {
  164. this.initFileList(val.join(','))
  165. } else {
  166. this.initFileListArr(val)
  167. }
  168. } else {
  169. this.initFileList(val)
  170. }
  171. },
  172. },
  173. },
  174. computed: {
  175. isImageComp() {
  176. return this.fileType === FILE_TYPE_IMG
  177. },
  178. complistType() {
  179. return this.fileType === FILE_TYPE_IMG ? 'picture-card' : 'text'
  180. },
  181. },
  182. created() {
  183. this.initFileSizeLimit()
  184. const token = Vue.ls.get(ACCESS_TOKEN)
  185. //---------------------------- begin 图片左右换位置 -------------------------------------
  186. this.headers = { 'X-Access-Token': token }
  187. this.containerId = 'container-ty-' + new Date().getTime()
  188. //---------------------------- end 图片左右换位置 -------------------------------------
  189. },
  190. methods: {
  191. initFileSizeLimit() {
  192. fileSizeLimit().then((res) => {
  193. if (res.code === 200) {
  194. this.sizeLimit = res.data
  195. }
  196. })
  197. },
  198. initFileListArr(val) {
  199. if (!val || val.length == 0) {
  200. this.fileList = []
  201. return
  202. }
  203. let fileList = []
  204. for (var a = 0; a < val.length; a++) {
  205. let url = getFileAccessHttpUrl(val[a].filePath)
  206. fileList.push({
  207. uid: uidGenerator(),
  208. name: val[a].fileName,
  209. status: 'done',
  210. url: url,
  211. response: {
  212. code: 'history',
  213. data: val[a].filePath,
  214. },
  215. })
  216. }
  217. this.fileList = fileList
  218. },
  219. initFileList(paths) {
  220. if (!paths || paths.length == 0) {
  221. //return [];
  222. // update-begin- --- author:os_chengtgen ------ date:20190729 ---- for:issues:326,Jupload组件初始化bug
  223. this.fileList = []
  224. return
  225. // update-end- --- author:os_chengtgen ------ date:20190729 ---- for:issues:326,Jupload组件初始化bug
  226. }
  227. let fileList = []
  228. let arr = paths.split(',')
  229. for (var a = 0; a < arr.length; a++) {
  230. let url = getFileAccessHttpUrl('systemConfig/static/' + arr[a])
  231. fileList.push({
  232. uid: uidGenerator(),
  233. name: getFileName(arr[a]),
  234. status: 'done',
  235. url: url,
  236. response: {
  237. code: 'history',
  238. data: arr[a],
  239. },
  240. })
  241. }
  242. this.fileList = fileList
  243. },
  244. handlePathChange() {
  245. let uploadFiles = this.fileList
  246. let path = ''
  247. if (!uploadFiles || uploadFiles.length == 0) {
  248. path = ''
  249. } else {
  250. let arr = []
  251. for (let a = 0; a < uploadFiles.length; a++) {
  252. arr.push(uploadFiles[a].response.data)
  253. }
  254. if (arr.length > 0) {
  255. path = arr.join(',')
  256. }
  257. }
  258. this.$emit('change', path)
  259. },
  260. beforeUpload(file) {
  261. this.uploadGoOn = true
  262. let fileType = file.type
  263. let fileSize = file.size
  264. if (this.fileType === FILE_TYPE_IMG) {
  265. if (fileType.indexOf('image') < 0) {
  266. this.$message.warning('请上传图片')
  267. this.uploadGoOn = false
  268. return false
  269. }
  270. }
  271. //验证文件大小
  272. if (fileSize > this.sizeLimit) {
  273. let parseSizeLimit = (this.sizeLimit / 1024 / 1024).toFixed(2)
  274. this.$message.warning('抱歉,文件大小不能超过' + parseSizeLimit + 'M')
  275. this.uploadGoOn = false
  276. return false
  277. }
  278. return true
  279. },
  280. handleChange(info) {
  281. console.log('--文件列表改变--')
  282. if (!info.file.status && this.uploadGoOn === false) {
  283. info.fileList.pop()
  284. }
  285. let fileList = info.fileList
  286. if (info.file.status === 'done') {
  287. if (this.number > 0) {
  288. fileList = fileList.slice(-this.number)
  289. }
  290. if (info.file.response.code === 200) {
  291. fileList = fileList.map((file) => {
  292. if (file.response) {
  293. let reUrl = file.response.data
  294. file.url = getFileAccessHttpUrl(reUrl)
  295. }
  296. return file
  297. })
  298. }
  299. //this.$message.success(`${info.file.name} 上传成功!`);
  300. } else if (info.file.status === 'error') {
  301. this.$message.error(`${info.file.name} 上传失败.`)
  302. } else if (info.file.status === 'removed') {
  303. this.handleDelete(info.file)
  304. }
  305. this.fileList = fileList
  306. if (info.file.status === 'done' || info.file.status === 'removed') {
  307. //returnUrl为true时仅返回文件路径
  308. if (this.returnUrl) {
  309. setTimeout(() => {
  310. this.handlePathChange()
  311. }, 500)
  312. } else {
  313. //returnUrl为false时返回文件名称、文件路径及文件大小
  314. this.newFileList = []
  315. for (var a = 0; a < fileList.length; a++) {
  316. var fileJson = {
  317. fileName: fileList[a].name,
  318. filePath: fileList[a].response.data,
  319. fileSize: fileList[a].size,
  320. }
  321. this.newFileList.push(fileJson)
  322. }
  323. this.$emit('change', this.newFileList)
  324. }
  325. }
  326. },
  327. handleDelete(file) {
  328. //如有需要新增 删除逻辑
  329. console.log(file)
  330. },
  331. handlePreview(file) {
  332. let postfix = file.name.substring(file.name.lastIndexOf('.'))
  333. if (
  334. postfix === '.gif' ||
  335. postfix === '.jpg' ||
  336. postfix === '.jpeg' ||
  337. postfix === '.png' ||
  338. postfix === '.GIF' ||
  339. postfix === '.JPG' ||
  340. postfix === '.JPEG' ||
  341. postfix === '.PNG'
  342. ) {
  343. this.previewImage = file.url || file.thumbUrl
  344. this.previewVisible = true
  345. } else {
  346. location.href = file.url
  347. }
  348. },
  349. handleCancel() {
  350. this.previewVisible = false
  351. },
  352. //---------------------------- begin 图片左右换位置 -------------------------------------
  353. moveLast() {
  354. //console.log(ev)
  355. //console.log(this.fileList)
  356. //console.log(this.currentImg)
  357. let index = this.getIndexByUrl()
  358. if (index == 0) {
  359. this.$message.warn('未知的操作')
  360. } else {
  361. let curr = this.fileList[index].url
  362. let last = this.fileList[index - 1].url
  363. let arr = []
  364. for (let i = 0; i < this.fileList.length; i++) {
  365. if (i == index - 1) {
  366. arr.push(curr)
  367. } else if (i == index) {
  368. arr.push(last)
  369. } else {
  370. arr.push(this.fileList[i].url)
  371. }
  372. }
  373. this.currentImg = last
  374. this.$emit('change', arr.join(','))
  375. }
  376. },
  377. moveNext() {
  378. let index = this.getIndexByUrl()
  379. if (index == this.fileList.length - 1) {
  380. this.$message.warn('已到最后~')
  381. } else {
  382. let curr = this.fileList[index].url
  383. let next = this.fileList[index + 1].url
  384. let arr = []
  385. for (let i = 0; i < this.fileList.length; i++) {
  386. if (i == index + 1) {
  387. arr.push(curr)
  388. } else if (i == index) {
  389. arr.push(next)
  390. } else {
  391. arr.push(this.fileList[i].url)
  392. }
  393. }
  394. this.currentImg = next
  395. this.$emit('change', arr.join(','))
  396. }
  397. },
  398. getIndexByUrl() {
  399. for (let i = 0; i < this.fileList.length; i++) {
  400. if (this.fileList[i].url === this.currentImg || encodeURI(this.fileList[i].url) === this.currentImg) {
  401. return i
  402. }
  403. }
  404. return -1
  405. },
  406. },
  407. mounted() {
  408. const moverObj = document.getElementById(this.containerId + '-mover')
  409. moverObj.addEventListener('mouseover', () => {
  410. this.moverHold = true
  411. this.moveDisplay = 'block'
  412. })
  413. moverObj.addEventListener('mouseout', () => {
  414. this.moverHold = false
  415. this.moveDisplay = 'none'
  416. })
  417. let picList = document.getElementById(this.containerId)
  418. ? document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card')
  419. : []
  420. if (picList && picList.length > 0) {
  421. picList[0].addEventListener('mouseover', (ev) => {
  422. ev = ev || window.event
  423. let target = ev.target || ev.srcElement
  424. if ('ant-upload-list-item-info' == target.className) {
  425. this.showMoverTask = false
  426. let item = target.parentElement
  427. this.left = item.offsetLeft
  428. this.top = item.offsetTop + item.offsetHeight - 50
  429. this.moveDisplay = 'block'
  430. this.currentImg = target.getElementsByTagName('img')[0].src
  431. }
  432. })
  433. picList[0].addEventListener('mouseout', (ev) => {
  434. ev = ev || window.event
  435. let target = ev.target || ev.srcElement
  436. //console.log('移除',target)
  437. if ('ant-upload-list-item-info' == target.className) {
  438. this.showMoverTask = true
  439. setTimeout(() => {
  440. if (this.moverHold === false) this.moveDisplay = 'none'
  441. }, 100)
  442. }
  443. if (
  444. 'ant-upload-list-item ant-upload-list-item-done' == target.className ||
  445. 'ant-upload-list ant-upload-list-picture-card' == target.className
  446. ) {
  447. this.moveDisplay = 'none'
  448. }
  449. })
  450. //---------------------------- end 图片左右换位置 -------------------------------------
  451. }
  452. },
  453. model: {
  454. prop: 'value',
  455. event: 'change',
  456. },
  457. }
  458. </script>
  459. <style lang="less">
  460. .uploadty-disabled {
  461. .ant-upload-list-item {
  462. .anticon-close {
  463. display: none;
  464. }
  465. .anticon-delete {
  466. display: none;
  467. }
  468. }
  469. }
  470. //---------------------------- begin 图片左右换位置 -------------------------------------
  471. .uploadty-mover-mask {
  472. background-color: rgba(0, 0, 0, 0.5);
  473. opacity: 0.8;
  474. color: #fff;
  475. height: 28px;
  476. line-height: 28px;
  477. }
  478. //---------------------------- end 图片左右换位置 -------------------------------------
  479. </style>