noVisit.vue 17 KB

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