index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <template>
  2. <div>
  3. <el-dialog
  4. title="上传图片"
  5. append-to-body
  6. :modal-append-to-body="true"
  7. :visible.sync="uploadModal"
  8. :width="isIframe ? '100%' : '1024px'"
  9. :fullscreen="isIframe"
  10. @close="closed"
  11. top="5vh"
  12. >
  13. <div class="main" v-loading="loading">
  14. <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
  15. <el-form-item label="上传方式:" prop="type">
  16. <el-radio-group v-model="ruleForm.type" @change="radioChange(ruleForm.type)">
  17. <el-radio :label="0">本地上传</el-radio>
  18. <el-radio :label="1">网络上传</el-radio>
  19. <el-radio :label="2">扫码上传</el-radio>
  20. </el-radio-group>
  21. </el-form-item>
  22. <el-form-item label="上传至分组:" prop="region" v-show="ruleForm.type == 0 || ruleForm.type == 1">
  23. <el-cascader
  24. class="form-width"
  25. v-model="ruleForm.region"
  26. :props="props"
  27. :options="categoryList"
  28. @change="handleChange"
  29. ></el-cascader>
  30. </el-form-item>
  31. <el-form-item label="网络图片:" prop="region" v-if="ruleForm.type == 1">
  32. <el-input class="form-width" v-model="webImgUrl" placeholder="请网络图片地址"></el-input>
  33. <span class="tq-text" @click="getImg">提取照片</span>
  34. </el-form-item>
  35. <el-form-item label="上传图片:" prop="region" v-if="ruleForm.type == 0">
  36. <div class="acea-row">
  37. <div class="uploadCont">
  38. <el-upload
  39. ref="upload"
  40. :action="fileUrl"
  41. list-type="picture-card"
  42. :on-change="fileChange"
  43. :file-list="ruleForm.imgList"
  44. :auto-upload="false"
  45. :data="uploadData"
  46. :headers="header"
  47. :before-upload="beforeUpload"
  48. :multiple="true"
  49. :limit="limit"
  50. >
  51. <i slot="default" class="el-icon-plus"></i>
  52. <div
  53. slot="file"
  54. slot-scope="{ file }"
  55. draggable="false"
  56. @dragstart="handleDragStart($event, file)"
  57. @dragover="handleDragOver($event, file)"
  58. @dragenter="handleDragEnter($event, file)"
  59. @dragend="handleDragEnd($event, file)"
  60. >
  61. <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
  62. <i class="el-icon-error btndel" @click="handleWebRemove(file)" />
  63. </div>
  64. </el-upload>
  65. <div class="tips">建议上传图片最大宽度750px,不超过3MB;仅支持jpeg、png格式,可拖拽调整上传顺序</div>
  66. </div>
  67. </div>
  68. </el-form-item>
  69. <template v-if="ruleForm.type == 1">
  70. <div class="img-box pl100">
  71. <div
  72. v-for="(item, index) in ruleForm.imgList"
  73. :key="index"
  74. class="pictrue"
  75. draggable="false"
  76. @dragstart="handleDragStart($event, item)"
  77. @dragover.prevent="handleDragOver($event, item)"
  78. @dragenter="handleDragEnter($event, item)"
  79. @dragend="handleDragEnd($event, item)"
  80. >
  81. <img :src="item.url" />
  82. <i class="el-icon-error btndel" @click="handleRemove(index)" />
  83. </div>
  84. </div>
  85. </template>
  86. <div class="code-image" v-if="ruleForm.type == 2">
  87. <div class="left">
  88. <el-form-item label="上传至分组:" prop="region">
  89. <el-cascader
  90. class="form-width"
  91. v-model="ruleForm.region"
  92. :props="props"
  93. :options="categoryList"
  94. @change="handleChange"
  95. ></el-cascader>
  96. </el-form-item>
  97. <el-form-item label="二维码:" prop="region">
  98. <div class="code" ref="qrCodeUrl"></div>
  99. <div class="trip">扫描二维码,快速上传手机图片</div>
  100. <div class="trip-small">建议使用手机浏览器</div>
  101. </el-form-item>
  102. </div>
  103. <div class="right">
  104. <el-button size="small" @click="scanUploadGet">刷新图库</el-button>
  105. <div class="tip">刷新图库按钮,可显示移动端上传成功的图片</div>
  106. <div class="img-box">
  107. <div
  108. v-for="(item, index) in ruleForm.imgList"
  109. :key="index"
  110. class="pictrue"
  111. draggable="false"
  112. @dragstart="handleDragStart($event, item)"
  113. @dragover.prevent="handleDragOver($event, item)"
  114. @dragenter="handleDragEnter($event, item)"
  115. @dragend="handleDragEnd($event, item)"
  116. >
  117. <img :src="item.att_dir" />
  118. <i class="el-icon-error btndel" @click="handleWebRemove(item)" />
  119. </div>
  120. </div>
  121. </div>
  122. </div>
  123. </el-form>
  124. </div>
  125. <span slot="footer" class="dialog-footer">
  126. <el-button @click="clear">取 消</el-button>
  127. <el-button type="primary" @click="submitUpload">确 定</el-button>
  128. </span>
  129. </el-dialog>
  130. </div>
  131. </template>
  132. <script>
  133. import { getCategoryListApi, moveApi, onlineUpload, scanUploadCode } from '@/api/uploadPictures';
  134. import Setting from '@/setting';
  135. import { getCookies } from '@/libs/util';
  136. import { fileUpload, scanUploadQrcode, scanUploadGet } from '@/api/setting';
  137. import QRCode from 'qrcodejs2';
  138. import compressImg from '@/utils/compressImg.js';
  139. export default {
  140. name: '',
  141. props: {
  142. categoryList: {
  143. default: () => {
  144. return [];
  145. },
  146. },
  147. categoryId: {
  148. default: '',
  149. },
  150. isPage: {
  151. default: false,
  152. },
  153. isIframe: {
  154. default: false,
  155. },
  156. },
  157. watch: {
  158. uploadModal: {
  159. handler(newVal) {
  160. if (newVal) this.ruleForm.region = this.categoryId;
  161. },
  162. immediate: true,
  163. },
  164. },
  165. data() {
  166. return {
  167. webImgUrl: '',
  168. uploadModal: false,
  169. fileUrl: Setting.apiBaseURL + '/file/upload',
  170. header: {
  171. 'Authori-zation': 'Bearer ' + getCookies('token'),
  172. },
  173. uploadData: {},
  174. props: { checkStrictly: true, emitPath: false, label: 'title', value: 'id' },
  175. disabled: false,
  176. ruleForm: {
  177. type: 0,
  178. region: '',
  179. imgList: [],
  180. },
  181. rules: { type: [{ required: true, message: '请选择活动资源', trigger: 'change' }] },
  182. qrcode: '',
  183. scanToken: '',
  184. limit: 20,
  185. loading: false,
  186. time: undefined,
  187. };
  188. },
  189. created() {},
  190. mounted() {},
  191. beforeDestroy() {
  192. clearInterval(this.time);
  193. this.time = undefined;
  194. },
  195. methods: {
  196. radioChange(type) {
  197. this.ruleForm.type = type;
  198. this.ruleForm.imgList = [];
  199. clearInterval(this.time);
  200. this.time = undefined;
  201. if (type == 2) {
  202. this.scanUploadQrcode();
  203. this.time = setInterval((e) => {
  204. this.scanUploadGet();
  205. }, 2000);
  206. }
  207. },
  208. scanUploadQrcode() {
  209. scanUploadQrcode(this.ruleForm.region).then((res) => {
  210. this.creatQrCode(res.data.url);
  211. this.scanToken = res.data.url;
  212. });
  213. },
  214. scanUploadGet() {
  215. let token = this.scanToken.split('token=')[1];
  216. scanUploadGet(token).then((res) => {
  217. this.ruleForm.imgList = res.data;
  218. console.log(res);
  219. });
  220. },
  221. getImg() {
  222. if (!this.webImgUrl) {
  223. this.$message.error('请先输入图片地址');
  224. return;
  225. }
  226. this.ruleForm.imgList.push({
  227. url: this.webImgUrl,
  228. });
  229. },
  230. async submitUpload() {
  231. if (this.ruleForm.type == 0) {
  232. this.uploadData = {
  233. pid: this.ruleForm.region,
  234. };
  235. if (this.ruleForm.imgList.length) {
  236. if (this.loading) return;
  237. this.loading = true;
  238. for (let i = 0; i < this.ruleForm.imgList.length; i++) {
  239. const file = this.ruleForm.imgList[i].raw;
  240. await this.uploadItem(file);
  241. if (i == this.ruleForm.imgList.length - 1) {
  242. this.$message.success('上传成功');
  243. this.$emit('uploadSuccess');
  244. this.uploadModal = false;
  245. this.loading = false;
  246. this.initData();
  247. }
  248. }
  249. }
  250. } else if (this.ruleForm.type == 1) {
  251. let urls = this.ruleForm.imgList.map((e) => {
  252. return e.url;
  253. });
  254. if (urls.length) {
  255. if (this.loading) return;
  256. this.loading = true;
  257. onlineUpload({ pid: this.ruleForm.region, images: urls })
  258. .then((res) => {
  259. this.$message.success('上传成功');
  260. this.$emit('uploadSuccess');
  261. this.uploadModal = false;
  262. this.loading = false;
  263. this.initData();
  264. })
  265. .catch((err) => {
  266. this.loading = false;
  267. this.$message.error(err.msg);
  268. });
  269. }
  270. } else if (this.ruleForm.type == 2) {
  271. let attId = this.ruleForm.imgList.map((e) => {
  272. return e.att_id;
  273. });
  274. moveApi({ pid: this.ruleForm.region, images: attId }).then((res) => {
  275. this.$message.success('上传成功');
  276. this.$emit('uploadSuccess');
  277. this.uploadModal = false;
  278. this.initData();
  279. });
  280. }
  281. },
  282. uploadItem(file) {
  283. return new Promise((resolve, reject) => {
  284. const formData = new FormData();
  285. formData.append('file', file);
  286. formData.append('pid', this.ruleForm.region);
  287. fileUpload(formData)
  288. .then((res) => {
  289. if (res.status == 200) {
  290. resolve();
  291. // this.$emit('uploadImgSuccess', res.data);
  292. } else {
  293. this.loading = false;
  294. this.$message({
  295. message: '上传失败',
  296. type: 'error',
  297. duration: 1000,
  298. });
  299. }
  300. })
  301. .catch((err) => {
  302. this.loading = false;
  303. this.$message.error(err.msg);
  304. });
  305. });
  306. },
  307. beforeUpload(file) {},
  308. creatQrCode(url) {
  309. this.$refs.qrCodeUrl.innerHTML = '';
  310. var qrcode = new QRCode(this.$refs.qrCodeUrl, {
  311. text: url, // 需要转换为二维码的内容
  312. width: 160,
  313. height: 160,
  314. colorDark: '#000000',
  315. colorLight: '#ffffff',
  316. correctLevel: QRCode.CorrectLevel.H,
  317. });
  318. },
  319. handleWebRemove(file) {
  320. console.log(file);
  321. let index = this.ruleForm.imgList.findIndex((e) => {
  322. return e.url == file.url;
  323. });
  324. this.ruleForm.imgList.splice(index, 1);
  325. },
  326. handleRemove(index) {
  327. this.ruleForm.imgList.splice(index, 1);
  328. },
  329. handlePictureCardPreview(file) {
  330. this.dialogImageUrl = file.url;
  331. this.dialogVisible = true;
  332. },
  333. handleDownload(file) {
  334. console.log(file);
  335. },
  336. async fileChange(file, fileList) {
  337. if (file.size >= 2097152) {
  338. await this.comImg(file.raw).then((res) => {
  339. fileList.map((e) => {
  340. if (e.uid === file.uid) {
  341. e.raw = res;
  342. }
  343. });
  344. this.ruleForm.imgList = fileList;
  345. });
  346. } else {
  347. this.ruleForm.imgList = fileList;
  348. }
  349. },
  350. comImg(file) {
  351. return new Promise((resolve, reject) => {
  352. compressImg(file).then((res) => {
  353. resolve(res);
  354. });
  355. });
  356. },
  357. loadData(item, callback) {
  358. getCategoryListApi({
  359. pid: item.value,
  360. })
  361. .then(async (res) => {
  362. const data = res.data.list;
  363. callback(data);
  364. })
  365. .catch((res) => {});
  366. },
  367. handleChange(e) {
  368. if (this.ruleForm.type == 2) this.scanUploadQrcode();
  369. },
  370. // 移动
  371. handleDragStart(e, item) {
  372. this.dragging = item;
  373. },
  374. handleDragEnd(e, item) {
  375. this.dragging = null;
  376. },
  377. handleDragOver(e) {
  378. e.dataTransfer.dropEffect = 'move';
  379. },
  380. handleDragEnter(e, item) {
  381. e.dataTransfer.effectAllowed = 'move';
  382. if (item === this.dragging) {
  383. return;
  384. }
  385. const newItems = [...this.ruleForm.imgList];
  386. const src = newItems.indexOf(this.dragging);
  387. const dst = newItems.indexOf(item);
  388. newItems.splice(dst, 0, ...newItems.splice(src, 1));
  389. this.ruleForm.imgList = newItems;
  390. },
  391. closed() {
  392. this.initData();
  393. scanUploadCode().then((res) => {});
  394. },
  395. clear() {
  396. this.uploadModal = false;
  397. this.initData();
  398. },
  399. initData() {
  400. this.ruleForm.type = 0;
  401. this.ruleForm.region = 0;
  402. this.scanToken = '';
  403. this.webImgUrl = '';
  404. this.ruleForm.imgList = [];
  405. clearInterval(this.time);
  406. this.time = undefined;
  407. },
  408. },
  409. };
  410. </script>
  411. <style lang="stylus" scoped>
  412. /deep/ .el-dialog__title{
  413. font-size: 16px;
  414. }
  415. .main{
  416. min-height: 500px
  417. }
  418. .pictrue {
  419. width: 60px;
  420. height: 60px;
  421. border: 1px dotted rgba(0, 0, 0, 0.1);
  422. margin-right: 10px;
  423. position: relative;
  424. cursor: pointer;
  425. img {
  426. width: 100%;
  427. height: 100%;
  428. }
  429. }
  430. .btndel {
  431. position: absolute;
  432. z-index: 1;
  433. font-size: 18px;
  434. right: -5px;
  435. top: -5px;
  436. color #999
  437. }
  438. .form-width{
  439. width 280px
  440. }
  441. .tq-text{
  442. margin-left 14px
  443. font-size: 12px;
  444. font-weight: 400;
  445. color: #1890FF;
  446. cursor pointer
  447. }
  448. /deep/ .el-upload--picture-card, /deep/ .el-upload-list--picture-card .el-upload-list__item{
  449. width 64px
  450. height 64px
  451. line-height: 72px;
  452. overflow inherit
  453. }
  454. /deep/ .el-upload--picture-card, /deep/ .el-upload-list--picture-card .el-upload-list__item img{
  455. width 64px
  456. height 64px
  457. border-radius: 6px;
  458. object-fit: cover;
  459. }
  460. .pl100{
  461. padding-left 100px
  462. }
  463. .img-box{
  464. display flex
  465. flex-wrap: wrap
  466. }
  467. .tips{
  468. font-size: 12px;
  469. color #BBBBBB
  470. }
  471. .code-image{
  472. display flex
  473. margin-top 12px
  474. .left{
  475. display flex
  476. flex-direction: column
  477. margin-right 20px
  478. align-items center
  479. .code{
  480. border: 1px solid #DDDDDD;
  481. display flex
  482. align-items center
  483. justify-content center
  484. width 200px
  485. height 200px
  486. border-radius: 4px
  487. .code-img{
  488. width 160px
  489. height 160px
  490. }
  491. }
  492. .form-width{
  493. width 200px
  494. }
  495. .code{
  496. margin-bottom 14px
  497. }
  498. .trip{
  499. color #333333
  500. text-align: center
  501. line-height: 18px;
  502. }
  503. .trip-small{
  504. font-size: 12px;
  505. font-weight: 400;
  506. color: #BBBBBB;
  507. text-align: center
  508. line-height: 16px;
  509. }
  510. }
  511. .right{
  512. margin-top: 62px;
  513. .tip{
  514. font-size: 12px;
  515. font-weight: 400;
  516. color: #BBBBBB;
  517. margin 10px 0
  518. }
  519. }
  520. }
  521. </style>