Browse Source

Merge branch 'feature_20241120_图像识别' into uat(dev)

# Conflicts:
#	src/store/getters.js
#	src/store/index.js
#	src/utils/request.js
#	src/views/storeManagement/storeAdd.vue
zhujindu 11 months ago
parent
commit
7d6b1815fd

+ 14 - 3
src/api/index.js

@@ -678,11 +678,12 @@ export function getChainsByDeptCode(query) {
 }
 }
 // 照片上传
 // 照片上传
 //门店
 //门店
-export function uploadImagev(data) {
+export function uploadImagev(data, signal) {
   return request({
   return request({
     url: '/mobile/store/uploadImage',
     url: '/mobile/store/uploadImage',
     method: 'post',
     method: 'post',
     data: data,
     data: data,
+    signal: signal,
   });
   });
 }
 }
 //任务
 //任务
@@ -694,11 +695,12 @@ export function addPhotov(data) {
   });
   });
 }
 }
 // 拜访
 // 拜访
-export function addstorePhoto(data) {
+export function addstorePhoto(data, signal) {
   return request({
   return request({
     url: '/mobile/storeGroup/addPhoto',
     url: '/mobile/storeGroup/addPhoto',
     method: 'post',
     method: 'post',
     data: data,
     data: data,
+    signal: signal,
   });
   });
 }
 }
 export function buryingPoint(data) {
 export function buryingPoint(data) {
@@ -905,7 +907,7 @@ export function selectVisitsRealTime(query) {
   });
   });
 }
 }
 
 
