uploadVNormal.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. <template>
  2. <div class="questionNamep">
  3. <!-- 0=企业微信,1=H5相机 -->
  4. <!-- 企业微信拍照 -->
  5. <div class="cameraDiv" @click="uploadImg" v-if="userInfo.photoMethod == '0'">
  6. <van-icon class="photo photos" name="photograph" size="22px" color="#969696" />
  7. </div>
  8. <!-- 原生自带拍照 -->
  9. <H5Camera
  10. @getImg="getImg"
  11. ref="H5Camera"
  12. :objectType="objectType"
  13. :capture="pictureSource == '1' ? '' : 'camera'"
  14. v-else />
  15. <div id="allmap"></div>
  16. <div class="mask" v-if="progressFlag">
  17. <el-progress
  18. type="circle"
  19. :percentage="percentage"
  20. :show-text="true"
  21. :width="110"
  22. :format="format"></el-progress>
  23. <div class="progressClose" @click="progressClose">取消</div>
  24. </div>
  25. <imageAIVerifyErr
  26. v-if="imageAIVerifyFlag"
  27. :imageAIVerifyFlag="imageAIVerifyFlag"
  28. :imageAIVerifyData="imageAIVerifyData"
  29. @confirmUpload="confirmUpload"
  30. @uploadImgFun="uploadImgFun"
  31. :source="'visit'"
  32. @normalFlow="normalFlow"
  33. @close="close"></imageAIVerifyErr>
  34. <!-- 图像识别白名单弹框提示 -->
  35. <imageWhiteStore
  36. v-if="imageWhiteStoreFlag"
  37. :imageWhiteStoreFlag="imageWhiteStoreFlag"
  38. :imageWhiteStoreData="imageWhiteStoreData"
  39. @normalFlow="normalFlow"
  40. @close="close">
  41. </imageWhiteStore>
  42. </div>
  43. </template>
  44. <script>
  45. import { addstorePhoto, addVisitsPosition, addPhotoToDB } from '@/api/index';
  46. import imageAIVerifyErr from './imageAIVerifyErr';
  47. import imageWhiteStore from './imageWhiteStore';
  48. import H5Camera from '@/components/H5Camera';
  49. import axios from 'axios';
  50. import uploadAliOss from '@/utils/uploadAliOss';
  51. import { addH5Photo } from '@/api/H5Camera';
  52. import { mapState } from 'vuex';
  53. export default {
  54. name: 'uploadImg',
  55. components: { imageAIVerifyErr, H5Camera, imageWhiteStore },
  56. props: {
  57. uploadid: {
  58. type: String,
  59. default: '',
  60. },
  61. storeGroupId: {
  62. type: String,
  63. default: '',
  64. },
  65. parentCollectionId: {
  66. type: String,
  67. default: '',
  68. },
  69. secondCollectionId: {
  70. type: [String, Number],
  71. default: '',
  72. },
  73. firstCollectionId: {
  74. type: String,
  75. default: '',
  76. },
  77. fourthCollectionId: {
  78. type: String,
  79. default: '',
  80. },
  81. thirdCollectionId: {
  82. type: String,
  83. default: '',
  84. },
  85. visitsId: {
  86. type: String,
  87. default: '',
  88. },
  89. taskId: {
  90. type: String,
  91. default: '',
  92. },
  93. collectionId: {
  94. type: String,
  95. default: '',
  96. },
  97. objectType: {
  98. type: String,
  99. default: '',
  100. },
  101. type: {
  102. type: Number,
  103. default: 1,
  104. },
  105. imgArr: {
  106. type: Array,
  107. default() {
  108. return [];
  109. },
  110. },
  111. visitModel: {
  112. type: String,
  113. default: '1',
  114. },
  115. deviceCode: {
  116. type: String,
  117. default: '',
  118. },
  119. putInCode: {
  120. type: String,
  121. default: '',
  122. },
  123. pictureSource: {
  124. // 是否允许从相册选择图片 1:允许;0:不允许
  125. type: String,
  126. default: '0',
  127. },
  128. photoIdentifyType: {
  129. // 图匠识别目的(1:店招内容识别(不能连拍和多选),3:调色机识别(不能连拍和多选),6:陈列SKU图片识别(不需要图匠实时识别))
  130. type: String,
  131. default: '',
  132. },
  133. continuousShoot: {
  134. // 是否允许连拍/相册多选 1:允许;0:不允许
  135. type: String,
  136. default: '0',
  137. },
  138. equipmentCode: {
  139. // 当前任务对应的资产编号
  140. type: String,
  141. default: '',
  142. },
  143. inStore: {
  144. // 调色机是否在店
  145. type: String,
  146. default: '否',
  147. },
  148. },
  149. computed: {
  150. ...mapState({
  151. userInfo: (state) => state.user.userInfo,
  152. }),
  153. },
  154. data() {
  155. return {
  156. shows: false,
  157. url: '',
  158. progressFlag: false,
  159. percentage: 0,
  160. timeFlag: null,
  161. imageAIVerifyFlag: false,
  162. imageAIVerifyData: null, //图匠校验返回的数据
  163. mediaId: '', //当前上传图片id
  164. addressesRemark: '', //当前位置信息
  165. controller: null, //取消请求状态
  166. fileUrl: '',
  167. imageWhiteStoreData: null,
  168. imageWhiteStoreFlag: false,
  169. localIdsArr: [],
  170. };
  171. },
  172. methods: {
  173. // 原生H5拍照图片
  174. // url: base64
  175. getImg(base64) {
  176. // 图片名称:用户名-时间戳
  177. let username = localStorage.getItem('loginName');
  178. let imgName = username + '-' + new Date().getTime();
  179. uploadAliOss(base64, imgName)
  180. .then((res) => {
  181. if (res.url && res.url.indexOf('http') != -1) {
  182. this.fileUrl = res.url;
  183. this.uploadImagev();
  184. }
  185. })
  186. .catch((err) => {
  187. console.log('err:' + err);
  188. });
  189. },
  190. uploadImgFun() {
  191. // 0=企业微信,1=H5相机
  192. if (this.userInfo.photoMethod == '0') {
  193. this.uploadImg();
  194. } else {
  195. this.$refs.H5Camera.camera();
  196. }
  197. },
  198. uploadImg() {
  199. var map = new TMap.Map('allmap', {
  200. zoom: 14,
  201. center: new TMap.LatLng(39.986785, 116.301012),
  202. });
  203. var geocoder = new TMap.service.Geocoder(); // 新建一个正逆地址解析类
  204. var markers = new TMap.MultiMarker({
  205. map: map,
  206. geometries: [],
  207. });
  208. markers.setGeometries([]);
  209. if (this.objectType == '' || this.objectType == null) {
  210. this.$toast('请选择类型!');
  211. return;
  212. }
  213. let url = window.location.href;
  214. let that = this;
  215. let wx = this.wx;
  216. let qiyeData;
  217. this.addressesRemark = '';
  218. const instance = axios.create();
  219. instance.defaults.headers.common['userId'] = localStorage.getItem('loginName');
  220. instance
  221. .get(process.env.VUE_APP_BASE_API + 'mobile/wx/ticket', {
  222. params: {
  223. url: url,
  224. },
  225. })
  226. .then((response) => {
  227. if (response.status == 200) {
  228. qiyeData = response.data.data;
  229. wx.config({
  230. beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
  231. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  232. appId: qiyeData.appId, // 必填,企业微信的corpID
  233. timestamp: qiyeData.timestamp, // 必填,生成签名的时间戳
  234. nonceStr: qiyeData.nonceStr, // 必填,生成签名的随机串
  235. signature: qiyeData.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
  236. jsApiList: ['ready', 'chooseImage', 'uploadImage', 'getLocation'], // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
  237. });
  238. wx.ready(function () {
  239. wx.getLocation({
  240. type: 'gcj02',
  241. success: function (res) {
  242. var location = new TMap.LatLng(res.latitude, res.longitude);
  243. map.setCenter(location);
  244. markers.updateGeometries([
  245. {
  246. id: 'main', // 点标注数据数组
  247. position: location,
  248. },
  249. ]);
  250. geocoder.getAddress({ location: location }).then(
  251. function (result) {
  252. var addresses = result.result.formatted_addresses;
  253. that.addressesRemark = addresses.recommend;
  254. },
  255. function (err) {
  256. that.addressesRemark = '';
  257. }
  258. );
  259. },
  260. fail: function () {
  261. that.$dialog.alert({
  262. message: 'GPS未开启',
  263. });
  264. },
  265. });
  266. console.log(that.pictureSource);
  267. let sourceType = that.pictureSource == '1' ? ['album', 'camera'] : ['camera'];
  268. let count = 1;
  269. // 1:店招内容识别(不能连拍和多选),3:调色机识别(不能连拍和多选) 需要实时识别的不支持连拍和多选
  270. if (that.photoIdentifyType != 1 && that.photoIdentifyType != 3) {
  271. count = that.continuousShoot == '1' ? 5 : 1; //是否允许连拍/相册多选 最多5张
  272. }
  273. wx.chooseImage({
  274. count: count,
  275. sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有
  276. sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有
  277. defaultCameraMode: count == 1 ? 'normal' : 'batch', //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
  278. // defaultCameraMode: 'normal', //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
  279. isSaveToAlbum: 0, //整型值,0表示拍照时不保存到系统相册,1表示自动保存,默认值是1
  280. success: function (res) {
  281. let localIds = res.localIds;
  282. that.localIdsArr = [];
  283. that.syncUpload(localIds);
  284. // var localIds = '';
  285. // if (res.localIds != undefined) {
  286. // localIds = res.localIds[0];
  287. // } else {
  288. // localIds = res.localId;
  289. // }
  290. // wx.uploadImage({
  291. // localId: localIds, // 需要上传的图片的本地ID,由chooseImage接口获得
  292. // isShowProgressTips: 0, // 默认为1,显示进度提示
  293. // success: function (res) {
  294. // that.mediaId = res.serverId;
  295. // that.uploadImagev(addressesRemark);
  296. // },
  297. // fail: (err) => {
  298. // that.$toast(err.errMsg);
  299. // that.$toast(err.errCode);
  300. // },
  301. // });
  302. },
  303. });
  304. });
  305. }
  306. });
  307. },
  308. syncUpload(localIds) {
  309. if (!localIds.length) {
  310. this.uploadImagev();
  311. } else {
  312. var localId = localIds.pop();
  313. wx.uploadImage({
  314. localId: localId,
  315. isShowProgressTips: 1, // 默认为1,显示进度提示
  316. success: (res) => {
  317. this.localIdsArr.push(res.serverId);
  318. this.syncUpload(localIds);
  319. },
  320. });
  321. }
  322. },
  323. uploadImagev() {
  324. // 初始化重置 图匠校验
  325. this.resetProgress();
  326. this.close();
  327. var that = this;
  328. var parentCollectionId = null;
  329. if (that.parentCollectionId != null && that.parentCollectionId != 'null') {
  330. parentCollectionId = that.parentCollectionId;
  331. }
  332. var secondCollectionId = null;
  333. if (that.secondCollectionId != null && that.secondCollectionId != 'null') {
  334. secondCollectionId = that.secondCollectionId;
  335. }
  336. var firstCollectionId = null;
  337. if (that.firstCollectionId != null && that.firstCollectionId != 'null') {
  338. firstCollectionId = that.firstCollectionId;
  339. }
  340. var fourthCollectionId = null;
  341. if (that.fourthCollectionId != null && that.fourthCollectionId != 'null') {
  342. fourthCollectionId = that.fourthCollectionId;
  343. }
  344. var thirdCollectionId = null;
  345. if (that.thirdCollectionId != null && that.thirdCollectionId != 'null') {
  346. thirdCollectionId = that.thirdCollectionId;
  347. }
  348. var form = {
  349. mediaIds: [],
  350. fileUrl: '',
  351. collectionItemId: that.collectionId,
  352. objectType: that.objectType,
  353. storeGroupId: that.storeGroupId,
  354. taskId: that.taskId,
  355. visitsId: localStorage.getItem('visitId'),
  356. visitModel: that.visitModel,
  357. visitSource: '1',
  358. locationRemark: that.addressesRemark,
  359. parentCollectionId: parentCollectionId,
  360. secondCollectionId: secondCollectionId,
  361. firstCollectionId: firstCollectionId,
  362. fourthCollectionId: fourthCollectionId,
  363. thirdCollectionId: thirdCollectionId,
  364. deviceCode: that.deviceCode, //设备编号
  365. putInCode: that.putInCode, //投放编号
  366. equipmentCode: that.equipmentCode,
  367. inStore: that.inStore,
  368. };
  369. // 0=企业微信,1=H5相机
  370. if (this.userInfo.photoMethod == '0') {
  371. form.mediaIds = this.localIdsArr; // string 图片素材id
  372. } else {
  373. form.fileUrl = this.fileUrl; // string 图片素材id
  374. }
  375. this.controller = null;
  376. // 需要图匠校验的添加参数和loading
  377. if (
  378. this.photoIdentifyType &&
  379. (this.photoIdentifyType == '1' || this.photoIdentifyType == '3')
  380. ) {
  381. form.photoIdentifyType = this.photoIdentifyType;
  382. this.progress();
  383. this.controller = new AbortController(); //取消请求
  384. } else {
  385. this.toastLoading(0, '上传中...', true);
  386. }
  387. addstorePhoto(form, this.controller ? this.controller.signal : null)
  388. .then((res) => {
  389. this.requestThen(res);
  390. })
  391. .catch((error) => {
  392. this.requestCatch(error);
  393. });
  394. },
  395. // 公用请求then
  396. requestThen(res) {
  397. this.toastLoading().clear();
  398. if (res.code == -1) {
  399. // 图匠图片校验接口超时
  400. this.requestTimeOut(res);
  401. } else if (res.code == 200) {
  402. // 图匠校验结果返回
  403. if (
  404. this.photoIdentifyType &&
  405. (this.photoIdentifyType == '1' || this.photoIdentifyType == '3')
  406. ) {
  407. // 重置loaidng状态
  408. this.resetProgress();
  409. this.imageAIVerifyFlag = true;
  410. this.imageAIVerifyData = res.data[0];
  411. } else {
  412. // 正常流程
  413. // 图像识别白名单用户弹出框提示
  414. if (res.data[0].whiteStore) {
  415. this.imageWhiteStoreFlag = true;
  416. this.imageWhiteStoreData = res.data[0];
  417. } else {
  418. this.normalFlow(res);
  419. }
  420. }
  421. } else {
  422. this.resetProgress();
  423. that.$toast('上传失败!');
  424. }
  425. },
  426. // 公用请求catch
  427. requestCatch(error) {
  428. if (error.message === 'canceled') {
  429. this.$toast('取消上传');
  430. console.log('请求被取消:', error.message);
  431. }
  432. this.resetProgress();
  433. },
  434. // 正常流程
  435. normalFlow(res) {
  436. this.$toast('上传成功!');
  437. let fileInfoList = [];
  438. res.data.forEach((val) => {
  439. fileInfoList.push({
  440. fileUrl: val.url,
  441. id: val.fileId,
  442. type: 2,
  443. });
  444. });
  445. this.$emit('newimgarr', {
  446. fileInfoList: fileInfoList,
  447. // fileUrl: res.data.url,
  448. // id: res.data.fileId,
  449. // type: 2,
  450. photoIdentifyType: this.photoIdentifyType,
  451. });
  452. },
  453. progress() {
  454. // 后端接口20000ms后失效,每1000m progress加10,到90停止;
  455. this.progressFlag = true;
  456. this.percentage = 10;
  457. this.timeFlag = setInterval(() => {
  458. this.percentage = this.percentage + 10;
  459. if (this.percentage == 90) clearInterval(this.timeFlag);
  460. }, 1000);
  461. },
  462. format(percentage) {
  463. return `${percentage} %\n图像识别中`;
  464. },
  465. // 重置loaidng状态
  466. resetProgress() {
  467. this.percentage = 100;
  468. clearInterval(this.timeFlag);
  469. this.progressFlag = false;
  470. this.percentage = 0;
  471. },
  472. // 照片是否入库,1.照片识别三次不通过仍要上传,2.照片识别通过
  473. // isUpdate:是否更新店招照片,只有门店店招需要更新
  474. confirmUpload(res) {
  475. if (this.photoIdentifyType && this.photoIdentifyType != '6') {
  476. var form = {
  477. mediaIds: [],
  478. fileUrl: '',
  479. visitSource: '1', // Long 拜访模式
  480. storeGroupId: this.storeGroupId, // string 门店任务组,多个用逗号隔开
  481. visitsId: localStorage.getItem('visitId'), // string 拜访id
  482. taskId: this.taskId, // string 任务id
  483. objectType: this.objectType, // string 照片类型,取任务上的照片类型,如果没有则取手动选择的照片类型
  484. locationRemark: this.addressesRemark, // String 当前地址信息
  485. firstCollectionId: this.firstCollectionId, // Long 第一级采集项id,取当前采集项的字段就行
  486. secondCollectionId: this.secondCollectionId, // Long 第二级采集项id,取当前采集项的字段就行
  487. putInCode: this.putInCode, // String 当前任务对应的投放编号
  488. deviceCode: this.deviceCode, // String 当前任务对应的设备编号
  489. collectionItemId: this.collectionId,
  490. url: res.data.url, // String 当前拍摄图片的url
  491. businessId: res.data.businessId, // 当前拍摄图片id
  492. feedbackMessage: res.feedbackMessage,
  493. equipmentCode: this.equipmentCode,
  494. inStore: this.inStore,
  495. };
  496. // 0=企业微信,1=H5相机
  497. if (this.userInfo.photoMethod == '0') {
  498. form.mediaIds = this.localIdsArr; // string 图片素材id
  499. } else {
  500. form.fileUrl = this.fileUrl; // string 图片素材id
  501. }
  502. if (res.isUpdate) {
  503. form.isUpdate = 'true';
  504. }
  505. addPhotoToDB(form).then((resData) => {
  506. if (resData.code == 200) {
  507. console.log(resData);
  508. res.data.fileId = resData.data[0].fileId;
  509. res.data = [res.data];
  510. this.normalFlow(res);
  511. }
  512. });
  513. }
  514. },
  515. close() {
  516. this.imageAIVerifyFlag = false;
  517. this.imageWhiteStoreFlag = false;
  518. },
  519. requestTimeOut(res) {
  520. this.resetProgress();
  521. this.close();
  522. this.$dialog
  523. .confirm({
  524. title: '系统提示',
  525. message: res.msg,
  526. showCancelButton: false,
  527. })
  528. .then(() => {
  529. this.confirmUpload(res);
  530. });
  531. },
  532. // 取消图片上传
  533. progressClose() {
  534. this.controller.abort();
  535. },
  536. },
  537. };
  538. </script>
  539. <style lang="scss" scoped>
  540. .questionNamep {
  541. font-size: 16px;
  542. color: #484848;
  543. // line-height: 40px;
  544. padding: 0 15px;
  545. box-sizing: border-box;
  546. position: relative;
  547. .cameraDivp {
  548. flex: 1;
  549. display: flex;
  550. align-items: center;
  551. justify-content: center;
  552. .photo {
  553. /*margin-top: 9px;*/
  554. float: right;
  555. }
  556. .camera {
  557. width: 60px;
  558. height: 100%;
  559. position: absolute;
  560. right: 0;
  561. top: 0;
  562. opacity: 0;
  563. z-index: 89;
  564. }
  565. }
  566. .mask {
  567. position: fixed;
  568. top: 0;
  569. left: 0;
  570. right: 0;
  571. bottom: 0;
  572. width: 100%;
  573. height: 100%;
  574. background: rgba(255, 255, 255, 1);
  575. display: flex;
  576. justify-content: center;
  577. align-items: center;
  578. z-index: 99999999;
  579. display: flex;
  580. flex-direction: column;
  581. .progressClose {
  582. width: 70px;
  583. text-align: center;
  584. background: #67c23a;
  585. color: #fff;
  586. height: 30px;
  587. line-height: 30px;
  588. border-radius: 5px;
  589. margin-top: 5px;
  590. font-size: 12px;
  591. }
  592. }
  593. }
  594. #allmap {
  595. width: 10px;
  596. height: 10px;
  597. left: -1000px;
  598. position: absolute;
  599. }
  600. </style>
  601. <style lang="scss">
  602. .mask {
  603. .el-progress__text {
  604. white-space: pre-wrap;
  605. }
  606. }
  607. </style>