ImgUpload.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. <template>
  2. <div>
  3. <div v-if="type !== 'callback'" class="imgcomp-upload-list" v-for="item in uploadList">
  4. <template v-if="item.status === 'finished'">
  5. <div class="imgcomp-upload-img" v-bind:style="{ 'background-image': 'url(' + __thumb(item.thumb) + ')' }"></div>
  6. <div class="imgcomp-upload-list-cover">
  7. <Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon>
  8. <Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
  9. </div>
  10. </template>
  11. <template v-else>
  12. <Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
  13. </template>
  14. </div>
  15. <div class="add-box" v-bind:class="{ 'callback-add-box': type === 'callback' }">
  16. <div class="add-box-icon">
  17. <Icon type="md-add" size="32"></Icon>
  18. </div>
  19. <div class="add-box-upload">
  20. <div class="add-box-item" @click="browsePicture">
  21. <span>浏览<em v-if="type === 'callback'">图片</em></span>
  22. </div>
  23. <div class="add-box-item">
  24. <Upload
  25. name="image"
  26. ref="upload"
  27. accept="image/*"
  28. :action="actionUrl"
  29. :data="params"
  30. :show-upload-list="false"
  31. :max-size="2048"
  32. :format="['jpg', 'jpeg', 'gif', 'png']"
  33. :default-file-list="defaultList"
  34. :on-success="handleSuccess"
  35. :on-format-error="handleFormatError"
  36. :on-exceeded-size="handleMaxSize"
  37. :before-upload="handleBeforeUpload"
  38. :multiple=multiple>
  39. <span>上传<em v-if="type === 'callback'">图片</em></span>
  40. </Upload>
  41. </div>
  42. </div>
  43. </div>
  44. <Modal title="浏览图片空间的图片" v-model="browseVisible" class="img-upload-modal" width="710" :styles="{top: '35px',paddingBottom: '35px'}">
  45. <div class="browse-load" v-if="isLoading">加载中...</div>
  46. <div class="browse-list" :class="httpType==='input'?'browse-list-disabled':''" ref="browselistbox">
  47. <div class="browse-item" v-for="item in browseList" @click="browseItem(item)">
  48. <Icon v-if="item.active" class="browse-icon" type="ios-checkmark-circle"></Icon>
  49. <div class="browse-img" v-bind:style="{ 'background-image': 'url(' + item.thumb + ')' }"></div>
  50. <div class="browse-title">{{item.title}}</div>
  51. </div>
  52. </div>
  53. <div slot="footer" class="img-upload-foot">
  54. <div v-if="type !== 'callback' && http && httpType===''" class="img-upload-foot-input" @click="httpType='input'">
  55. <Icon type="ios-image" size="22"/>
  56. <div class="img-upload-foot-httptitle">自定义图片地址</div>
  57. </div>
  58. <div v-if="type !== 'callback' && http && httpType==='input'" class="img-upload-foot-input">
  59. <Input v-model="httpValue" placeholder="以“http://”或“https://”开头" @on-search="httpEnter" search enter-button="确定">
  60. <span slot="prepend" @click="httpType=''" style="cursor:pointer">自定义地址:</span>
  61. </Input>
  62. </div>
  63. <Button v-if="httpType===''" @click="browseVisible=false">关闭</Button>
  64. <Button v-if="httpType===''" type="primary" @click="handleCallback(true)">完成</Button>
  65. </div>
  66. </Modal>
  67. <Modal title="查看图片" v-model="visible" class="img-upload-modal" draggable>
  68. <div style="max-height:480px;overflow:auto;">
  69. <a :href="imgVisible" target="_blank"><img :src="imgVisible" v-if="visible" style="max-width:100%;max-height:900px;display:block;margin:0 auto"></a>
  70. </div>
  71. </Modal>
  72. </div>
  73. </template>
  74. <style lang="scss">
  75. .img-upload-modal {
  76. .ivu-modal-mask {
  77. z-index: 1001;
  78. }
  79. .ivu-modal-no-mask {
  80. background-color: rgba(55,55,55,.2);
  81. }
  82. .ivu-modal-wrap {
  83. z-index: 1001;
  84. }
  85. }
  86. .imgcomp-upload-list{
  87. display: inline-block;
  88. width: 60px;
  89. height: 60px;
  90. text-align: center;
  91. line-height: 60px;
  92. border: 1px solid transparent;
  93. border-radius: 4px;
  94. overflow: hidden;
  95. background: #fff;
  96. position: relative;
  97. box-shadow: 0 1px 1px rgba(0,0,0,.2);
  98. margin-right: 4px;
  99. vertical-align: top;
  100. .imgcomp-upload-img {
  101. position: absolute;
  102. top: 0;
  103. left: 0;
  104. width: 100%;
  105. height: 100%;
  106. background-position: center;
  107. background-size: cover;
  108. }
  109. .imgcomp-upload-list-cover{
  110. display: none;
  111. position: absolute;
  112. top: 0;
  113. bottom: 0;
  114. left: 0;
  115. right: 0;
  116. background: rgba(0,0,0,.6);
  117. }
  118. .imgcomp-upload-list-cover i{
  119. color: #fff;
  120. font-size: 24px;
  121. cursor: pointer;
  122. vertical-align: middle;
  123. margin: 0;
  124. transition: all .2s;
  125. }
  126. .imgcomp-upload-list-cover i:hover{
  127. font-size: 28px;
  128. }
  129. .ivu-progress-outer {
  130. background-color: rgba(0, 0, 0, 0.68);
  131. .ivu-progress-inner{
  132. width: 88%;
  133. }
  134. }
  135. }
  136. .imgcomp-upload-list:hover .imgcomp-upload-list-cover{
  137. display: block;
  138. }
  139. .img-upload-foot {
  140. display: flex;
  141. align-items: center;
  142. justify-content: flex-end;
  143. .img-upload-foot-input {
  144. flex: 1;
  145. text-align: left;
  146. display: flex;
  147. align-items: center;
  148. justify-content: flex-end;
  149. .img-upload-foot-httptitle {
  150. cursor: pointer;
  151. padding-left: 3px;
  152. margin-right: 22px;
  153. }
  154. }
  155. }
  156. .add-box {
  157. width: 60px;
  158. height: 60px;
  159. line-height: 60px;
  160. display: inline-block;
  161. background: #fff;
  162. border: 1px dashed #dddee1;
  163. border-radius: 4px;
  164. text-align: center;
  165. position: relative;
  166. overflow: hidden;
  167. vertical-align: top;
  168. .add-box-icon {
  169. i {
  170. vertical-align:middle;
  171. padding-bottom: 2px;
  172. }
  173. }
  174. .add-box-upload {
  175. display: none;
  176. position: absolute;
  177. top: 0;
  178. left: 0;
  179. height: 100%;
  180. width: 100%;
  181. color: #ffffff;
  182. padding-top: 9px;
  183. background: rgba(0, 0, 0, 0.6);
  184. .add-box-item {
  185. height: 22px;
  186. line-height: 22px;
  187. cursor: pointer;
  188. .ivu-upload-drag,.ivu-upload-drag:hover {
  189. background:transparent;
  190. border:0;
  191. border-radius:0;
  192. }
  193. span {
  194. transition: all .2s;
  195. font-size: 12px;
  196. }
  197. }
  198. .add-box-item:hover {
  199. span {
  200. font-size: 14px;
  201. }
  202. }
  203. }
  204. em {
  205. font-style: normal;
  206. }
  207. }
  208. .add-box:hover {
  209. border-color: rgba(0,0,0,.6);
  210. .add-box-upload {
  211. display: block;
  212. }
  213. }
  214. .callback-add-box {
  215. display: block;
  216. width: auto;
  217. height: 25px;
  218. line-height: 25px;
  219. border: 0;
  220. background: transparent;
  221. .add-box-icon {
  222. display: none;
  223. }
  224. .add-box-upload {
  225. display: block;
  226. width: auto;
  227. background: transparent;
  228. color: #333;
  229. padding: 0;
  230. > div {
  231. display: inline-block;
  232. padding-right: 10px;
  233. }
  234. }
  235. }
  236. .browse-load {
  237. margin: 20px;
  238. text-align: center;
  239. }
  240. .browse-list {
  241. max-height: 540px;
  242. overflow: auto;
  243. .browse-item {
  244. margin: 10px 15px;
  245. display: inline-block;
  246. text-align: center;
  247. cursor: pointer;
  248. position: relative;
  249. .browse-img {
  250. width: 64px;
  251. height: 64px;
  252. background-image: url("../../../statics/images/loading.png");
  253. background-position: center;
  254. background-repeat: no-repeat;
  255. background-size: cover;
  256. }
  257. .browse-title {
  258. display: block;
  259. width: 64px;
  260. margin-top: 5px;
  261. white-space: nowrap;
  262. overflow: hidden;
  263. text-overflow: ellipsis;
  264. }
  265. .browse-icon {
  266. position: absolute;
  267. top: 0;
  268. left: 0;
  269. width: 100%;
  270. height: 64px;
  271. font-size: 36px;
  272. padding-top: 15px;
  273. color: #ffffff;
  274. background-color: rgba(0, 0, 0, 0.5);
  275. }
  276. }
  277. }
  278. .browse-list-disabled {
  279. position: relative;
  280. }
  281. .browse-list-disabled:after {
  282. position: absolute;
  283. content: '';
  284. top: 0;
  285. left: 0;
  286. width: 100%;
  287. height: 100%;
  288. background-color: rgba(255, 255, 255, 0.9);
  289. z-index: 1;
  290. }
  291. </style>
  292. <script>
  293. export default {
  294. name: 'ImgUpload',
  295. props: {
  296. value: {
  297. },
  298. num: {
  299. },
  300. width: {
  301. },
  302. height: {
  303. },
  304. type: {
  305. },
  306. http: {
  307. type: Boolean,
  308. default: false
  309. },
  310. },
  311. data () {
  312. return {
  313. actionUrl: $A.aUrl('imgupload'),
  314. params: {'token': $A.token(), 'width': this.width, 'height': this.height},
  315. multiple: this.num > 1,
  316. visible: false,
  317. browseVisible: false,
  318. isLoading: false,
  319. browseList: [],
  320. browseListNext: [],
  321. imgVisible: '',
  322. defaultList: this.initItems(this.value),
  323. uploadList: [],
  324. maxNum: Math.min(Math.max($A.runNum(this.num), 1), 99),
  325. httpValue: '',
  326. httpType: '',
  327. }
  328. },
  329. mounted () {
  330. this.uploadList = this.$refs.upload.fileList;
  331. this.$emit('input', this.uploadList);
  332. //
  333. let browseBox = $A(this.$refs.browselistbox);
  334. browseBox.scroll(()=>{
  335. let nHight = browseBox[0].scrollHeight;
  336. let nTop = browseBox[0].scrollTop;
  337. let boxHight = browseBox.height();
  338. if(nTop + boxHight >= nHight) {
  339. //到底了
  340. if (this.browseListNext.length > 0) {
  341. let tmpNext = this.browseListNext;
  342. this.browseListNext = [];
  343. this.browsePictureFor(tmpNext);
  344. }
  345. }
  346. });
  347. },
  348. watch: {
  349. value (val) {
  350. if (typeof val === 'string') {
  351. this.$emit('input', this.initItems(val));
  352. return;
  353. }
  354. if (val === this.$refs.upload.fileList) {
  355. return;
  356. }
  357. this.$refs.upload.fileList = this.initItems(val);
  358. this.uploadList = this.$refs.upload.fileList;
  359. },
  360. browseVisible() {
  361. this.httpType = '';
  362. this.httpValue = '';
  363. }
  364. },
  365. methods: {
  366. handleCallback(file) {
  367. if (this.type === 'callback') {
  368. if (file === true) {
  369. this.$emit('on-callback', this.uploadList);
  370. this.$refs.upload.fileList = [];
  371. this.uploadList = this.$refs.upload.fileList;
  372. }else if (typeof file === "object") {
  373. this.$emit('on-callback', [file]);
  374. }
  375. }
  376. this.browseVisible = false;
  377. },
  378. initItems(items) {
  379. //数据初始化
  380. if (typeof items === 'string') {
  381. items = [{'url': items}];
  382. }
  383. let lists = [];
  384. $A.each(items, (index, item)=>{
  385. if (typeof item === 'string') item = {'url': item};
  386. if (item.url) {
  387. item.active = true;
  388. item.status = 'finished';
  389. if (typeof item.path === 'undefined') item.path = item.url;
  390. if (typeof item.thumb === 'undefined') item.thumb = item.url;
  391. lists.push(item);
  392. }
  393. });
  394. return lists;
  395. },
  396. handleView (item) {
  397. //查看
  398. this.visible = true;
  399. this.imgVisible = item.url;
  400. },
  401. handleRemove (item) {
  402. //删除
  403. let fileList = this.$refs.upload.fileList;
  404. this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
  405. this.$emit('input', this.$refs.upload.fileList);
  406. },
  407. handleSuccess (res, file) {
  408. //上传完成
  409. if (res.ret === 1) {
  410. file.url = res.data.url;
  411. file.path = res.data.path;
  412. file.thumb = res.data.thumb;
  413. this.handleCallback(file);
  414. }else{
  415. this.$Modal.warning({
  416. title: '上传失败',
  417. content: '文件 ' + file.name + ' 上传失败,' + res.msg
  418. });
  419. this.$refs.upload.fileList.pop();
  420. }
  421. this.$emit('input', this.$refs.upload.fileList);
  422. },
  423. handleFormatError (file) {
  424. //上传类型错误
  425. this.$Modal.warning({
  426. title: '文件格式不正确',
  427. content: '文件 ' + file.name + ' 格式不正确,请上传 jpg、jpeg、gif、png 格式的图片。'
  428. });
  429. },
  430. handleMaxSize (file) {
  431. //上传大小错误
  432. this.$Modal.warning({
  433. title: '超出文件大小限制',
  434. content: '文件 ' + file.name + ' 太大,不能超过 2M。'
  435. });
  436. },
  437. handleBeforeUpload () {
  438. //上传前判断
  439. let check = this.uploadList.length < this.maxNum;
  440. if (!check) {
  441. this.$Modal.warning({ title: '温馨提示', content: '最多只能上传 ' + this.maxNum + ' 张图片。' });
  442. }
  443. return check;
  444. },
  445. handleClick() {
  446. //手动上传
  447. if (this.handleBeforeUpload()) {
  448. this.$refs.upload.handleClick()
  449. }
  450. },
  451. browsePicture(path) {
  452. //获取图片空间
  453. this.browseVisible = true;
  454. this.browseList = [];
  455. this.browseListNext = [];
  456. this.isLoading = true;
  457. $A.aAjax({
  458. url: 'imgview',
  459. data: { path: path?path:'' },
  460. beforeSend: true,
  461. complete: true,
  462. error: true,
  463. success: (res) => {
  464. this.isLoading = false;
  465. if (res.ret === 1) {
  466. let dirs = res.data['dirs'];
  467. for (let i = 0; i < dirs.length; i++) {
  468. this.browseList.push(dirs[i]);
  469. }
  470. this.browsePictureFor(res.data['files']);
  471. }else if (res.ret === -2) {
  472. this.browseVisible = false;
  473. this.$Modal.warning({ title: '温馨提示', content: res.msg });
  474. }
  475. }
  476. });
  477. },
  478. browsePictureFor(files) {
  479. for (let o = 0; o < files.length; o++) {
  480. for (let j = 0; j < this.uploadList.length; j++) {
  481. if (this.uploadList[j]['url'] === files[o]['url']
  482. || this.uploadList[j]['url'] === files[o]['path']) {
  483. files[o]['active'] = true;
  484. break;
  485. }
  486. }
  487. if (o < 100) {
  488. this.browseList.push(files[o]);
  489. }else{
  490. this.browseListNext.push(files[o]);
  491. }
  492. }
  493. },
  494. browseItem(item) {
  495. //点击选择图片
  496. if (item.type === 'dir') {
  497. //目录
  498. this.browsePicture(item.path);
  499. }else if (item.type === 'file') {
  500. //文件
  501. if (item.active) {
  502. let fileList = this.$refs.upload.fileList;
  503. this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
  504. item.active = false;
  505. }else{
  506. if (this.maxNum === 1) {
  507. for (let i = 0; i < this.browseList.length; i++) {
  508. this.browseList[i].active = false;
  509. }
  510. this.$refs.upload.fileList = [];
  511. this.uploadList = this.$refs.upload.fileList;
  512. }
  513. let check = this.uploadList.length < this.maxNum;
  514. if (!check) {
  515. this.$Modal.warning({ title: '温馨提示', content: '最多只能选择 ' + this.maxNum + ' 张图片。' });
  516. return;
  517. }
  518. item.active = true;
  519. item.status = 'finished';
  520. this.$refs.upload.fileList.push(item);
  521. this.uploadList = this.$refs.upload.fileList;
  522. }
  523. this.$emit('input', this.$refs.upload.fileList);
  524. }
  525. },
  526. __thumb(url) {
  527. if ($A.strExists(url, "?", false)) {
  528. return url + "&__thumb=true";
  529. }else{
  530. return url + "?__thumb=true";
  531. }
  532. },
  533. httpEnter() {
  534. this.$emit('input', this.initItems(this.httpValue));
  535. this.browseVisible = false;
  536. }
  537. }
  538. }
  539. </script>