-// 审批历史
+// 审批历史-审批历史
 export function storeApprovaHistory(query) {
 export function storeApprovaHistory(query) {
   return request({
   return request({
     url: '/mobile/store/storeApprovaHistory',
     url: '/mobile/store/storeApprovaHistory',
@@ -959,3 +961,12 @@ export function getDictOption(query, dictTypr) {
     params: query,
     params: query,
   });
   });
 }
 }
+
+// 仍要上传图片入库
+export function addPhotoToDB(data) {
+  return request({
+    url: 'mobile/storeGroup/addPhotoToDB',
+    method: 'post',
+    data: data,
+  });
+}

BIN
src/assets/imageEmpty.png


+ 46 - 31
src/components/deleteUploadImg1.vue

@@ -1,27 +1,37 @@
 <template>
 <template>
-  <div >
-  <van-row gutter="10" >
-    <van-col span="6" v-for="(urls, index) in imgs" :key="index">
-      <div class="imgview">
-        <van-icon name="close" size="16" v-on:click="deleteImg(index,urls.id)"/>
-        <img v-if="urls.type=='2'" :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>
-        <img v-else :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>
-      </div>
-    </van-col>
-  </van-row>
-<!--  <div style="padding: 10px 16px 0;">-->
-<!--    <div class="img-box" v-for="(urls, index) in imgs" :key="index">-->
-<!--      <van-icon name="clear" v-on:click="deleteImg(index,urls.id)"/>-->
-<!--      <img v-if="urls.type=='2'" :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>-->
-<!--      <img v-else :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>-->
-<!--    </div>-->
-<!--  </div>-->
+  <div>
+    <van-row gutter="10">
+      <van-col span="6" v-for="(urls, index) in imgs" :key="index">
+        <div class="imgview">
+          <van-icon name="close" size="16" v-on:click="deleteImg(index, urls.id)" />
+          <img
+            v-if="urls.type == '2'"
+            :src="urls.fileUrl"
+            width="100px"
+            height="100px"
+            @click="previewsImg(index)" />
+          <img
+            v-else
+            :src="urls.fileUrl"
+            width="100px"
+            height="100px"
+            @click="previewsImg(index)" />
+        </div>
+      </van-col>
+    </van-row>
+    <!--  <div style="padding: 10px 16px 0;">-->
+    <!--    <div class="img-box" v-for="(urls, index) in imgs" :key="index">-->
+    <!--      <van-icon name="clear" v-on:click="deleteImg(index,urls.id)"/>-->
+    <!--      <img v-if="urls.type=='2'" :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>-->
+    <!--      <img v-else :src="urls.fileUrl" width="100px" height="100px" @click="previewsImg(index)"/>-->
+    <!--    </div>-->
+    <!--  </div>-->
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import {ImagePreview} from "vant";
-import {removePhoto} from "@/api/index";
+import { ImagePreview } from 'vant';
+import { removePhoto } from '@/api/index';
 
 
 export default {
 export default {
   name: 'deleteUploadImg',
   name: 'deleteUploadImg',
@@ -29,41 +39,46 @@ export default {
     imgs: {
     imgs: {
       type: Array,
       type: Array,
       default() {
       default() {
-        return []
-      }
+        return [];
+      },
+    },
+    photoIdentifyType: {
+      // 图匠识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别,4:更换店招)
+      type: String,
+      default: '',
     },
     },
   },
   },
   data() {
   data() {
     return {
     return {
-      url: process.env.VUE_APP_Target1 + process.env.VUE_APP_BASE_API
-    }
+      url: process.env.VUE_APP_Target1 + process.env.VUE_APP_BASE_API,
+    };
   },
   },
   methods: {
   methods: {
     deleteImg(index, collectionItemId) {
     deleteImg(index, collectionItemId) {
-      removePhoto({fileId: collectionItemId}).then(res => {
+      removePhoto({ fileId: collectionItemId }).then((res) => {
         if (res.code == 200) {
         if (res.code == 200) {
-          this.$toast("删除成功!")
+          this.$toast('删除成功!');
           this.imgs.splice(index, 1);
           this.imgs.splice(index, 1);
         } else {
         } else {
-          this.$toast("删除失败!")
+          this.$toast('删除失败!');
         }
         }
-      })
+      });
     },
     },
     previewsImg(index) {
     previewsImg(index) {
-      var arrimg = []
+      var arrimg = [];
       for (var imgi = 0; imgi < this.imgs.length; imgi++) {
       for (var imgi = 0; imgi < this.imgs.length; imgi++) {
-        arrimg.push(this.imgs[imgi].fileUrl)
+        arrimg.push(this.imgs[imgi].fileUrl);
       }
       }
       ImagePreview({
       ImagePreview({
         images: arrimg,
         images: arrimg,
         startPosition: index,
         startPosition: index,
         onClose() {
         onClose() {
           // do something
           // do something
-        }
+        },
       });
       });
     },
     },
   },
   },
-}
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

+ 429 - 0
src/components/imageAIVerifyErr copy.vue

@@ -0,0 +1,429 @@
+<template>
+  <div class="imageAIVerifyErr">
+    <el-dialog
+      title=""
+      :visible.sync="vanPopup"
+      width="80%"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      @close="close"
+      custom-class="AIVerifyErrdialog">
+      <div class="AIVerifyErrMask">
+        <div class="contentAIVerify">
+          <!-- <div class="uploadImgAIVerify" @click="uploadImg(false)" v-if="shopSignChange == 0">
+            <div class="labelAIVerify"><span class="van-f-red-AIVerify">*</span>重新拍照上传</div>
+            <div class="iconAIVerify">
+              <van-icon class="photoAIVerify" name="photograph" size="22px" color="#969696" />
+            </div>
+          </div> -->
+          <div class="errorImg" v-if="shopSignChange == 0">
+            <img
+              v-if="imageAIVerifyData.url"
+              :src="imageAIVerifyData.url"
+              width="100%"
+              height="200px"
+              @click="previewsImg(imageAIVerifyData.url)" />
+            <img v-else :src="imageEmpty" width="100%" height="200px" />
+          </div>
+          <div class="AIVerify">
+            图像识别结果:<span style="color: red">{{ contentMessage }}</span>
+          </div>
+        </div>
+        <!-- shopSignChange 与历史照片是否一致(是否要更换照片) 0一致(要更换),1不一致(不要更换) -->
+        <template v-if="shopSignChange == 0">
+          <template v-if="shotsNum >= 3">
+            <!-- 拜访店招显示 -->
+            <div class="tipsAIVerify" v-if="npkpiData.recognizeType == 1">
+              <van-icon name="question-o" />上传后作为本店标准店招,未来每次拜访时校验。
+            </div>
+            <div class="feedbackMessage">
+              <div class="label">反馈图像识别不正确:</div>
+              <div class="value">
+                <van-field
+                  v-model="feedbackMessage"
+                  rows="1"
+                  autosize
+                  type="textarea"
+                  placeholder="请输入反馈意见" />
+              </div>
+            </div>
+          </template>
+          <div class="uploadBtnAIVerify">
+            <div class="confirmUploadAIVerify" @click="uploadImg(false)">重新拍照</div>
+            <div v-if="shotsNum >= 3" class="stillUploadAIVerify" @click="confirmUpload">
+              仍要上传
+            </div>
+          </div>
+        </template>
+        <template v-if="shopSignChange == 1">
+          <div class="historyImageAIVerify">
+            <!-- 有门店身份证时 只显示门店身份证和本地拜访照 -->
+            <template v-if="imageAIVerifyData.storeIDCardUrl">
+              <div class="storeIDCardUrl imageItemAIVerify">
+                <img
+                  :src="imageAIVerifyData.storeIDCardUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(imageAIVerifyData.storeIDCardUrl)" />
+                <span>门店标准店招</span>
+              </div>
+            </template>
+            <template v-else>
+              <div class="initImage imageItemAIVerify">
+                <img
+                  v-if="imageAIVerifyData.createStoreUrl"
+                  :src="imageAIVerifyData.createStoreUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(imageAIVerifyData.createStoreUrl)" />
+                <img v-else :src="imageEmpty" width="100px" height="100px" />
+                <span>建店时门店照</span>
+              </div>
+              <div class="newestImage imageItemAIVerify">
+                <img
+                  v-if="imageAIVerifyData.lastVisitUrl"
+                  :src="imageAIVerifyData.lastVisitUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(imageAIVerifyData.lastVisitUrl)" />
+                <img v-else :src="imageEmpty" width="100px" height="100px" />
+                <span>上次拜访店招</span>
+              </div>
+            </template>
+            <div class="presentImage imageItemAIVerify">
+              <img
+                v-if="imageAIVerifyData.url"
+                :src="imageAIVerifyData.url"
+                width="100px"
+                height="100px"
+                @click="previewsImg(imageAIVerifyData.url)" />
+              <img v-else :src="imageEmpty" width="100px" height="100px" />
+              <span>本次拜访店招</span>
+            </div>
+          </div>
+          <div class="tipsRemarkAIVerify">
+            <div>若历史照片拍摄不规范,请选择<span style="color: #81b337">更新门店照</span></div>
+            <div>本次拜访店招会作为本店标准店招,未来每次拜访时校验</div>
+          </div>
+          <div class="feedbackMessage">
+            <div class="label">反馈图像识别不正确:</div>
+            <div class="value">
+              <van-field
+                v-model="feedbackMessage"
+                rows="2"
+                autosize
+                type="textarea"
+                placeholder="请输入反馈意见" />
+            </div>
+          </div>
+          <div class="uploadBtnAIVerify">
+            <div class="confirmUploadAIVerify" @click="uploadImg(true)">重新拍照</div>
+            <div class="changeImageAIVerify" @click="confirmUpDataImage()">更新门店照</div>
+          </div>
+        </template>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { ImagePreview } from 'vant';
+import store from '@/store';
+import { mapState } from 'vuex';
+import imageEmpty from '@/assets/imageEmpty.png';
+export default {
+  props: {
+    imageAIVerifyFlag: {
+      type: Boolean,
+      default: false,
+    },
+    imageAIVerifyData: {
+      type: [Array, Object],
+    },
+    source: {
+      // 新建店还是门店拜访 visit/newCreated
+      type: String,
+    },
+  },
+  computed: {
+    ...mapState({
+      shotsNum: (state) => state.otheStore.shotsNum,
+    }),
+  },
+  watch: {
+    imageAIVerifyFlag: {
+      handler(val) {
+        console.log('imageAIVerifyFlag=' + val);
+        if (val) this.initData();
+      },
+      immediate: true,
+    },
+  },
+  data() {
+    return {
+      imageEmpty: imageEmpty,
+      contentMessage: '', //提示内容
+      vanPopup: true,
+      shopSignChange: 0,
+      npkpiData: null,
+      feedbackMessage: '', //反馈图像识别不正确原因
+    };
+  },
+  methods: {
+    initData() {
+      // 图匠识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别,4:更换店招)
+      // shopSignChange  是否更换店招(0:未更换,1:更换) 1不一致,0一致
+      // checkInfo 图片检查结果
+      // cheatState 是否作弊(0:未作弊,1:作弊)
+      // cheatType	作弊类型
+      // qualifiedState 是否合格(0:不合格,1:合格)
+      // unqualifiedReason	不合格原因
+      this.feedbackMessage = '';
+      this.shopSignChange = 0;
+      this.npkpiData =
+        this.source == 'visit'
+          ? this.imageAIVerifyData.npkpiData
+          : this.imageAIVerifyData[0].npkpiData;
+      this.shopSignMatchList = this.npkpiData.shopSignMatchList;
+      // 先判断照片作弊情况,然后是否合格,然后是否和历史照片一致
+      // 作弊和不合格记录识别次数,超过两次弹框提醒
+      if (this.npkpiData.checkInfo) {
+        // 作弊
+        if (this.npkpiData.checkInfo.cheatState == 1) {
+          // 增加识别次数
+          store.dispatch('setShotsNum', this.shotsNum + 1);
+          // 作弊原因
+          this.contentMessage = this.contentMessage + this.npkpiData.checkInfo.cheatType;
+          return;
+        }
+        // 不合格
+        if (this.npkpiData.checkInfo.qualifiedState == 0) {
+          // 增加识别次数
+          store.dispatch('setShotsNum', this.shotsNum + 1);
+          // 不合格原因
+          this.contentMessage = this.contentMessage + this.npkpiData.checkInfo.unqualifiedReason;
+          return;
+        }
+        // recognizeType 识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别)
+        if (this.npkpiData.recognizeType == 1) {
+          this.comparisonImage();
+        } else {
+          this.confirmUpload();
+        }
+      }
+    },
+    // 照片和历史照片是否一致
+    comparisonImage() {
+      this.shopSignChange = this.npkpiData.shopSignChange;
+      if (this.npkpiData.shopSignChange == 1) {
+        this.contentMessage = '与历史照片不一致,请确认店招是否更换?';
+        return false;
+      } else {
+        this.confirmUpDataImage();
+      }
+    },
+    // 重新拍照
+    uploadImg(flag) {
+      // flag: true,识别与历史照片不一致状态下,点击重新拍照,照片识别次数需要加1
+      if (flag) {
+        // 增加识别次数
+        store.dispatch('setShotsNum', this.shotsNum + 1);
+      }
+      this.$emit('close');
+      this.$emit('uploadImgFun');
+    },
+    // 照片是否入库,1.照片识别三次不通过仍要上传,2.照片识别通过
+    // isUpdate:是否更新店招照片,只有门店店招需要更新
+    confirmUpload() {
+      // 拜访店招 不合格或作弊三次先提示是否仍要上传,确认后在判断是否与历史照片一致
+      if (this.npkpiData.recognizeType == 1 && this.shotsNum >= 3) {
+        this.comparisonImage();
+      } else {
+        this.$emit('close');
+        this.$emit('confirmUpload', {
+          data: this.imageAIVerifyData,
+          feedbackMessage: this.feedbackMessage,
+        });
+      }
+    },
+    confirmUpDataImage() {
+      this.$emit('close');
+      this.$emit('confirmUpload', {
+        data: this.imageAIVerifyData,
+        isUpdate: 'true',
+        feedbackMessage: this.feedbackMessage,
+      });
+    },
+    close() {
+      this.$emit('close');
+    },
+    openTips() {
+      this.$dialog
+        .confirm({
+          title: '提示',
+          message: '不规范的照片上传后会更换本店标准店招,未来每次拜访时校验。',
+          showCancelButton: false,
+          className: 'openTips',
+          overlayClass: 'openTipsMask',
+        })
+        .then(() => {});
+    },
+    previewsImg(url) {
+      ImagePreview({
+        images: [url],
+        className: 'AIImageItem',
+        getContainer: 'el-dialog__wrapper',
+      });
+    },
+  },
+};
+</script>
+<style lang="scss">
+.el-dialog__wrapper {
+  z-index: 3333 !important;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: rgba(0, 0, 0, 0.5) !important;
+  .el-dialog__body {
+    padding: 6px !important;
+  }
+  .el-dialog__header {
+    text-align: center;
+  }
+  .AIVerifyErrdialog {
+    width: 95% !important;
+    margin-top: 1vh !important;
+    border-radius: 8px !important;
+  }
+  .AIVerifyErrMask {
+    width: 100%;
+    padding: 8px;
+    overflow: hidden;
+    /* min-height: 180px; */
+  }
+  .van-popup {
+    width: 90%;
+    padding: 8px;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+  .van-f-red-AIVerify {
+    color: red;
+    width: 8px;
+    display: inline-block;
+    line-height: 26px;
+  }
+  .photoAIVerify {
+    /*margin-top: 9px;*/
+    float: right;
+  }
+  .title {
+    font-size: 16px;
+    font-weight: 600;
+    text-align: center;
+    padding: 5px;
+  }
+  .contentAIVerify {
+    .AIVerify {
+      padding: 6px 0;
+      font-size: 14px;
+      /* color: red; */
+      /* text-align: center; */
+      /* border-top: 1px solid #cfcfcf; */
+    }
+    .uploadImgAIVerify {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 8px 0;
+      border-top: 1px solid #cfcfcf;
+      .labelAIVerify {
+        font-size: 14px;
+      }
+    }
+    .errorImg {
+      width: 100%;
+    }
+  }
+  .tipsAIVerify {
+    border-top: 1px solid #cfcfcf;
+    padding: 5px 0;
+    font-size: 14px;
+    color: red;
+    /* white-space: nowrap; */
+  }
+  .uploadBtnAIVerify {
+    /* border-top: 1px solid #cfcfcf; */
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 8px 0;
+    div {
+      /* width: 40%; */
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 14px;
+      color: #fff;
+      border-radius: 10px;
+      margin: 0 6px;
+      flex: 1;
+    }
+    .confirmUploadAIVerify {
+      background-color: #0057ba;
+      padding: 8px 0;
+    }
+    .changeImageAIVerify {
+      background-color: #81b337;
+      padding: 8px 0;
+    }
+    .stillUploadAIVerify {
+      border: 1px solid #0057ba;
+      color: #0057ba;
+      padding: 8px 0;
+    }
+  }
+  .historyImageAIVerify {
+    display: flex;
+    justify-content: space-around;
+    padding: 5px 0;
+    .imageItemAIVerify {
+      width: 30%;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      span {
+        font-size: 12px;
+      }
+    }
+  }
+  .tipsRemarkAIVerify {
+    border-top: 1px solid #cfcfcf;
+    div {
+      font-size: 12px;
+      padding: 3px 0;
+    }
+  }
+  .feedbackMessage {
+    border-top: 1px solid #cfcfcf;
+    padding: 5px 0;
+    /* width: 100%; */
+    .van-field__body {
+      border: 1px solid #ccc;
+      padding-left: 10px;
+    }
+  }
+}
+.openTipsMask,
+.openTips {
+  z-index: 3334 !important;
+}
+.van-overlay {
+  /* z-index: 3334 !important; */
+}
+.van-image-preview {
+  z-index: 3335 !important;
+  background: rgba(0, 0, 0, 0.8) !important;
+}
+</style>

+ 432 - 0
src/components/imageAIVerifyErr.vue

@@ -0,0 +1,432 @@
+<template>
+  <div class="imageAIVerifyErr">
+    <el-dialog
+      title=""
+      :visible.sync="vanPopup"
+      width="80%"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      @close="close"
+      custom-class="AIVerifyErrdialog">
+      <div class="AIVerifyErrMask" v-if="npkpiData">
+        <div class="contentAIVerify">
+          <!-- <div class="uploadImgAIVerify" @click="uploadImg(false)" v-if="shopSignChange == 0">
+            <div class="labelAIVerify"><span class="van-f-red-AIVerify">*</span>重新拍照上传</div>
+            <div class="iconAIVerify">
+              <van-icon class="photoAIVerify" name="photograph" size="22px" color="#969696" />
+            </div>
+          </div> -->
+          <div class="errorImg" v-if="shopSignChange == 0">
+            <img v-if="url" :src="url" height="200px" @click="previewsImg(url)" />
+            <img v-else :src="imageEmpty" width="100%" height="200px" />
+          </div>
+          <div class="AIVerify">
+            图像识别结果:<span style="color: red">{{ contentMessage }}</span>
+          </div>
+        </div>
+        <!-- shopSignChange 与历史照片是否一致(是否要更换照片) 0一致(要更换),1不一致(不要更换) -->
+        <template v-if="shopSignChange == 0">
+          <template v-if="shotsNum >= 3">
+            <!-- 拜访店招显示 -->
+            <div class="tipsAIVerify" v-if="npkpiData.recognizeType == 1">
+              <van-icon name="question-o" />上传后作为本店标准店招,未来每次拜访时校验。
+            </div>
+            <div class="feedbackMessage">
+              <div class="label">反馈图像识别不正确:</div>
+              <div class="value">
+                <van-field
+                  v-model="feedbackMessage"
+                  rows="1"
+                  autosize
+                  type="textarea"
+                  placeholder="请输入反馈意见" />
+              </div>
+            </div>
+          </template>
+          <div class="uploadBtnAIVerify">
+            <div class="confirmUploadAIVerify" @click="uploadImg(false)">重新拍照</div>
+            <div v-if="shotsNum >= 3" class="stillUploadAIVerify" @click="confirmUpload">
+              仍要上传
+            </div>
+          </div>
+        </template>
+        <template v-if="shopSignChange == 1">
+          <div class="historyImageAIVerify">
+            <!-- 有门店身份证时 只显示门店身份证和本地拜访照 -->
+            <template v-if="storeIDCardUrl">
+              <div class="storeIDCardUrl imageItemAIVerify">
+                <img
+                  :src="storeIDCardUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(storeIDCardUrl)" />
+                <span>门店标准店招</span>
+              </div>
+            </template>
+            <template v-else>
+              <div class="initImage imageItemAIVerify">
+                <img
+                  v-if="createStoreUrl"
+                  :src="createStoreUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(createStoreUrl)" />
+                <img v-else :src="imageEmpty" width="100px" height="100px" />
+                <span>建店时门店照</span>
+              </div>
+              <div class="newestImage imageItemAIVerify">
+                <img
+                  v-if="lastVisitUrl"
+                  :src="lastVisitUrl"
+                  width="100px"
+                  height="100px"
+                  @click="previewsImg(lastVisitUrl)" />
+                <img v-else :src="imageEmpty" width="100px" height="100px" />
+                <span>上次拜访店招</span>
+              </div>
+            </template>
+            <div class="presentImage imageItemAIVerify">
+              <img v-if="url" :src="url" width="100px" height="100px" @click="previewsImg(url)" />
+              <img v-else :src="imageEmpty" width="100px" height="100px" />
+              <span>本次拜访店招</span>
+            </div>
+          </div>
+          <div class="tipsRemarkAIVerify">
+            <div>若历史照片拍摄不规范,请选择<span style="color: #81b337">更新门店照</span></div>
+            <div>本次拜访店招会作为本店标准店招,未来每次拜访时校验</div>
+          </div>
+          <div class="feedbackMessage">
+            <div class="label">反馈图像识别不正确:</div>
+            <div class="value">
+              <van-field
+                v-model="feedbackMessage"
+                rows="2"
+                autosize
+                type="textarea"
+                placeholder="请输入反馈意见" />
+            </div>
+          </div>
+          <div class="uploadBtnAIVerify">
+            <div class="confirmUploadAIVerify" @click="uploadImg(true)">重新拍照</div>
+            <div class="changeImageAIVerify" @click="confirmUpDataImage()">更新门店照</div>
+          </div>
+        </template>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { ImagePreview } from 'vant';
+import store from '@/store';
+import { mapState } from 'vuex';
+import imageEmpty from '@/assets/imageEmpty.png';
+export default {
+  props: {
+    imageAIVerifyFlag: {
+      type: Boolean,
+      default: false,
+    },
+    imageAIVerifyData: {
+      type: [Array, Object],
+    },
+    source: {
+      // 新建店还是门店拜访 visit/newCreated
+      type: String,
+    },
+  },
+  computed: {
+    ...mapState({
+      shotsNum: (state) => state.otheStore.shotsNum,
+    }),
+  },
+  watch: {
+    imageAIVerifyFlag: {
+      handler(val) {
+        console.log('imageAIVerifyFlag=' + val);
+        if (val) this.initData();
+      },
+      immediate: true,
+    },
+  },
+  data() {
+    return {
+      imageEmpty: imageEmpty,
+      contentMessage: '', //提示内容
+      vanPopup: true,
+      shopSignChange: 0,
+      npkpiData: null,
+      feedbackMessage: '', //反馈图像识别不正确原因
+      url: '', //	本次图片路径
+      createStoreUrl: '', //	建店时店招
+      lastVisitUrl: '', //	上次拜访时店招
+      storeIDCardUrl: '', //	门店身份证
+    };
+  },
+  methods: {
+    initData() {
+      // 图匠识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别,4:更换店招)
+      // shopSignChange  是否更换店招(0:未更换,1:更换) 1不一致,0一致
+      // checkInfo 图片检查结果
+      // cheatState 是否作弊(0:未作弊,1:作弊)
+      // cheatType	作弊类型
+      // qualifiedState 是否合格(0:不合格,1:合格)
+      // unqualifiedReason	不合格原因
+      this.feedbackMessage = '';
+      this.shopSignChange = 0;
+      this.npkpiData =
+        this.source == 'visit'
+          ? this.imageAIVerifyData.npkpiData
+          : this.imageAIVerifyData[0].npkpiData;
+      let imageAIVerifyData =
+        this.source == 'visit' ? this.imageAIVerifyData : this.imageAIVerifyData[0];
+      this.shopSignMatchList = this.npkpiData.shopSignMatchList;
+      this.url = imageAIVerifyData.url || ''; //	图片路径
+      this.createStoreUrl = imageAIVerifyData.createStoreUrl || ''; //	建店时店招
+      this.lastVisitUrl = imageAIVerifyData.lastVisitUrl || ''; //	上次拜访时店招
+      this.storeIDCardUrl = imageAIVerifyData.storeIDCardUrl || ''; //	门店身份证
+      // 先判断照片作弊情况,然后是否合格,然后是否和历史照片一致
+      // 作弊和不合格记录识别次数,超过两次弹框提醒
+      if (this.npkpiData.checkInfo) {
+        // 作弊
+        if (this.npkpiData.checkInfo.cheatState == 1) {
+          // 增加识别次数
+          store.dispatch('setShotsNum', this.shotsNum + 1);
+          // 作弊原因
+          this.contentMessage = this.contentMessage + this.npkpiData.checkInfo.cheatType;
+          return;
+        }
+        // 不合格
+        if (this.npkpiData.checkInfo.qualifiedState == 0) {
+          // 增加识别次数
+          store.dispatch('setShotsNum', this.shotsNum + 1);
+          // 不合格原因
+          this.contentMessage = this.contentMessage + this.npkpiData.checkInfo.unqualifiedReason;
+          return;
+        }
+        // recognizeType 识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别)
+        if (this.npkpiData.recognizeType == 1) {
+          this.comparisonImage();
+        } else {
+          this.confirmUpload();
+        }
+      }
+    },
+    // 照片和历史照片是否一致
+    comparisonImage() {
+      this.shopSignChange = this.npkpiData.shopSignChange;
+      if (this.npkpiData.shopSignChange == 1) {
+        this.contentMessage = '与历史照片不一致,请确认店招是否更换?';
+        return false;
+      } else {
+        this.confirmUpDataImage();
+      }
+    },
+    // 重新拍照
+    uploadImg(flag) {
+      // flag: true,识别与历史照片不一致状态下,点击重新拍照,照片识别次数需要加1
+      if (flag) {
+        // 增加识别次数
+        store.dispatch('setShotsNum', this.shotsNum + 1);
+      }
+      this.$emit('close');
+      this.$emit('uploadImgFun');
+    },
+    // 照片是否入库,1.照片识别三次不通过仍要上传,2.照片识别通过
+    // isUpdate:是否更新店招照片,只有门店店招需要更新
+    confirmUpload() {
+      // 拜访店招 不合格或作弊三次先提示是否仍要上传,确认后在判断是否与历史照片一致
+      if (this.npkpiData.recognizeType == 1 && this.shotsNum >= 3) {
+        this.comparisonImage();
+      } else {
+        this.$emit('close');
+        this.$emit('confirmUpload', {
+          data: this.imageAIVerifyData,
+          feedbackMessage: this.feedbackMessage,
+        });
+      }
+    },
+    confirmUpDataImage() {
+      this.$emit('close');
+      this.$emit('confirmUpload', {
+        data: this.imageAIVerifyData,
+        isUpdate: 'true',
+        feedbackMessage: this.feedbackMessage,
+      });
+    },
+    close() {
+      this.$emit('close');
+    },
+    openTips() {
+      this.$dialog
+        .confirm({
+          title: '提示',
+          message: '不规范的照片上传后会更换本店标准店招,未来每次拜访时校验。',
+          showCancelButton: false,
+          className: 'openTips',
+          overlayClass: 'openTipsMask',
+        })
+        .then(() => {});
+    },
+    previewsImg(url) {
+      ImagePreview({
+        images: [url],
+        className: 'AIImageItem',
+        getContainer: 'el-dialog__wrapper',
+      });
+    },
+  },
+};
+</script>
+<style lang="scss">
+.el-dialog__wrapper {
+  z-index: 3333 !important;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: rgba(0, 0, 0, 0.5) !important;
+  .el-dialog__body {
+    padding: 6px !important;
+  }
+  .el-dialog__header {
+    text-align: center;
+  }
+  .AIVerifyErrdialog {
+    width: 95% !important;
+    margin-top: 1vh !important;
+    border-radius: 8px !important;
+  }
+  .AIVerifyErrMask {
+    width: 100%;
+    padding: 8px;
+    overflow: hidden;
+    /* min-height: 180px; */
+  }
+  .van-popup {
+    width: 90%;
+    padding: 8px;
+    border-radius: 8px;
+    overflow: hidden;
+  }
+  .van-f-red-AIVerify {
+    color: red;
+    width: 8px;
+    display: inline-block;
+    line-height: 26px;
+  }
+  .photoAIVerify {
+    /*margin-top: 9px;*/
+    float: right;
+  }
+  .title {
+    font-size: 16px;
+    font-weight: 600;
+    text-align: center;
+    padding: 5px;
+  }
+  .contentAIVerify {
+    .AIVerify {
+      padding: 6px 0;
+      font-size: 14px;
+      /* color: red; */
+      /* text-align: center; */
+      /* border-top: 1px solid #cfcfcf; */
+    }
+    .uploadImgAIVerify {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 8px 0;
+      border-top: 1px solid #cfcfcf;
+      .labelAIVerify {
+        font-size: 14px;
+      }
+    }
+    .errorImg {
+      width: 100%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  .tipsAIVerify {
+    border-top: 1px solid #cfcfcf;
+    padding: 5px 0;
+    font-size: 14px;
+    color: red;
+    /* white-space: nowrap; */
+  }
+  .uploadBtnAIVerify {
+    /* border-top: 1px solid #cfcfcf; */
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 8px 0;
+    div {
+      /* width: 40%; */
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 14px;
+      color: #fff;
+      border-radius: 10px;
+      margin: 0 6px;
+      flex: 1;
+    }
+    .confirmUploadAIVerify {
+      background-color: #0057ba;
+      padding: 8px 0;
+    }
+    .changeImageAIVerify {
+      background-color: #81b337;
+      padding: 8px 0;
+    }
+    .stillUploadAIVerify {
+      border: 1px solid #0057ba;
+      color: #0057ba;
+      padding: 8px 0;
+    }
+  }
+  .historyImageAIVerify {
+    display: flex;
+    justify-content: space-around;
+    padding: 5px 0;
+    .imageItemAIVerify {
+      width: 30%;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      span {
+        font-size: 12px;
+      }
+    }
+  }
+  .tipsRemarkAIVerify {
+    border-top: 1px solid #cfcfcf;
+    div {
+      font-size: 12px;
+      padding: 3px 0;
+    }
+  }
+  .feedbackMessage {
+    border-top: 1px solid #cfcfcf;
+    padding: 5px 0;
+    /* width: 100%; */
+    .van-field__body {
+      border: 1px solid #ccc;
+      padding-left: 10px;
+    }
+  }
+}
+.openTipsMask,
+.openTips {
+  z-index: 3334 !important;
+}
+.van-overlay {
+  /* z-index: 3334 !important; */
+}
+.van-image-preview {
+  z-index: 3335 !important;
+  background: rgba(0, 0, 0, 0.8) !important;
+}
+</style>

+ 161 - 18
src/components/uploadImgVStore.vue

@@ -17,6 +17,23 @@
       </p>
       </p>
     </div>
     </div>
     <p style="text-align: center">{{ imgText }}</p>
     <p style="text-align: center">{{ imgText }}</p>
+    <div class="mask" v-if="progressFlag">
+      <el-progress
+        type="circle"
+        :percentage="percentage"
+        :show-text="true"
+        :format="format"></el-progress>
+      <div class="progressClose" @click="progressClose">取消</div>
+    </div>
+    <imageAIVerifyErr
+      v-if="imageAIVerifyFlag"
+      :imageAIVerifyFlag="imageAIVerifyFlag"
+      :imageAIVerifyData="imageAIVerifyData"
+      @confirmUpload="confirmUpload"
+      @uploadImgFun="uploadImg"
+      :source="'newCreated'"
+      @normalFlow="normalFlow"
+      @close="close"></imageAIVerifyErr>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -24,9 +41,10 @@
 import { ImagePreview } from 'vant';
 import { ImagePreview } from 'vant';
 import axios from 'axios';
 import axios from 'axios';
 import { uploadImagev } from '@/api/index';
 import { uploadImagev } from '@/api/index';
-
+import imageAIVerifyErr from './imageAIVerifyErr';
 export default {
 export default {
   name: 'uploadImg',
   name: 'uploadImg',
+  components: { imageAIVerifyErr },
   props: {
   props: {
     uploadid: {
     uploadid: {
       type: String,
       type: String,
@@ -59,6 +77,11 @@ export default {
       type: Number,
       type: Number,
       default: 1,
       default: 1,
     },
     },
+    photoIdentifyType: {
+      // 图匠识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别,4:更换店招)
+      type: String,
+      default: '',
+    },
   },
   },
   data() {
   data() {
     return {
     return {
@@ -68,6 +91,12 @@ export default {
       num: 0,
       num: 0,
       serverIdArr: [],
       serverIdArr: [],
       imgUrlArr: [],
       imgUrlArr: [],
+      progressFlag: false,
+      percentage: 0,
+      timeFlag: null,
+      imageAIVerifyFlag: false,
+      imageAIVerifyData: null, //图匠校验返回的数据
+      controller: null, //取消请求状态
     };
     };
   },
   },
   watch: {
   watch: {
@@ -128,6 +157,9 @@ export default {
       });
       });
     },
     },
     uploadImagev(meidaId) {
     uploadImagev(meidaId) {
+      // 初始化重置 图匠校验
+      this.resetProgress();
+      this.close();
       var that = this;
       var that = this;
       var form = {
       var form = {
         mediaId: meidaId,
         mediaId: meidaId,
@@ -135,26 +167,103 @@ export default {
         locationRemark: localStorage.getItem('locationRemark'),
         locationRemark: localStorage.getItem('locationRemark'),
         deptName: localStorage.getItem('deptName'),
         deptName: localStorage.getItem('deptName'),
       };
       };
-      var loind1 = that.$toast.loading({
-        duration: 0,
-        message: '上传中...',
-        forbidClick: true,
+      this.controller = null;
+      // 需要图匠校验的添加参数和loading
+      if (this.photoIdentifyType) {
+        form.photoIdentifyType = this.photoIdentifyType;
+        this.progress();
+        this.controller = new AbortController(); //取消请求
+      } else {
+        this.toastLoading(0, '上传中...', true);
+      }
+      uploadImagev(form, this.controller ? this.controller.signal : null)
+        .then((res) => {
+          this.toastLoading().clear();
+          if (res.code == -1) {
+            // 图匠图片校验接口超时
+            this.requestTimeOut(res);
+          } else if (res.code == 200) {
+            // 图匠校验结果返回
+            if (this.photoIdentifyType) {
+              // 重置loaidng状态
+              this.resetProgress();
+              this.imageAIVerifyFlag = true;
+              console.log('res.data=' + JSON.stringify(res.data));
+              this.imageAIVerifyData = res.data;
+            } else {
+              // 正常流程
+              this.normalFlow(res);
+            }
+          } else {
+            this.resetProgress();
+            that.$toast('上传失败!');
+          }
+        })
+        .catch((error) => {
+          if (error.message === 'canceled') {
+            this.$toast('取消上传');
+            console.log('请求被取消:', error.message);
+          }
+          this.resetProgress();
+        });
+    },
+    progress() {
+      // 后端接口20000ms后失效,每1000m progress加10,到90停止;
+      this.progressFlag = true;
+      this.percentage = 10;
+      this.timeFlag = setInterval(() => {
+        this.percentage = this.percentage + 10;
+        if (this.percentage == 90) clearInterval(this.timeFlag);
+      }, 1000);
+    },
+    format(percentage) {
+      return `${percentage} %\n图像识别中`;
+    },
+    requestTimeOut(res) {
+      this.resetProgress();
+      this.close();
+      this.$dialog
+        .confirm({
+          title: '系统提示',
+          message: res.msg,
+          showCancelButton: false,
+        })
+        .then(() => {
+          this.normalFlow(res);
+        });
+    },
+    // 正常流程
+    normalFlow(res) {
+      let imgArr = [];
+      let businessId = [];
+      res.data.forEach((item) => {
+        imgArr.push(item.url);
+        if (item.businessId) businessId.push(item.businessId);
       });
       });
-      uploadImagev(form).then((res) => {
-        if (res.code == 200) {
-          // that.imgArr = res.data.url;
-          let imgArr = [];
-          res.data.forEach((item) => {
-            imgArr.push(item.url);
-          });
-          loind1.clear();
-          that.$toast('上传成功!');
-          that.$emit('newimgarr', { fileUrl: imgArr.join(','), type: that.type });
-        } else {
-          that.$toast('上传失败!');
-        }
+      this.$toast('上传成功!');
+      this.$emit('newimgarr', {
+        fileUrl: imgArr.join(','),
+        type: this.type,
+        businessId: businessId.join(','),
       });
       });
     },
     },
+    // 重置loaidng状态
+    resetProgress() {
+      this.percentage = 100;
+      clearInterval(this.timeFlag);
+      this.progressFlag = false;
+      this.percentage = 0;
+    },
+    // 取消图片上传
+    progressClose() {
+      this.controller.abort();
+    },
+    confirmUpload(res) {
+      this.normalFlow(res);
+    },
+    close() {
+      this.imageAIVerifyFlag = false;
+    },
   },
   },
 };
 };
 </script>
 </script>
@@ -212,4 +321,38 @@ export default {
 .coverImg .ico {
 .coverImg .ico {
   top: 42%;
   top: 42%;
 }
 }
+.mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(255, 255, 255, 0.8);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 99999999;
+  display: flex;
+  flex-direction: column;
+  .progressClose {
+    width: 70px;
+    text-align: center;
+    background: #67c23a;
+    color: #fff;
+    height: 30px;
+    line-height: 30px;
+    border-radius: 5px;
+    margin-top: 5px;
+    font-size: 12px;
+  }
+}
+</style>
+<style lang="scss">
+.mask {
+  .el-progress__text {
+    white-space: pre-wrap;
+  }
+}
 </style>
 </style>

+ 194 - 16
src/components/uploadVNormal.vue

@@ -4,15 +4,35 @@
       <van-icon class="photo photos" name="photograph" size="22px" color="#969696" />
       <van-icon class="photo photos" name="photograph" size="22px" color="#969696" />
     </div>
     </div>
     <div id="allmap"></div>
     <div id="allmap"></div>
+    <div class="mask" v-if="progressFlag">
+      <el-progress
+        type="circle"
+        :percentage="percentage"
+        :show-text="true"
+        :width="110"
+        :format="format"></el-progress>
+      <div class="progressClose" @click="progressClose">取消</div>
+    </div>
+    <imageAIVerifyErr
+      v-if="imageAIVerifyFlag"
+      :imageAIVerifyFlag="imageAIVerifyFlag"
+      :imageAIVerifyData="imageAIVerifyData"
+      @confirmUpload="confirmUpload"
+      @uploadImgFun="uploadImg"
+      :source="'visit'"
+      @normalFlow="normalFlow"
+      @close="close"></imageAIVerifyErr>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import { addstorePhoto, addVisitsPosition } from '@/api/index';
+import { addstorePhoto, addVisitsPosition, addPhotoToDB } from '@/api/index';
+import imageAIVerifyErr from './imageAIVerifyErr';
 import axios from 'axios';
 import axios from 'axios';
 
 
 export default {
 export default {
   name: 'uploadImg',
   name: 'uploadImg',
+  components: { imageAIVerifyErr },
   props: {
   props: {
     uploadid: {
     uploadid: {
       type: String,
       type: String,
@@ -27,7 +47,7 @@ export default {
       default: '',
       default: '',
     },
     },
     secondCollectionId: {
     secondCollectionId: {
-      type: String,
+      type: [String, Number],
       default: '',
       default: '',
     },
     },
     firstCollectionId: {
     firstCollectionId: {
@@ -80,11 +100,24 @@ export default {
       type: String,
       type: String,
       default: '',
       default: '',
     },
     },
+    photoIdentifyType: {
+      // 图匠识别目的(1:店招内容识别,2:门店代码识别,3:调色机识别,4:更换店招)
+      type: String,
+      default: '',
+    },
   },
   },
   data() {
   data() {
     return {
     return {
       shows: false,
       shows: false,
       url: '',
       url: '',
+      progressFlag: false,
+      percentage: 0,
+      timeFlag: null,
+      imageAIVerifyFlag: false,
+      imageAIVerifyData: null, //图匠校验返回的数据
+      meidaId: '', //当前上传图片id
+      addressesRemark: '', //当前位置信息
+      controller: null, //取消请求状态
     };
     };
   },
   },
   methods: {
   methods: {
@@ -160,10 +193,10 @@ export default {
               });
               });
               wx.chooseImage({
               wx.chooseImage({
                 count: 1,
                 count: 1,
-                sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
+                sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有
                 sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有
                 sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有
                 defaultCameraMode: 'normal', //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
                 defaultCameraMode: 'normal', //表示进入拍照界面的默认模式,目前有normal与batch两种选择,normal表示普通单拍模式,batch表示连拍模式,不传该参数则为normal模式。从3.0.26版本开始支持front和batch_front两种值,其中front表示默认为前置摄像头单拍模式,batch_front表示默认为前置摄像头连拍模式。(注:用户进入拍照界面仍然可自由切换两种模式)
-                isSaveToAlbum: 0,
+                isSaveToAlbum: 0, //整型值,0表示拍照时不保存到系统相册,1表示自动保存,默认值是1
                 success: function (res) {
                 success: function (res) {
                   var localIds = '';
                   var localIds = '';
                   if (res.localIds != undefined) {
                   if (res.localIds != undefined) {
@@ -185,6 +218,9 @@ export default {
         });
         });
     },
     },
     uploadImagev(meidaId, addressesRemark) {
     uploadImagev(meidaId, addressesRemark) {
+      // 初始化重置 图匠校验
+      this.resetProgress();
+      this.close();
       var that = this;
       var that = this;
       var parentCollectionId = null;
       var parentCollectionId = null;
       if (that.parentCollectionId != null && that.parentCollectionId != 'null') {
       if (that.parentCollectionId != null && that.parentCollectionId != 'null') {
@@ -206,6 +242,8 @@ export default {
       if (that.thirdCollectionId != null && that.thirdCollectionId != 'null') {
       if (that.thirdCollectionId != null && that.thirdCollectionId != 'null') {
         thirdCollectionId = that.thirdCollectionId;
         thirdCollectionId = that.thirdCollectionId;
       }
       }
+      this.meidaId = meidaId;
+      this.addressesRemark = addressesRemark;
       var form = {
       var form = {
         mediaId: meidaId,
         mediaId: meidaId,
         collectionItemId: that.collectionId,
         collectionItemId: that.collectionId,
@@ -224,20 +262,126 @@ export default {
         deviceCode: that.deviceCode, //设备编号
         deviceCode: that.deviceCode, //设备编号
         putInCode: that.putInCode, //投放编号
         putInCode: that.putInCode, //投放编号
       };
       };
-      var loind1 = that.$toast.loading({
-        duration: 0,
-        message: '上传中...',
-        forbidClick: true,
+      this.controller = null;
+      // 需要图匠校验的添加参数和loading
+      if (this.photoIdentifyType) {
+        form.photoIdentifyType = this.photoIdentifyType;
+        this.progress();
+        this.controller = new AbortController(); //取消请求
+      } else {
+        this.toastLoading(0, '上传中...', true);
+      }
+      addstorePhoto(form, this.controller ? this.controller.signal : null)
+        .then((res) => {
+          this.toastLoading().clear();
+          if (res.code == -1) {
+            // 图匠图片校验接口超时
+            this.requestTimeOut(res);
+          } else if (res.code == 200) {
+            // 图匠校验结果返回
+            if (this.photoIdentifyType) {
+              // 重置loaidng状态
+              this.resetProgress();
+              this.imageAIVerifyFlag = true;
+              this.imageAIVerifyData = res.data;
+            } else {
+              // 正常流程
+              this.normalFlow(res);
+            }
+          } else {
+            this.resetProgress();
+            that.$toast('上传失败!');
+          }
+        })
+        .catch((error) => {
+          if (error.message === 'canceled') {
+            this.$toast('取消上传');
+            console.log('请求被取消:', error.message);
+          }
+          this.resetProgress();
+        });
+    },
+    // 正常流程
+    normalFlow(res) {
+      this.$toast('上传成功!');
+      this.$emit('newimgarr', {
+        fileUrl: res.data.url,
+        id: res.data.fileId,
+        type: 2,
+        photoIdentifyType: this.photoIdentifyType,
       });
       });
-      addstorePhoto(form).then((res) => {
-        if (res.code == 200) {
-          loind1.clear();
-          that.$toast('上传成功!');
-          that.$emit('newimgarr', { fileUrl: res.data.url, id: res.data.fileId, type: 2 });
-        } else {
-          that.$toast('上传失败!');
+    },
+    progress() {
+      // 后端接口20000ms后失效,每1000m progress加10,到90停止;
+      this.progressFlag = true;
+      this.percentage = 10;
+      this.timeFlag = setInterval(() => {
+        this.percentage = this.percentage + 10;
+        if (this.percentage == 90) clearInterval(this.timeFlag);
+      }, 1000);
+    },
+    format(percentage) {
+      return `${percentage} %\n图像识别中`;
+    },
+    // 重置loaidng状态
+    resetProgress() {
+      this.percentage = 100;
+      clearInterval(this.timeFlag);
+      this.progressFlag = false;
+      this.percentage = 0;
+    },
+    // 照片是否入库,1.照片识别三次不通过仍要上传,2.照片识别通过
+    // isUpdate:是否更新店招照片,只有门店店招需要更新
+    confirmUpload(res) {
+      if (this.photoIdentifyType) {
+        var form = {
+          mediaId: this.meidaId, //	string	图片素材id
+          visitSource: '1', //	Long	拜访模式
+          storeGroupId: this.storeGroupId, //	string	门店任务组,多个用逗号隔开
+          visitsId: localStorage.getItem('visitId'), //	string	拜访id
+          taskId: this.taskId, //	string	任务id
+          objectType: this.objectType, //	string	照片类型,取任务上的照片类型,如果没有则取手动选择的照片类型
+          locationRemark: this.addressesRemark, //	String	当前地址信息
+          firstCollectionId: this.firstCollectionId, //	Long	第一级采集项id,取当前采集项的字段就行
+          secondCollectionId: this.secondCollectionId, //	Long	第二级采集项id,取当前采集项的字段就行
+          putInCode: this.putInCode, //	String	当前任务对应的投放编号
+          deviceCode: this.deviceCode, //	String	当前任务对应的设备编号
+          collectionItemId: this.collectionId,
+          url: res.data.url, //	String	当前拍摄图片的url
+          businessId: res.data.businessId, // 当前拍摄图片id
+        };
+        if (res.isUpdate) {
+          form.isUpdate = 'true';
+          form.feedbackMessage = res.feedbackMessage;
         }
         }
-      });
+        addPhotoToDB(form).then((resData) => {
+          if (resData.code == 200) {
+            console.log(resData);
+            res.data.fileId = resData.data.fileId;
+            this.normalFlow(res);
+          }
+        });
+      }
+    },
+    close() {
+      this.imageAIVerifyFlag = false;
+    },
+    requestTimeOut(res) {
+      this.resetProgress();
+      this.close();
+      this.$dialog
+        .confirm({
+          title: '系统提示',
+          message: res.msg,
+          showCancelButton: false,
+        })
+        .then(() => {
+          this.confirmUpload(res);
+        });
+    },
+    // 取消图片上传
+    progressClose() {
+      this.controller.abort();
     },
     },
   },
   },
 };
 };
@@ -270,6 +414,33 @@ export default {
       z-index: 89;
       z-index: 89;
     }
     }
   }
   }
+  .mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(255, 255, 255, 1);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    z-index: 99999999;
+    display: flex;
+    flex-direction: column;
+    .progressClose {
+      width: 70px;
+      text-align: center;
+      background: #67c23a;
+      color: #fff;
+      height: 30px;
+      line-height: 30px;
+      border-radius: 5px;
+      margin-top: 5px;
+      font-size: 12px;
+    }
+  }
 }
 }
 #allmap {
 #allmap {
   width: 10px;
   width: 10px;
@@ -278,3 +449,10 @@ export default {
   position: relative;
   position: relative;
 }
 }
 </style>
 </style>
+<style lang="scss">
+.mask {
+  .el-progress__text {
+    white-space: pre-wrap;
+  }
+}
+</style>

+ 6 - 0
src/main.js

@@ -33,11 +33,17 @@ import ElPopover from 'element-ui/lib/popover';
 import 'element-ui/lib/theme-chalk/table-column.css';
 import 'element-ui/lib/theme-chalk/table-column.css';
 import 'element-ui/lib/theme-chalk/popover.css';
 import 'element-ui/lib/theme-chalk/popover.css';
 import Vconsole from 'vconsole';
 import Vconsole from 'vconsole';
+import ElProgress from 'element-ui/lib/progress';
+import 'element-ui/lib/theme-chalk/progress.css';
+import ElDialog from 'element-ui/lib/dialog';
+import 'element-ui/lib/theme-chalk/dialog.css';
 // import wx from 'weixin-js-sdk';
 // import wx from 'weixin-js-sdk';
 
 
 Vue.use(ElTable);
 Vue.use(ElTable);
 Vue.use(ElTableColumn);
 Vue.use(ElTableColumn);
 Vue.use(ElPopover);
 Vue.use(ElPopover);
+Vue.use(ElProgress);
+Vue.use(ElDialog);
 Vue.config.productionTip = false;
 Vue.config.productionTip = false;
 Vue.prototype.parseTime = parseTime;
 Vue.prototype.parseTime = parseTime;
 Vue.prototype.selectDictLabel = selectDictLabel;
 Vue.prototype.selectDictLabel = selectDictLabel;

+ 1 - 0
src/store/getters.js

@@ -2,5 +2,6 @@ const getters = {
   userInfo: (state) => state.user.userInfo,
   userInfo: (state) => state.user.userInfo,
   refreshClewPage: (state) => state.isRefreshPage.refreshClewPage,
   refreshClewPage: (state) => state.isRefreshPage.refreshClewPage,
   storeType: (state) => state.user.storeType,
   storeType: (state) => state.user.storeType,
+  shotsNum: (state) => state.otheStore.shotsNum,
 };
 };
 export default getters;
 export default getters;

