noVisit.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <template>
  2. <div class="noVisit">
  3. <div class="header">
  4. <van-nav-bar class="navBar" title="未拜访门店" left-arrow @click-left="onClickLeft" />
  5. </div>
  6. <div class="content">
  7. <van-collapse v-model="activeName" accordion @change="collapseCange">
  8. <van-collapse-item v-for="(val, key, ind) in list" :key="ind" :name="key">
  9. <template #title>
  10. <div class="title">{{ key | storeType }}</div>
  11. <div class="num">{{ val.storeNum }}家</div>
  12. </template>
  13. <div class="itemContent">
  14. <template v-if="val.storeList.length">
  15. <div class="item" v-for="(item, index) in val.storeList" :key="index">
  16. <div class="itemLeft">
  17. <div class="storeName">{{ item.storeName }}</div>
  18. <div class="address">
  19. <van-icon name="location-o" />
  20. {{ item.addressLine }}
  21. <!-- <img v-if="item.distance" style="width: 36px" :src="sbpmdh" @click="linkapp(item)" /> -->
  22. </div>
  23. <div class="distance" v-if="item.distance">
  24. (距离{{ Micrometer(item.distance) }}m)
  25. </div>
  26. </div>
  27. <div class="itemRight">
  28. <div
  29. class="statstext"
  30. :style="{
  31. 'background-color': item.stateString == '未拜访' ? '#ed5c68' : 'white',
  32. }">
  33. <van-icon
  34. v-if="item.stateString == '拜访中'"
  35. :name="times"
  36. color="#ee0a24"
  37. size="32" />
  38. {{ item.stateString == '未拜访' ? '未拜访' : '' }}
  39. </div>
  40. <div class="toVisit" @click="storeVisit(item)">
  41. 进入拜访 <van-icon name="arrow" />
  42. </div>
  43. </div>
  44. </div>
  45. </template>
  46. <template v-else><div style="text-align: center">暂无数据</div></template>
  47. </div>
  48. </van-collapse-item>
  49. </van-collapse>
  50. </div>
  51. </div>
  52. </template>
  53. <script>
  54. import {
  55. selectUserStoreNoVisits,
  56. mobileReposition,
  57. checkVisit,
  58. addVisitsPosition,
  59. } from '@/api/index';
  60. import { checkStoreAddressByStoreCode } from '@/api/visitstore';
  61. import { getPosition, getTicketFun } from '@/utils/TXApiFun';
  62. import sbpmdh from '@/assets/sbpmdh.png';
  63. import times from '@/assets/Icon/times.png';
  64. import { mapState } from 'vuex';
  65. import store from '@/store';
  66. export default {
  67. name: 'noVisit',
  68. computed: {
  69. ...mapState({
  70. activaTypeStore: (state) => state.user.activaTypeStore,
  71. }),
  72. },
  73. data() {
  74. return {
  75. sbpmdh: sbpmdh,
  76. times: times,
  77. activeName: '',
  78. list: {},
  79. TXPiont: {}, //腾讯定位数据
  80. TXisBD: {}, // 腾讯定位数据转百度
  81. activatStoreVal: {}, //当前点击门店数据
  82. visitRoutePath: '', //拜访页面路径
  83. clickIsFlage: true,
  84. };
  85. },
  86. filters: {
  87. storeType(value) {
  88. let type = '';
  89. if (value == 'keKong') {
  90. type = '可控店';
  91. } else if (value == 'jinPai') {
  92. type = '金牌店';
  93. } else if (value == 'tongA') {
  94. type = '同城A';
  95. } else if (value == 'tongB') {
  96. type = '同城B';
  97. }
  98. return type;
  99. },
  100. },
  101. activated() {
  102. // 授权
  103. getTicketFun().then(() => {
  104. // 获取定位
  105. getPosition()
  106. .then((res) => {
  107. let { TXisBD } = res;
  108. this.getList(TXisBD);
  109. })
  110. .catch((error) => {
  111. this.$dialog.alert({
  112. message: error,
  113. });
  114. });
  115. });
  116. this.activeName = this.activaTypeStore || '';
  117. },
  118. methods: {
  119. collapseCange(value) {
  120. store.dispatch('setActivaTypeStore', value);
  121. },
  122. getList(TXisBD) {
  123. selectUserStoreNoVisits({
  124. lat: TXisBD.lat,
  125. lon: TXisBD.lon,
  126. }).then((res) => {
  127. this.list = res.data;
  128. console.log(this.list);
  129. });
  130. },
  131. tabChange(val) {},
  132. // 进入拜访
  133. storeVisit(val) {
  134. if (!this.clickIsFlage) return;
  135. this.clickIsFlage = false;
  136. this.toastLoading(0, '加载中...', true);
  137. // 删除拜访id
  138. localStorage.removeItem('visitId');
  139. checkVisit({ storeId: val.storeId }).then((res) => {
  140. if (res.code == 200) {
  141. this.activatStoreVal = val;
  142. // 拜访页面分为 计划外、计划内; 0计划内 1计划外
  143. this.visitRoutePath =
  144. this.activatStoreVal.visitEntry == '1'
  145. ? '/suishenbangOutstoreVisit'
  146. : '/storeVisitpage';
  147. if (val.stateString.indexOf('拜访中') != -1) {
  148. this.clickIsFlage = true;
  149. localStorage.setItem('startTime', new Date());
  150. localStorage.setItem('ORGName', this.activatStoreVal.deptName);
  151. localStorage.setItem('chainNameR', this.activatStoreVal.storeName);
  152. this.$router.push({
  153. path: this.visitRoutePath,
  154. query: {
  155. storeId: this.activatStoreVal.storeId,
  156. rdId: this.activatStoreVal.rdId,
  157. lat: this.activatStoreVal.lat,
  158. lon: this.activatStoreVal.lon,
  159. visitId: this.activatStoreVal.visitId,
  160. pageType: 'out',
  161. addressLine: this.activatStoreVal.addressLine,
  162. storeCategory: this.activatStoreVal.storeCategoryName,
  163. storeName: this.activatStoreVal.storeName,
  164. hisTime: this.activatStoreVal.hisTime,
  165. contactName: this.activatStoreVal.contactName,
  166. storeCode: this.activatStoreVal.storeCode,
  167. tabVal: this.tabVal,
  168. visitModel: '1',
  169. latNew: this.activatStoreVal.lat,
  170. lonNew: this.activatStoreVal.lon,
  171. PointSum: 0,
  172. marklat: this.activatStoreVal.lat,
  173. marklon: this.activatStoreVal.lon,
  174. from: 'outPlan',
  175. },
  176. });
  177. } else {
  178. // 拜访时重新获取定位
  179. getPosition()
  180. .then((res) => {
  181. let { TXisBD, resData } = res;
  182. this.TXisBD = TXisBD;
  183. this.TXPiont = resData;
  184. localStorage.setItem('lat', TXisBD.lat);
  185. localStorage.setItem('lon', TXisBD.lon);
  186. this.checkStoreAddressByStoreCodeFun();
  187. })
  188. .catch((error) => {
  189. this.clickIsFlage = true;
  190. this.$dialog.alert({
  191. message: error,
  192. });
  193. });
  194. }
  195. } else {
  196. this.toastLoading().clear();
  197. this.clickIsFlage = true;
  198. this.$dialog.alert({
  199. message: res.msg,
  200. });
  201. }
  202. });
  203. },
  204. checkStoreAddressByStoreCodeFun() {
  205. this.toastLoading(0, '加载中...', true);
  206. let PointSumval = this.twoPointSum(
  207. this.TXisBD.lat,
  208. this.TXisBD.lon,
  209. this.TXisBD.lat,
  210. this.TXisBD.lon
  211. ).toFixed(2);
  212. // GZ:工装店铺 直接进入拜访
  213. if (localStorage.getItem('postType') == 'GZ') {
  214. localStorage.setItem('startTime', new Date());
  215. localStorage.setItem('ORGName', this.activatStoreVal.deptName);
  216. localStorage.setItem('chainNameR', this.activatStoreVal.storeName);
  217. this.toSuishenbangOutstoreVisit(PointSumval);
  218. return;
  219. }
  220. checkStoreAddressByStoreCode({
  221. storeCode: this.activatStoreVal.storeCode,
  222. lon: this.TXisBD.lon,
  223. lat: this.TXisBD.lat,
  224. })
  225. .then((response) => {
  226. this.clickIsFlage = true;
  227. // 门店校验 地址不通过
  228. if (response.code != 200) {
  229. this.toastLoading().clear();
  230. // updateAddress : ,1:同城AB+金牌,去修改地址;2:非金牌店铺,非同城店铺偏差过大不允许拜访,可以重置定位;0非金牌店铺,非同城店铺 位置信息不存在 可以继续拜访
  231. if (response.data) {
  232. if (response.data.updateAddress == 0) {
  233. // 非金牌店铺,非同城店铺 位置信息不存在 可以继续拜访
  234. this.$dialog
  235. .confirm({
  236. confirmButtonText: '确定拜访',
  237. cancelButtonText: '取消拜访',
  238. title: '系统提示',
  239. message:
  240. '该客户没有经纬度,此次拜访会保存定位点作为客户经纬度,下次拜访时判断是否偏差过大。',
  241. closeOnClickOverlay: true,
  242. })
  243. .then(() => {
  244. this.toSuishenbangOutstoreVisit(PointSumval);
  245. });
  246. } else if (response.data.updateAddress == 1) {
  247. // 同城AB+金牌,去修改地址
  248. // addressUpdateTimesOver: true=已经达到最大次数,不让修改; false=没有达到可以修改
  249. if (!response.data.addressUpdateTimesOver) {
  250. this.$dialog
  251. .confirm({
  252. title: '系统提示',
  253. message: response.msg + '请立即修改后再拜访',
  254. messageAlign: 'left',
  255. confirmButtonText: '立即修改',
  256. cancelButtonText: '取消',
  257. })
  258. .then(() => {
  259. this.$router.push({
  260. path: '/storeDetail',
  261. query: {
  262. id: this.activatStoreVal.storeId,
  263. type: 'address',
  264. storeAddressId: this.activatStoreVal.storeAddressId,
  265. },
  266. });
  267. });
  268. } else {
  269. this.$dialog.confirm({
  270. title: '系统提示',
  271. message: '已经达到最大修改次数',
  272. messageAlign: 'left',
  273. confirmButtonText: '确定',
  274. });
  275. }
  276. } else if (response.data.updateAddress == 2) {
  277. // 1.非金牌店铺,非同城店铺 位置偏差过大 重置经纬度
  278. this.resetCoord(PointSumval);
  279. return;
  280. }
  281. } else {
  282. this.$dialog.confirm({
  283. title: '系统提示',
  284. message: response.msg,
  285. showCancelButton: false,
  286. confirmButtonText: '确定',
  287. });
  288. }
  289. } else {
  290. // 门店编码校验门店地址通过 进入拜访
  291. this.toSuishenbangOutstoreVisit(PointSumval);
  292. }
  293. })
  294. .catch((error) => {
  295. this.clickIsFlage = true;
  296. });
  297. },
  298. // 进入拜访
  299. toSuishenbangOutstoreVisit(PointSumval) {
  300. addVisitsPosition({
  301. storeId: this.activatStoreVal.storeId,
  302. visitsId: '',
  303. lon: this.TXPiont.longitude,
  304. lat: this.TXPiont.latitude,
  305. sourceLon: this.TXisBD.lon,
  306. sourceLat: this.TXisBD.lat,
  307. positionDesc: '',
  308. accuracy: this.TXPiont.accuracy,
  309. });
  310. this.clickIsFlage = true;
  311. this.toastLoading().clear();
  312. this.$router.push({
  313. path: this.visitRoutePath,
  314. query: {
  315. storeId: this.activatStoreVal.storeId,
  316. rdId: this.activatStoreVal.rdId,
  317. lat: this.TXisBD.lat,
  318. lon: this.TXisBD.lon,
  319. visitId: this.activatStoreVal.visitId,
  320. pageType: 'out',
  321. addressLine: this.activatStoreVal.addressLine,
  322. storeCategory: this.activatStoreVal.storeCategoryName,
  323. storeName: this.activatStoreVal.storeName,
  324. hisTime: this.activatStoreVal.hisTime,
  325. contactName: this.activatStoreVal.contactName,
  326. storeCode: this.activatStoreVal.storeCode,
  327. tabVal: this.tabVal,
  328. visitModel: '1',
  329. latNew: this.TXisBD.lat,
  330. lonNew: this.TXisBD.lon,
  331. PointSum: PointSumval,
  332. marklat: this.TXPiont.latitude,
  333. marklon: this.TXPiont.longitude,
  334. from: 'outPlan',
  335. },
  336. });
  337. },
  338. // 重置经纬度
  339. resetCoord(PointSumval) {
  340. this.$dialog
  341. .confirm({
  342. confirmButtonText: '初始化定位',
  343. cancelButtonText: '取消拜访',
  344. title: '系统提示',
  345. message: '偏差过大,不允许拜访。可修改本店定位.',
  346. closeOnClickOverlay: true,
  347. })
  348. .then(() => {
  349. mobileReposition({
  350. storeId: this.activatStoreVal.storeId,
  351. lat: this.TXisBD.lat,
  352. lon: this.TXisBD.lon,
  353. }).then((response) => {
  354. if (response.code == 200) {
  355. this.$dialog
  356. .alert({
  357. title: '系统提示',
  358. message: '本信息定位已更新成功!',
  359. })
  360. .then(() => {
  361. this.toSuishenbangOutstoreVisit(PointSumval);
  362. });
  363. localStorage.setItem('startTime', new Date());
  364. localStorage.setItem('ORGName', this.activatStoreVal.deptName);
  365. localStorage.setItem('chainNameR', this.activatStoreVal.storeName);
  366. } else {
  367. this.$toast(response.msg);
  368. }
  369. });
  370. });
  371. },
  372. onClickLeft() {
  373. this.$router.go(-1);
  374. },
  375. },
  376. };
  377. </script>
  378. <style lang="scss" scoped>
  379. .noVisit {
  380. height: 100%;
  381. width: 100%;
  382. /* overflow-y: auto; */
  383. .content {
  384. padding: 8px 10px;
  385. .item {
  386. background: #deedff;
  387. padding: 8px;
  388. margin: 10px 0;
  389. border-radius: 5px;
  390. display: flex;
  391. .storeName {
  392. font-size: 15px;
  393. font-weight: bold;
  394. color: #333;
  395. padding: 3px 0;
  396. }
  397. .address,
  398. .distance {
  399. font-size: 14px;
  400. color: #909090;
  401. padding: 3px 0;
  402. }
  403. .distance {
  404. padding-left: 12px;
  405. }
  406. .itemLeft {
  407. flex: 1;
  408. }
  409. .itemRight {
  410. width: 25%;
  411. display: flex;
  412. flex-direction: column;
  413. justify-content: space-between;
  414. align-items: end;
  415. .statstext {
  416. background-color: #0057ba;
  417. padding: 2px 6px 2px 12px;
  418. border-bottom-left-radius: 60px;
  419. border-top-left-radius: 60px;
  420. color: #fff;
  421. width: 60px;
  422. margin-right: -8px;
  423. .van-icon__image {
  424. height: 0.7em;
  425. }
  426. }
  427. .toVisit {
  428. height: 40%;
  429. font-size: 15px;
  430. color: #1989fa;
  431. width: 100%;
  432. display: flex;
  433. align-items: center;
  434. justify-content: end;
  435. }
  436. }
  437. }
  438. }
  439. .van-collapse-item {
  440. border-bottom: 1px solid #dcdcdc;
  441. }
  442. }
  443. </style>
  444. <style lang="scss">
  445. .noVisit {
  446. .van-cell__title {
  447. font-size: 15px;
  448. font-weight: bold;
  449. color: #333;
  450. display: flex;
  451. justify-content: space-between;
  452. .num {
  453. color: #909090;
  454. margin-right: 5px;
  455. }
  456. }
  457. .van-collapse-item__wrapper {
  458. border-top: 1px solid #dcdcdc;
  459. }
  460. .van-collapse-item__title--expanded {
  461. position: sticky;
  462. top: 0px;
  463. z-index: 10;
  464. }
  465. }
  466. </style>