JUpload.vue 15 KB

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