+ 2 - 0
src/store/index.js

@@ -2,6 +2,7 @@ import Vue from 'vue';
 import Vuex from 'vuex';
 import Vuex from 'vuex';
 import user from './modules/user';
 import user from './modules/user';
 import isRefreshPage from './modules/isRefreshPage';
 import isRefreshPage from './modules/isRefreshPage';
+import otheStore from './modules/otheStore';
 import getters from './getters';
 import getters from './getters';
 
 
 Vue.use(Vuex);
 Vue.use(Vuex);
@@ -10,6 +11,7 @@ const store = new Vuex.Store({
   modules: {
   modules: {
     user,
     user,
     isRefreshPage,
     isRefreshPage,
+    otheStore,
   },
   },
   getters,
   getters,
 });
 });

+ 19 - 0
src/store/modules/otheStore.js

@@ -0,0 +1,19 @@
+const otheStore = {
+  state: {
+    shotsNum: 0,
+  },
+
+  mutations: {
+    SET_SHOTS_NUM: (state, value) => {
+      state.shotsNum = value;
+    },
+  },
+
+  actions: {
+    setShotsNum({ commit }, value) {
+      commit('SET_SHOTS_NUM', value);
+    },
+  },
+};
+
+export default otheStore;

+ 1 - 0
src/utils/TXApiFun.js

