parkinglog.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. <template>
  2. <view class="content">
  3. <u-navbar title="" :is-back="false" :background="{backgroundColor: '#ffffff'}" class="top-navbar">
  4. <text style="position: absolute;z-index: 1;left:40rpx;">停车记录</text>
  5. <u-dropdown ref="filterDropdown">
  6. <!-- <u-dropdown-item v-model="selectedParkIdx" :title="selectedParkName" :options="myParkSites" @change="changePark"> -->
  7. <u-dropdown-item :title="selectedParkName" >
  8. <view class="slot-content dropdown-filter-con">
  9. <!--
  10. <view class="filter-item">
  11. <text class="filter-label">出场日期</text>
  12. <view class="filter-date" @tap="showCalendar=true">
  13. <text>{{filter.endDate.length>0?(filter.startDate+' 至 '+filter.endDate):'请选择'}}</text>
  14. <u-icon name="search" style="margin:0rpx 20rpx;"></u-icon>
  15. </view>
  16. </view>-->
  17. <view class="filter-item">
  18. <text class="filter-label">停车场</text>
  19. <view class="filter-con">
  20. <!-- <view @tap="selectedParkVal='all'" class="filter-con-item" :class="{'selected-filter':selectedParkVal=='all'}" data-val="all">全部</view> -->
  21. <block v-for="(item,index) in myParkSites" :key="item.park_id">
  22. <view @tap="selectedParkVal=item.park_id;selectedParkIdx=index" class="filter-con-item" :class="{'selected-filter':selectedParkVal==item.park_id}" :data-val="item.park_id">{{item.parking_name.length>7?(item.parking_name.substr(0,7)+'...'):item.parking_name}}</view>
  23. </block>
  24. </view>
  25. </view>
  26. <view class="filter-item">
  27. <text class="filter-label">区域</text>
  28. <view class="filter-con">
  29. <view @tap="selectedAreaIdx=null" class="filter-con-item filter-con-item-big" :class="{'selected-filter':selectedAreaIdx==null}" data-val="all">全部</view>
  30. <block v-for="(item,index) in areaMapping[selectedParkVal]" :key="index">
  31. <view @tap="selectedAreaIdx=index" class="filter-con-item filter-con-item-big" :class="{'selected-filter':selectedAreaIdx==index}" :data-val="item.area">{{item.areaName.length>10?(item.areaName.substr(0,10)+'...'):item.areaName}}</view>
  32. </block>
  33. </view>
  34. </view>
  35. <view class="filter-btn">
  36. <view class="filter-btn-reset"></view>
  37. <view class="filter-btn-sure" @tap="changePark">确定</view>
  38. </view>
  39. </view>
  40. </u-dropdown-item>
  41. </u-dropdown>
  42. </u-navbar>
  43. <u-calendar v-model="showCalendar" mode="range" @change="changeCalendar"></u-calendar>
  44. <u-tabs :list="tablist" :is-scroll="false" :current="currentTab" @change="changeTab"></u-tabs>
  45. <!--已离场列表 start-->
  46. <view class="tab-con-wrap" v-show="currentTab==0">
  47. <view class="tab-con-header">
  48. <view style="display: flex;align-items: center;padding:10rpx 0rpx;">
  49. <u-icon name="calendar" size="48" color="#5555ff" style="margin:0rpx 40rpx;" @tap="showCalendar=true"></u-icon>
  50. <u-search shape="round" border-color="#72b2ff" placeholder="输入车牌号模糊查找" v-model="filter.carNum" @search="searchHandler('off')" @custom="searchHandler('off')"></u-search>
  51. </view>
  52. </view>
  53. <view class="tab-con-body">
  54. <scroll-view style="padding:20rpx;height:calc(100vh - 335rpx)" scroll-y="true" lower-threshold="1" @scrolltolower="scrollbtm('off')">
  55. <view class="tab-con-item" style="height: 340rpx;" v-for="(item,index) in offPageData.records" :key="index">
  56. <view class="item-top" style="height:240rpx;">
  57. <u-image width="200rpx" height="160rpx" :src="item.car_img" border-radius="5rpx" @click="previewCarPhoto(item.car_img)"></u-image>
  58. <view class="item-top-right">
  59. <view style="margin-bottom: 10rpx;"><text>{{item.parking_name}}</text></view>
  60. <view class="top-right-con">
  61. <view>进场时间:{{item.in_parking_time}}</view>
  62. <view v-if="item.release_status=='1'">离场时间:{{item.out_parking_time}}</view>
  63. <view>停车时长:{{item.parking_time_txt}}</view>
  64. <view>离场方式:{{item.out_type_name}}</view>
  65. <view v-if="item.out_type=='3'">缴费金额:{{item.pay_amount?(item.pay_amount+'元'):''}}</view>
  66. <view v-else> </view>
  67. </view>
  68. </view>
  69. </view>
  70. <view class="item-footer">
  71. <text class="car-num">{{item.car_num}}</text>
  72. <template v-if="item.out_type=='2'">
  73. <u-button type="warning" size="mini" style="margin:0rpx;" @tap="restoreManualOut(item)">还原手动出场</u-button>
  74. </template>
  75. </view>
  76. </view>
  77. <!-- <u-loadmore :status="loadMoreStat"/> -->
  78. <view v-show="offPageData.showMoreTip">
  79. <u-loadmore :status="offPageData.loadMoreStat" :load-text="loadMoreText"/>
  80. </view>
  81. </scroll-view>
  82. </view>
  83. </view>
  84. <!--已离场列表 end-->
  85. <!--未离场列表 start-->
  86. <view class="tab-con-wrap" v-show="currentTab==1">
  87. <view class="tab-con-header">
  88. <view style="display: flex;align-items: center;padding:10rpx 30rpx;">
  89. <u-button type="primary" size="medium" style="margin:0rpx 10rpx;padding:0rpx 30rpx;" @tap="batchOff" v-show="true">批量出场未标记车辆</u-button>
  90. <u-search shape="round" border-color="#72b2ff" placeholder="输入车牌号模糊查找" v-model="filter.carNum" @search="searchHandler('in')" @custom="searchHandler('in')"></u-search>
  91. </view>
  92. </view>
  93. <view class="tab-con-body">
  94. <scroll-view style="padding:20rpx;height:calc(100vh - 340rpx)" scroll-y="true" lower-threshold="0.5" @scrolltolower="scrollbtm('in')">
  95. <view class="tab-con-item" v-for="(item,index) in inPageData.records" :key="index">
  96. <view class="item-top">
  97. <u-image width="200rpx" height="160rpx" :src="item.car_img" border-radius="5rpx" @click="previewCarPhoto(item.car_img)"></u-image>
  98. <view class="item-top-right">
  99. <view style="margin-bottom: 10rpx;"><text>{{item.parking_name}}</text></view>
  100. <view class="top-right-con">
  101. <view>进场时间:{{item.in_parking_time}}</view>
  102. <view v-if="item.release_status=='1'">离场时间:{{item.out_parking_time}}</view>
  103. <view>停车时长:{{item.parking_time_txt}}</view>
  104. </view>
  105. </view>
  106. </view>
  107. <view class="item-footer">
  108. <text class="car-num">{{item.car_num}}</text>
  109. <template v-if="item.mark_in">
  110. <u-tag text="已标记在场" type="success" />
  111. <u-button type="warning" size="mini" style="margin:0rpx;" @tap="cancelMarkCarIn(item.id)">取消标记</u-button>
  112. </template>
  113. <template v-else>
  114. <u-button type="primary" size="mini" style="margin:0rpx;" @tap="manualOut(item)">手动出场</u-button>
  115. <u-button type="warning" size="mini" style="margin:0rpx;" @tap="markCarIn(item.id)">标记在场</u-button>
  116. </template>
  117. </view>
  118. </view>
  119. <!-- <u-loadmore :status="loadMoreStat"/> -->
  120. <view v-show="inPageData.showMoreTip">
  121. <u-loadmore :status="inPageData.loadMoreStat" :load-text="loadMoreText"/>
  122. </view>
  123. </scroll-view>
  124. </view>
  125. </view>
  126. <!--未离场列表 end-->
  127. <!--已标记列表 start-->
  128. <view class="tab-con-wrap" v-show="false">
  129. <view class="tab-con-header">
  130. <view style="display: flex;align-items: center;padding:10rpx 10rpx;">
  131. <u-button type="primary" size="medium" style="margin:0rpx 10rpx;padding:0rpx 30rpx;" @tap="batchOff" v-show="true">批量出场未标记车辆</u-button>
  132. <u-search shape="round" border-color="#72b2ff" placeholder="输入车牌号模糊查找" v-model="filter.carNum" @search="searchHandler('marked')" @custom="searchHandler('marked')"></u-search>
  133. </view>
  134. </view>
  135. <view class="tab-con-body">
  136. <scroll-view style="padding:20rpx;height:calc(100vh - 340rpx);" scroll-y="true" lower-threshold="0.5" @scrolltolower="scrollbtm('marked')">
  137. <view class="tab-con-item" v-for="(item,index) in markedPageData.records" :key="index">
  138. <view class="item-top">
  139. <u-image width="200rpx" height="160rpx" :src="item.car_img" border-radius="5rpx" @click="previewCarPhoto(item.car_img)"></u-image>
  140. <view class="item-top-right">
  141. <view style="margin-bottom: 10rpx;"><text>{{item.parking_name}}</text></view>
  142. <view class="top-right-con">
  143. <view>进场时间:{{item.in_parking_time}}</view>
  144. <view>停车时长:{{item.parking_time_txt}}</view>
  145. </view>
  146. </view>
  147. </view>
  148. <view class="item-footer">
  149. <text class="car-num">{{item.car_num}}</text>
  150. <u-tag text="已标记在场" type="success" />
  151. <u-button type="warning" size="mini" style="margin:0rpx;" @tap="cancelMarkCarIn(item.id)">取消标记</u-button>
  152. </view>
  153. </view>
  154. <view v-show="markedPageData.showMoreTip">
  155. <u-loadmore :status="markedPageData.loadMoreStat" :load-text="loadMoreText"/>
  156. </view>
  157. </scroll-view>
  158. </view>
  159. </view>
  160. <!--已标记列表 end-->
  161. </view>
  162. </template>
  163. <script>
  164. import * as api from '@/apis/parkinglog.js'
  165. import app from '@/utils/app.js'
  166. export default {
  167. data() {
  168. return {
  169. showCalendar:false,
  170. tabTitParam:{
  171. offCount:0,
  172. inCount:0,
  173. markedCount:0,
  174. isToday:true
  175. },
  176. currentTab:0,
  177. loadMoreStat:'loadmore',
  178. showMoreTip:false,
  179. loadMoreText: {
  180. loadmore: '轻轻上拉',
  181. loading: '努力加载中',
  182. nomore: '实在没有了'
  183. },
  184. loadingMore:false,
  185. filter:{
  186. startDate:'',
  187. endDate:'',
  188. carNum:''
  189. },
  190. myParkSites:[],
  191. parkAreas:[],
  192. areaMapping:{},
  193. selectedParkVal:'all',
  194. selectedAreaIdx:null,
  195. allParkIds:'',
  196. selectedParkIdx:null,
  197. filterInputCss:{
  198. 'background-color':'#f2f5fa',
  199. 'padding-left':'10rpx',
  200. 'phstyle':'font-size:24rpx;'
  201. },
  202. pagedData:{},
  203. offPageData:{loadMoreStat:'loadmore',showMoreTip:false}, //已离场
  204. inPageData:{loadMoreStat:'loadmore',showMoreTip:false} ,//未离场
  205. markedPageData:{loadMoreStat:'loadmore',showMoreTip:false} //已标记
  206. }
  207. },
  208. onLoad(){
  209. this.loadMyParkSites()
  210. this.changePark()
  211. },
  212. onShow(){
  213. //this.loadPageData(this.getLoadParams(1),false,"in");
  214. //this.loadPageData(this.getLoadParams(1),false,"off");
  215. },
  216. computed:{
  217. selectedParkName(){
  218. let chk=this.myParkSites && this.selectedParkIdx!=null
  219. if(chk){
  220. let dropWinTit=this.myParkSites[this.selectedParkIdx].label
  221. if(this.areaMapping[this.selectedParkVal] && this.selectedAreaIdx!=null){
  222. dropWinTit+="-"+this.areaMapping[this.selectedParkVal][this.selectedAreaIdx].areaName
  223. }
  224. return dropWinTit
  225. }
  226. else{
  227. return '选择停车场'
  228. }
  229. },
  230. tablist(){
  231. return [
  232. {name:`${this.tabTitParam.isToday?'今日':''}已离场(${this.tabTitParam.offCount})`},
  233. {name:`未离场(${this.tabTitParam.inCount}/${this.tabTitParam.markedCount})`}
  234. ]
  235. }
  236. },
  237. methods: {
  238. getLoadParams(pnum){
  239. let selParkId=this.myParkSites[this.selectedParkIdx].park_id
  240. let selArea=this.areaMapping[selParkId] && this.selectedAreaIdx!=null ? this.areaMapping[selParkId][this.selectedAreaIdx].area:''
  241. let status=this.currentTab==0?"off":"in"
  242. let {carNum,startDate:queryStart,endDate:queryEnd}=this.filter
  243. /*
  244. if(status=="off"){
  245. return {outType:'2',parkId:selParkId,status,carNum,queryStart,queryEnd,pageNum:pnum,pageSize:10}
  246. }
  247. else{
  248. return {parkId:selParkId,status,carNum,queryStart,queryEnd,pageNum:pnum,pageSize:10}
  249. }*/
  250. return {area:selArea,parkId:selParkId,status,carNum,queryStart,queryEnd,pageNum:pnum,pageSize:10}
  251. },
  252. checkHadMore(offType){
  253. let rst=null
  254. if(offType=="off"){
  255. rst=this.offPageData.pageNum<this.offPageData.pageCount;
  256. this.offPageData.showMoreTip=true;
  257. this.offPageData.loadMoreStat=rst?'loadmore':'nomore';
  258. }
  259. else if(offType=="in"){
  260. rst=this.inPageData.pageNum<this.inPageData.pageCount;
  261. this.inPageData.showMoreTip=true;
  262. this.inPageData.loadMoreStat=rst?'loadmore':'nomore';
  263. }
  264. else if(offType=="marked"){
  265. rst=this.markedPageData.pageNum<this.markedPageData.pageCount;
  266. this.markedPageData.showMoreTip=true;
  267. this.markedPageData.loadMoreStat=rst?'loadmore':'nomore';
  268. }
  269. return rst;
  270. },
  271. changePark(){
  272. if(this.$refs.filterDropdown){
  273. this.$refs.filterDropdown.close();
  274. }
  275. //切换停车场时,清空之前的时间条件
  276. this.filter.startDate=null;
  277. this.filter.endDate=null;
  278. this.loadPageData(this.getLoadParams(1),false,"in");
  279. this.loadPageData(this.getLoadParams(1),false,"off");
  280. this.loadMarked(this.getLoadParams(1),false)
  281. },
  282. changeTab(idx){
  283. this.currentTab=idx;
  284. },
  285. searchHandler(type){
  286. //3个搜索框的搜索处理
  287. if(type=="off"){ //已离场
  288. this.loadPageData(this.getLoadParams(1),false,"off")
  289. }
  290. else if(type=="in"){
  291. this.loadPageData(this.getLoadParams(1),false,"in")
  292. }
  293. else if(type=="marked"){
  294. this.loadMarked(this.getLoadParams(1),false)
  295. }
  296. },
  297. changeCalendar(e){
  298. this.filter.startDate=e.startDate;
  299. this.filter.endDate=e.endDate;
  300. //日期查询目前只用于已离场
  301. this.loadPageData(this.getLoadParams(1),false,"off");
  302. },
  303. scrollbtm(offType){
  304. //console.log('scroll btm')
  305. //触底事件会反复触发,会导致同时发出多个相同请求,需要同步控制
  306. /*if(this.loadingMore){
  307. return;
  308. }
  309. this.loadingMore=true;
  310. */
  311. if(!this.checkHadMore(offType)){
  312. return;
  313. }
  314. let pnum=1;
  315. if(offType=="off" && this.offPageData.loadMoreStat!='loading'){
  316. this.offPageData.loadMoreStat='loading';
  317. pnum=this.offPageData.pageNum+1;
  318. this.loadPageData(this.getLoadParams(pnum),true,offType)
  319. }
  320. else if(offType=="in" && this.inPageData.loadMoreStat!='loading'){
  321. this.inPageData.loadMoreStat='loading';
  322. pnum=this.inPageData.pageNum+1;
  323. this.loadPageData(this.getLoadParams(pnum),true,offType)
  324. }
  325. else if(offType=="marked" && this.markedPageData.loadMoreStat!='loading'){
  326. this.markedPageData.loadMoreStat='loading';
  327. pnum=this.markedPageData.pageNum+1;
  328. this.loadMarked(this.getLoadParams(pnum),true)
  329. }
  330. },
  331. async loadMyParkSites(){
  332. //本地缓存中获取停车场,需刷新首页才能更新
  333. let pks=api.getMyParkSites();
  334. if(!pks){
  335. return;
  336. }
  337. let ids=[];
  338. pks.forEach(function(item,index){
  339. ids.push(item.park_id);
  340. item['value']=index;
  341. item['label']=item.parking_name;
  342. });
  343. this.allParkIds=ids.join(",");
  344. this.myParkSites=pks;
  345. //默认选中第1个
  346. this.selectedParkIdx=0;
  347. this.selectedParkVal=pks[this.selectedParkIdx].park_id
  348. //加载区域信息
  349. let resp=await api.loadMultiParkAreas(this.allParkIds).catch(err=>{
  350. console.log(err)
  351. })
  352. if(resp && resp.success && resp.data){
  353. console.log(resp)
  354. let areaMap={}
  355. resp.data.forEach(item=>{
  356. if(!areaMap[item.parkId]){
  357. areaMap[item.parkId]=[]
  358. }
  359. areaMap[item.parkId].push(item)
  360. })
  361. this.areaMapping=areaMap
  362. //console.log(areaMap)
  363. }
  364. },
  365. loadMarked(param,moreLoad){
  366. //加载已标记记录
  367. let offType='marked'
  368. if(!moreLoad){
  369. this.markedPageData.records=[] //避免加载失败后旧数据还在显示
  370. }
  371. uni.showLoading({
  372. title:'加载中...'
  373. });
  374. api.loadMarked(param).then(resp=>{
  375. uni.hideLoading()
  376. //console.log(resp)
  377. if(!resp.success){
  378. uni.showToast({
  379. title:resp.msg||'加载已标记数据失败',
  380. icon:'none'
  381. })
  382. return;
  383. }
  384. let pagedData=resp.data.pagedData
  385. this.parseDatas(pagedData);
  386. if(moreLoad && this.markedPageData && this.markedPageData.records){
  387. pagedData.records=this.markedPageData.records.concat(pagedData.records)
  388. }
  389. pagedData.showMoreTip=this.markedPageData.showMoreTip
  390. pagedData.loadMoreStat=this.markedPageData.loadMoreStat
  391. this.markedPageData=pagedData
  392. this.checkHadMore(offType);
  393. this.renderSortTab(pagedData,offType);
  394. }).catch(err=>{
  395. console.log(err)
  396. uni.hideLoading()
  397. uni.showToast({
  398. title:'加载已标记数据出错',
  399. icon:'none'
  400. })
  401. })
  402. },
  403. loadPageData(param,moreLoad,offType){
  404. uni.showLoading({
  405. title:'加载中...'
  406. });
  407. param.status=offType
  408. api.loadPageData(param).then(resp => {
  409. //console.log(resp)
  410. uni.hideLoading();
  411. if(!resp.success){
  412. uni.showToast({
  413. title:resp.msg||'加载数据失败',
  414. icon:'none'
  415. })
  416. return;
  417. }
  418. let pagedData=resp.data.pagedData;
  419. this.parseDatas(pagedData);
  420. if(offType=="off"){ //查询已离场数据结果
  421. if(moreLoad){
  422. pagedData.records=pagedData.records?this.offPageData.records.concat(pagedData.records):this.offPageData.records;
  423. }
  424. pagedData.showMoreTip=this.offPageData.showMoreTip
  425. pagedData.loadMoreStat=this.offPageData.loadMoreStat
  426. this.offPageData=pagedData
  427. }
  428. else{ //未离场
  429. if(moreLoad){
  430. pagedData.records=pagedData.records?this.inPageData.records.concat(pagedData.records):this.inPageData.records;
  431. }
  432. pagedData.showMoreTip=this.inPageData.showMoreTip
  433. pagedData.loadMoreStat=this.inPageData.loadMoreStat
  434. this.inPageData=pagedData
  435. }
  436. this.renderSortTab(pagedData,offType);
  437. this.checkHadMore(offType);
  438. }).catch(error => {
  439. console.log(error)
  440. uni.hideLoading();
  441. });
  442. },
  443. renderSortTab(pageMode,offType){ //rptData
  444. /**
  445. let [tab1,tab2]=this.tablist
  446. if(offType=="off"){
  447. let tmpname=this.filter.startDate && this.filter.startDate!=''?'已离场':'今日已离场';
  448. tab1={name:`${tmpname}(${pageMode.total!=null?pageMode.total:0})`}
  449. }
  450. else if(offType=="in"){
  451. tab2={name:`未离场(${pageMode.total!=null?pageMode.total:0})`}
  452. }
  453. else if(offType=="marked"){
  454. tab3={name:`已标记(${pageMode.total!=null?pageMode.total:0})`}
  455. }
  456. this.tablist=[tab1,tab2]**/
  457. if(offType=="off"){
  458. this.tabTitParam.isToday=this.filter.startDate==null || this.filter.startDate==''
  459. this.tabTitParam.offCount=pageMode.total!=null?pageMode.total:0
  460. }
  461. else if(offType=="in"){
  462. this.tabTitParam.inCount=pageMode.total!=null?pageMode.total:0
  463. }
  464. else if(offType=="marked"){
  465. this.tabTitParam.markedCount=pageMode.total!=null?pageMode.total:0
  466. }
  467. },
  468. parseDatas(respData){
  469. respData['pageNum']=respData.current;
  470. respData['pageCount']=respData.pages;
  471. respData['pageSize']=respData.size;
  472. let outTypeOpt={'1':'手动抬杆','2':'手动移出','3':'缴费离场','4':'VIP会员'}
  473. let datas=respData.records;
  474. let tmp=null,pkh=null;
  475. datas.forEach((item) => {
  476. tmp=item.release_status=='0'?item.cal_parking_time:item.parking_time;
  477. tmp=!tmp?0:tmp;
  478. pkh=Math.floor(tmp/60);
  479. item['parking_time_txt']=pkh>0?(pkh.toFixed(0)+"小时"+(tmp-pkh*60)+"分钟"):(tmp+"分钟");
  480. item['car_img']=item.release_status=='0'?item.in_image:item.out_image;
  481. if(!item['car_img']){
  482. item['car_img']='../../static/img/def_car.png';
  483. }
  484. item['out_type_name']=outTypeOpt[item['out_type']] || '';
  485. item['pay_amount']=item['pay_amount']?item['pay_amount'].toFixed(2):null;
  486. //item['out_type']=='3' &&
  487. });
  488. },
  489. previewCarPhoto(img){
  490. let array = [];
  491. array.push(img);
  492. uni.previewImage({
  493. urls: array,
  494. current: array[0]
  495. });
  496. },
  497. manualOut(record){
  498. let con=`确定要对车辆【${record.car_num}](停车${record.parking_time_txt})进行手动出场吗?`;
  499. uni.showModal({
  500. title:'手动出场确认',
  501. content:con,
  502. success:(res)=>{
  503. if (res.confirm) {
  504. this.manualOutSubmit(record.id)
  505. } else if (res.cancel) {
  506. console.log('用户取消手动出场');
  507. }
  508. }
  509. })
  510. },
  511. manualOutSubmit(recordId){
  512. api.manualOut(recordId,app.takeSetting('user_id')).then(resp=>{
  513. if(!resp.success){
  514. uni.showToast({
  515. title:resp.msg||'手动出场失败',
  516. icon:'none'
  517. })
  518. return;
  519. }
  520. uni.showToast({
  521. title:'操作成功',
  522. icon:'success'
  523. })
  524. //避免成功提示跳过
  525. setTimeout(()=>{
  526. //let pn=this.inPageData.pageNum
  527. this.loadPageData(this.getLoadParams(1),false,'in') //刷新当前页
  528. this.loadPageData(this.getLoadParams(1),false,'off')
  529. },1000)
  530. }).catch(err=>{
  531. console.log(err)
  532. uni.showToast({
  533. title:'手动出场出错',
  534. icon:'none'
  535. })
  536. })
  537. },
  538. markCarIn(recordId){
  539. api.markCarIn(recordId,app.takeSetting('user_id')).then(resp=>{
  540. if(!resp.success){
  541. uni.showToast({
  542. title:resp.msg||'标记车辆失败',
  543. icon:'none'
  544. })
  545. return;
  546. }
  547. uni.showToast({
  548. title:'标记成功',
  549. icon:'success'
  550. })
  551. setTimeout(()=>{
  552. //let pn=this.inPageData.pageNum
  553. this.loadPageData(this.getLoadParams(1),false,'in')
  554. this.loadMarked(this.getLoadParams(1),false)
  555. },1000)
  556. }).catch(err=>{
  557. uni.showToast({
  558. title:'标记车辆出错',
  559. icon:'none'
  560. })
  561. })
  562. },
  563. cancelMarkCarIn(recordId){
  564. api.cancelMarkCarIn(recordId,app.takeSetting('user_id')).then(resp=>{
  565. if(!resp.success){
  566. uni.showToast({
  567. title:resp.msg||'取消标记失败',
  568. icon:'none'
  569. })
  570. return;
  571. }
  572. uni.showToast({
  573. title:'取消标记成功',
  574. icon:'success'
  575. })
  576. setTimeout(()=>{
  577. //let pn=this.inPageData.pageNum
  578. this.loadPageData(this.getLoadParams(1),false,'in')
  579. this.loadMarked(this.getLoadParams(1),false)
  580. },1000)
  581. }).catch(err=>{
  582. uni.showToast({
  583. title:'取消标记出错',
  584. icon:'none'
  585. })
  586. })
  587. },
  588. batchOff(){
  589. let markedCount=this.markedPageData ? this.markedPageData.total :0
  590. if(markedCount<=0){
  591. uni.showToast({
  592. title:'还未标记任何车辆',
  593. icon:'none'
  594. })
  595. return
  596. }
  597. let selPark=this.myParkSites?this.myParkSites[this.selectedParkIdx]:null
  598. if(!selPark){
  599. uni.showToast({
  600. title:'还未选择停车场',
  601. icon:'none'
  602. })
  603. return
  604. }
  605. if(this.markedPageData.records[0].park_id != selPark.park_id){
  606. uni.showModal({
  607. title:'操作提示',
  608. content:'标记车辆所在停车场与选择的停车场不一致',
  609. showCancel:false
  610. })
  611. return
  612. }
  613. uni.showModal({
  614. title:'未标记车辆出场确认',
  615. content:`系统记录的未离场车辆与实际不一致,已标记表示确实在场内,未标记(实际已不在场内)将更新为出场状态。请确认信息:停车场【${selPark.parking_name}】,已完成标记数【${markedCount}】,`,
  616. showCancel:true,
  617. success:(res)=>{
  618. if (res.confirm) {
  619. this.batchOffSubmit(selPark.park_id);
  620. } else if (res.cancel) {
  621. console.log('用户点击取消');
  622. }
  623. }
  624. })
  625. },
  626. batchOffSubmit(parkId){
  627. uni.showLoading({
  628. title:'处理中...',
  629. mask:true
  630. });
  631. api.batchOffUnmarked(parkId).then(resp=>{
  632. uni.hideLoading()
  633. if(!resp.success){
  634. uni.showToast({
  635. title:resp.msg||'批量出场失败',
  636. icon:'none'
  637. })
  638. return;
  639. }
  640. uni.showToast({
  641. title:'批量出场成功',
  642. icon:'success'
  643. })
  644. setTimeout(()=>{
  645. this.changePark()
  646. },1000)
  647. }).catch(err=>{
  648. uni.hideLoading()
  649. console.log(err)
  650. uni.showToast({
  651. title:'批量出场失败',
  652. icon:'none'
  653. })
  654. })
  655. },
  656. restoreManualOut(record){
  657. let con=`确定要对车辆【${record.car_num}](停车${record.parking_time_txt})还原手动出场吗?`;
  658. uni.showModal({
  659. title:'还原手动出场确认',
  660. content:con,
  661. showCancel:true,
  662. success:(res)=>{
  663. if (res.confirm) {
  664. this.restoreManualOutSubmit(record.id);
  665. } else if (res.cancel) {
  666. console.log('用户点击取消');
  667. }
  668. }
  669. })
  670. },
  671. restoreManualOutSubmit(parkingLogId){
  672. uni.showLoading({
  673. title:'处理中...',
  674. mask:true
  675. });
  676. api.restoreManualOut(parkingLogId,app.takeSetting('user_id')).then(resp=>{
  677. uni.hideLoading()
  678. if(!resp.success){
  679. uni.showToast({
  680. title:resp.msg||'还原手动出场失败',
  681. icon:'none'
  682. })
  683. return;
  684. }
  685. uni.showToast({
  686. title:'还原手动出场成功',
  687. icon:'success'
  688. })
  689. setTimeout(()=>{
  690. this.loadPageData(this.getLoadParams(1),false,'off')
  691. this.loadPageData(this.getLoadParams(1),false,'in')
  692. },1000)
  693. }).catch(err=>{
  694. uni.hideLoading()
  695. uni.showToast({
  696. title:'还原手动出场出错',
  697. icon:'none'
  698. })
  699. })
  700. }
  701. }
  702. }
  703. </script>
  704. <style>
  705. page{
  706. background-color: #f4f4f4;
  707. overflow: hidden;
  708. }
  709. .top-navbar/deep/ .u-slot-content{
  710. justify-content: space-between;
  711. padding:0rpx;
  712. }
  713. .top-navbar/deep/ .u-dropdown__menu{
  714. justify-content: flex-end;
  715. }
  716. .top-navbar/deep/ .u-dropdown__menu .u-dropdown__menu__item{
  717. flex:none;
  718. margin-right: 40rpx;
  719. }
  720. .top-navbar/deep/ .u-dropdown__menu__item__text{
  721. color:#0055ff !important;
  722. }
  723. .top-navbar{
  724. font-size:28rpx;
  725. }
  726. uni-scroll-view{
  727. box-sizing: border-box;
  728. }
  729. .tab-con-item{
  730. background-color: #ffffff;
  731. border-radius: 10rpx;
  732. padding:20rpx;
  733. margin-bottom: 20rpx;
  734. }
  735. .tab-con-item .item-top{
  736. padding:0rpx;
  737. display: flex;
  738. flex-flow: row nowrap;
  739. justify-content:flex-start;
  740. align-items: center;
  741. margin-bottom: 10rpx;
  742. }
  743. .tab-con-item .item-top-right{
  744. display: flex;
  745. flex-flow: column nowrap;
  746. justify-content:space-between;
  747. margin-left:20rpx;
  748. }
  749. .tab-con-item .item-top-right>text{
  750. color:#000000;
  751. margin-bottom:20rpx;
  752. }
  753. .tab-con-item .item-top-right .top-right-con{
  754. font-size:24rpx;
  755. }
  756. .tab-con-item .item-top-right .top-right-con>view{
  757. margin-bottom:10rpx;
  758. }
  759. .tab-con-item .item-footer{
  760. display: flex;
  761. flex-flow: row nowrap;
  762. justify-content:space-between;
  763. align-items: center;
  764. font-size:24rpx;
  765. }
  766. .tab-con-item .item-footer .car-num{
  767. font-size:28rpx;
  768. font-weight: bold;
  769. }
  770. .tab-con-item .item-footer .item-footer-btn{
  771. padding:10rpx 15rpx;
  772. color:#ffffff;
  773. background-color: #185AC6;
  774. border-radius: 6rpx;
  775. }
  776. .dropdown-filter-con{
  777. display: flex;
  778. flex-direction: column;
  779. align-items: flex-start;
  780. justify-content: center;
  781. padding:20rpx 0rpx 0rpx;
  782. box-sizing: border-box;
  783. background-color: #fafafa;
  784. font-size: 26rpx;
  785. }
  786. .filter-item{
  787. width:100%;
  788. padding:0rpx 20rpx 30rpx;
  789. }
  790. .filter-item .filter-label{
  791. /* font-family: '楷体'; */
  792. font-weight: bold;
  793. }
  794. .filter-item .uni-input-wrapper{
  795. background-color: #f2f5fa;
  796. }
  797. .filter-date{
  798. width:100%;
  799. height:72rpx;
  800. line-height: 55rpx;
  801. background-color: #f2f5fa;
  802. margin-top: 20rpx;
  803. display: flex;
  804. align-items:center;
  805. padding-left:10rpx;
  806. }
  807. .filter-date text{
  808. flex:1;
  809. }
  810. .filter-con{
  811. display: flex;
  812. flex-flow: row wrap;
  813. justify-content:space-between;
  814. /* justify-self: center; */
  815. align-items: center;
  816. margin: 20rpx auto 0rpx;
  817. }
  818. .filter-con .filter-con-item{
  819. padding:10rpx 10rpx;
  820. text-align: center;
  821. background-color: #f2f5fa;
  822. /* color:#ffffff; */
  823. /* height: 45rpx; */
  824. width:28vw;
  825. margin-right: 3vw;
  826. margin-bottom: 20rpx;
  827. }
  828. .filter-con .filter-con-item-big{
  829. width:24vw;
  830. height:88rpx;
  831. }
  832. .filter-con .selected-filter{
  833. background-color: #185ac6;
  834. color:#ffffff;
  835. }
  836. .filter-btn{
  837. display: flex;
  838. flex-flow: row wrap;
  839. justify-content:flex-start;
  840. align-items: center;
  841. height: 80rpx;
  842. width:100vw;
  843. border-top:1px solid #f2f2f2;
  844. }
  845. .filter-btn-reset{
  846. flex:1;
  847. text-align: center;
  848. line-height: 80rpx;
  849. background-color: #f2f2f2;
  850. }
  851. .filter-btn-sure{
  852. flex:2;
  853. text-align: center;
  854. background-color: #185ac6;
  855. color:#ffffff;
  856. line-height: 80rpx;
  857. }
  858. </style>