@@ -136,6 +136,7 @@ export function getTicketFun(jsApiList = ['getLocation'], configType = 'config')
       } else {
       } else {
         console.log('获取签名失败');
         console.log('获取签名失败');
         reject('获取签名失败');
         reject('获取签名失败');
+        alert('获取签名失败');
       }
       }
     });
     });
   });
   });

+ 3 - 0
src/utils/request.js

@@ -42,6 +42,9 @@ service.interceptors.response.use(
       //     duration:5000
       //     duration:5000
       // });
       // });
       return res.data;
       return res.data;
+    } else if (code == -1) {
+      // 图匠图片校验接口超时
+      return res.data;
     } else if (code !== 200) {
     } else if (code !== 200) {
       Toast({
       Toast({
         message: msg,
         message: msg,

+ 1 - 0
src/views/deviceOutside/suishenbangOutstoreVisit.vue

@@ -557,6 +557,7 @@ export default {
           locationCity: this.city,
           locationCity: this.city,
           locationRemark: this.address,
           locationRemark: this.address,
           locationAccuracy: this.locationAccuracy,
           locationAccuracy: this.locationAccuracy,
+          photoIdentifyType: val.photoIdentifyType,
         },
         },
       });
       });
     },
     },

File diff suppressed because it is too large
+ 388 - 214
src/views/deviceWithin/addStoreVisit.vue


+ 1 - 0
src/views/deviceWithin/storeVisit.vue

@@ -687,6 +687,7 @@ export default {
             types: this.$route.query.type,
             types: this.$route.query.type,
             locationAccuracy: this.locationAccuracy,
             locationAccuracy: this.locationAccuracy,
             insert: this.insert,
             insert: this.insert,
+            photoIdentifyType: val.photoIdentifyType,
           },
           },
         });
         });
       }
       }

+ 3 - 1
src/views/deviceWithin/taskTips.vue

@@ -1,6 +1,8 @@
 <template>
 <template>
   <div class="tips">
   <div class="tips">
-    <span class="examples" v-if="examplePhoto" @click="openExamplesImg(examplePhoto)">示例</span>
+    <span class="examples" v-if="examplePhoto" @click="openExamplesImg(examplePhoto)"
+      >拍摄要求</span
+    >
     <span class="phone" v-if="contactPhone">
     <span class="phone" v-if="contactPhone">
       <van-icon name="phone" size="18px" /><a :href="'tel:' + contactPhone" class="call">{{
       <van-icon name="phone" size="18px" /><a :href="'tel:' + contactPhone" class="call">{{
         contactPhone
         contactPhone

+ 13 - 1
src/views/storeManagement/storeAdd.vue

@@ -329,7 +329,9 @@
                         :imgArr="fromValue.img"
                         :imgArr="fromValue.img"
                         @newimgarr="newimgarr1"
                         @newimgarr="newimgarr1"
                         :imgText="fromValue.ifJzStoreType != 1 ? '门店照' : '家装前台照片'"
                         :imgText="fromValue.ifJzStoreType != 1 ? '门店照' : '家装前台照片'"
-                        :type="1"></upload-img>
+                        :photoIdentifyType="fromValue.ifJzStoreType != 1 ? '1' : ''"
+                        :type="1"
+                        ref="uploadImgVStore"></upload-img>
                     </div>
                     </div>
                   </van-col>
                   </van-col>
                   <!-- 新建同城分销店不显示陈列照 -->
                   <!-- 新建同城分销店不显示陈列照 -->
@@ -713,6 +715,7 @@ import txmapimg2 from '@/assets/txmap2.svg';
 import txmapimg3 from '@/assets/marker_blue.png';
 import txmapimg3 from '@/assets/marker_blue.png';
 import { getPosition, getTicketFun } from '@/utils/TXApiFun';
 import { getPosition, getTicketFun } from '@/utils/TXApiFun';
 import { listChainsByCategory } from '@/api/store';
 import { listChainsByCategory } from '@/api/store';
+import store from '@/store';
 export default {
 export default {
   name: 'storeAdd',
   name: 'storeAdd',
   components: { uploadImg, uploadImgView, mapmarker, uploadImgc, deleteImgView },
   components: { uploadImg, uploadImgView, mapmarker, uploadImgc, deleteImgView },
@@ -864,6 +867,8 @@ export default {
     this.dictTypeQGJZFormShow = false;
     this.dictTypeQGJZFormShow = false;
     this.dictTypeSJSFormShow = false;
     this.dictTypeSJSFormShow = false;
     this.dictTypeFormShow = false;
     this.dictTypeFormShow = false;
+    // 拍照次数重置
+    store.dispatch('setShotsNum', 0);
   },
   },
   watch: {
   watch: {
     $route(to, from) {
     $route(to, from) {
@@ -931,6 +936,10 @@ export default {
         this.getQGJZist();
         this.getQGJZist();
         this.getStreetQuery();
         this.getStreetQuery();
       }
       }
+      if (from.path == '/storeAdd') {
+        // 离开当前页面时,关闭弹框
+        if (this.$refs.uploadImgVStore) this.$refs.uploadImgVStore.close();
+      }
     },
     },
   },
   },
   activated() {
   activated() {
@@ -1260,6 +1269,7 @@ export default {
       } else {
       } else {
         this.fromValue.carShopImgList.push(val.fileUrl);
         this.fromValue.carShopImgList.push(val.fileUrl);
       }
       }
+      this.fromValue.businessId = val.businessId ? val.businessId : '';
     },
     },
     getChainsByDeptId(deptCode, ifJzStoreType) {
     getChainsByDeptId(deptCode, ifJzStoreType) {
       getChainsByDeptCode({
       getChainsByDeptCode({
@@ -1640,6 +1650,8 @@ export default {
       this.fromValue.orgName = '';
       this.fromValue.orgName = '';
       this.fromValue.orgId = '';
       this.fromValue.orgId = '';
       this.fromValue.ifJzStoreType = value.ifJzStoreType;
       this.fromValue.ifJzStoreType = value.ifJzStoreType;
+      // 重置拍摄照片
+      this.fromValue.img = '';
       this.getChainsByDeptCode(null, value.ifJzStoreType);
       this.getChainsByDeptCode(null, value.ifJzStoreType);
       // 切换门店类型删除选定经销商
       // 切换门店类型删除选定经销商
       this.treeSelect = [];
       this.treeSelect = [];

+ 5 - 2
src/views/storeManagement/success.vue

@@ -38,7 +38,10 @@
         ></van-col
         ></van-col
       > -->
       > -->
     </van-row>
     </van-row>
-    <van-row gutter="20" style="display: flex; justify-content: center">
+    <van-row
+      gutter="20"
+      style="display: flex; justify-content: center"
+      v-if="fromValue && this.fromValue.storeId">
       <van-col>
       <van-col>
         <van-button
         <van-button
           style="width: 120px"
           style="width: 120px"
@@ -64,7 +67,7 @@ export default {
   name: 'success',
   name: 'success',
   data() {
   data() {
     return {
     return {
-      fromValue: {},
+      fromValue: null,
       cont: 0,
       cont: 0,
       timer: null,
       timer: null,
       flag: true,
       flag: true,