parkingSiteDes.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <view class="container">
  3. <u-navbar title="停车场主页" :background="{backgroundColor: '#ffffff'}" class="top-navbar" title-size="30">
  4. </u-navbar>
  5. <view class="parking-panel">
  6. <view class="panel-left">
  7. <view class="panel-row">
  8. <text class="item-title" style="font-size: 32rpx;color:#000;">{{parkingSite.parking_name}}</text>
  9. <u-icon name="edit-pen" size="32" color="#4a4a4a" style="margin-left:100rpx;padding:10rpx;" @tap="editParking"></u-icon>
  10. </view>
  11. <view class="panel-row">
  12. <text class="item-title">区域</text>
  13. <text class="item-title">车位余数 / 总数</text>
  14. </view>
  15. <view class="panel-row" v-for="(site,index) in parkingSite.sites" :key="index">
  16. <text class="item-title">{{site.areaName}}</text>
  17. <text class="num-txt">{{site.surplusParkingNumber}} / {{site.totalParkingNumber}}</text>
  18. </view>
  19. </view>
  20. <image :src="parkingSite.pic_url" style="width:200rpx;height:160rpx;border-radius: 10rpx;"></image>
  21. </view>
  22. <view class="parking-adr">
  23. <view style="padding-left:30rpx;line-height:60rpx;height: 60rpx;position: absolute;z-index: 2;width:100%;background-color: rgba(255,255,255,0.9);">{{parkingSite.address_}}</view>
  24. <image src="../../static/img/addrbg.png" style="height: 60rpx;width:100%;position: relative;z-index: 1;"></image>
  25. </view>
  26. <view class="li-title">收费规则</view>
  27. <view class="li-con">
  28. <text space="emsp"> {{chargeRule.rule_txt}}</text>
  29. <!-- <view style="margin-top:15rpx;"><text space="emsp"> {{chargeRule.oth_rule_txt}}</text></view> -->
  30. </view>
  31. <view class="li-title" style="display: flex;justify-content: space-between;">
  32. <text>设备列表</text>
  33. <u-icon name="reload" size="32" color="#55aaff" @click="loadPageData(crtparkId)"></u-icon>
  34. </view>
  35. <view class="li-con" v-for="(item,index) in devs">
  36. <view class="dev-tit">
  37. <text>{{item.gateName}}</text>
  38. <u-button type="primary" :custom-style="{height:'60rpx',margin:'0rpx 30rpx'}" :plain="true" @tap="manualPass(item.onlineDevId,item.gateName)">手动放行</u-button>
  39. <!-- <view class="dev-view"><text>查看</text><u-icon name="arrow-right"></u-icon></view> -->
  40. </view>
  41. <view class="dev-stat">
  42. <view><text style="margin-right:10rpx;">闸口状态:{{item.gateStatus?'在线':'离线'}} </text>
  43. <u-icon :name="item.channel_status=='1'?'checkmark-circle-fill':'error-circle-fill'" size="30" :color="item.gateStatus?'#15b53a':'#888888'"></u-icon>
  44. <!-- <text style="margin:0rpx 10rpx 0rpx 40rpx;">摄像头状态:正常 </text><u-icon name="checkmark-circle-fill" size="30" color="#15b53a"></u-icon> -->
  45. </view>
  46. </view>
  47. </view>
  48. <!-- <u-button type="primary" style="margin:50rpx 50rpx;" @tap="manualPass">出口抬杆放行</u-button> -->
  49. <u-modal v-model="showModal" :title="modalTitle" :show-cancel-button="true" @confirm="exePass">
  50. <view class="slot-content">
  51. <u-field v-model="passNote" label="" placeholder="请填写放行说明" type="textarea" label-width="0" :auto-height="false" :field-style="{height:'140rpx'}"/>
  52. </view>
  53. </u-modal>
  54. <u-modal v-model="showEditModal" ref="editModal" title="车位数编辑" :show-cancel-button="true" :async-close="true" @confirm="submitSeat">
  55. <view class="eidt-content">
  56. <view class="edit-row" style="font-weight: bold;">
  57. <text class="item-title">区域</text>
  58. <text class="item-title" style="margin-right:30rpx;">车位余数 / 总数</text>
  59. </view>
  60. <view class="edit-row" v-for="(site,index) in editSites" :key="index">
  61. <text class="item-title">{{site.areaName}}</text>
  62. <view style="display: flex;justify-content: flex-end;">
  63. <u-field type="number" v-model="site.surplusParkingNumber" label="" :label-width="0" :field-style="{'border-bottom':'1px solid #55aaff','width':'60rpx'}" :clearable="false"/>
  64. <u-field type="number" v-model="site.totalParkingNumber" label="" :label-width="0" :field-style="{'border-bottom':'1px solid #55aaff','width':'60rpx'}" :clearable="false"/>
  65. </view>
  66. </view>
  67. </view>
  68. </u-modal>
  69. </view>
  70. </template>
  71. <script>
  72. import * as api from '@/apis/myparkings.js'
  73. export default {
  74. data() {
  75. return {
  76. crtparkId:null,
  77. showModal:false,
  78. modalTitle:'放行说明',
  79. passNote:'',
  80. opening:false,
  81. openingChannel:'',
  82. parkingSite:{},
  83. editSites:null,
  84. chargeRule:{},
  85. othChargeRule:[],
  86. devs:[],
  87. showEditModal:false,
  88. seatModel:{
  89. total:null,
  90. idle:null
  91. }
  92. }
  93. },
  94. onLoad(opt){
  95. this.loadPageData(opt.park_id);
  96. this.crtparkId=opt.park_id
  97. },
  98. methods: {
  99. editParking(){
  100. this.showEditModal=true;
  101. },
  102. closeEditModal(isClose){
  103. if(isClose){
  104. this.showEditModal=false;
  105. }
  106. else{
  107. this.$refs.editModal.clearLoading();
  108. }
  109. },
  110. synSites(){ //编辑车位提交成功后同步模型数据
  111. this.parkingSite['sites']=JSON.parse(JSON.stringify(this.editSites))
  112. },
  113. submitSeat(){
  114. //this.crtparkId
  115. //let arySeat=[{parkId:'11',area:'0',totalParkingNumber:0,surplusParkingNumber:2}]
  116. let arySeat=this.editSites.map(area=>{
  117. area['parkId']=this.crtparkId
  118. return area
  119. })
  120. if(this.crtparkId=='1'){ //荆鹏停车场
  121. api.updateParkingAreaSeat(arySeat).then(resp=>{
  122. if(!resp.success){
  123. uni.showToast({
  124. title:resp.msg||'保存数据失败',
  125. icon:'none'
  126. })
  127. this.closeEditModal()
  128. return;
  129. }
  130. uni.showToast({
  131. title:'操作成功',
  132. icon:'success'
  133. })
  134. this.synSites()
  135. this.closeEditModal(true)
  136. }).catch(err=>{
  137. this.closeEditModal()
  138. uni.showToast({
  139. title:'保存数据出错',
  140. icon:'none'
  141. })
  142. })
  143. }
  144. else{
  145. api.updateParkingSeat(arySeat[0].parkId,arySeat[0].totalParkingNumber,arySeat[0].surplusParkingNumber).then(resp=>{
  146. if(!resp.success){
  147. uni.showToast({
  148. title:resp.msg||'保存数据失败',
  149. icon:'none'
  150. })
  151. this.closeEditModal()
  152. return;
  153. }
  154. uni.showToast({
  155. title:'操作成功',
  156. icon:'success'
  157. })
  158. this.synSites()
  159. this.closeEditModal(true)
  160. }).catch(err=>{
  161. this.closeEditModal()
  162. uni.showToast({
  163. title:'保存数据出错',
  164. icon:'none'
  165. })
  166. })
  167. }
  168. },
  169. manualPass(channelId,gateName){
  170. if(this.opening){
  171. uni.showToast({
  172. title:'开门中,勿重复操作',
  173. icon:'none'
  174. })
  175. return;
  176. }
  177. this.modalTitle=gateName+"放行";
  178. this.showModal=true;
  179. this.openingChannel=channelId;
  180. },
  181. exePass(){
  182. if(!this.openingChannel){
  183. uni.showToast({
  184. title:'未选择要开启设备',
  185. icon:'none'
  186. })
  187. return;
  188. }
  189. uni.showLoading({
  190. title:'开门中...'
  191. });
  192. api.manualPass(this.openingChannel,this.passNote).then(resp => {
  193. this.opening=false;
  194. uni.hideLoading();
  195. if(!resp.success){
  196. uni.showToast({
  197. title:resp.msg||'开门失败',
  198. icon:'none'
  199. })
  200. }
  201. else{
  202. uni.showToast({
  203. title:'手动开门已执行',
  204. icon:'none'
  205. })
  206. }
  207. }).catch(error => {
  208. this.opening=false;
  209. uni.hideLoading();
  210. });
  211. this.opening=true;
  212. },
  213. loadPageData(id){
  214. uni.showLoading({
  215. title:'加载中...'
  216. });
  217. api.loadParkingCompose(id).then(resp => {
  218. //console.log(resp);
  219. uni.hideLoading();
  220. if(!resp.success){
  221. uni.showToast({
  222. title:resp.msg||'加载数据失败',
  223. icon:'none'
  224. })
  225. return;
  226. }
  227. this.processParkInfo(resp.data.areas, resp.data.parkInfo,id)
  228. this.processRuleDatas(resp.data.chargeRule,resp.data.othchargeRule)
  229. this.devs=this.processDevDatas(resp.data.devs,id); //resp.data.devs
  230. //console.log(this.devs)
  231. }).catch(error => {
  232. uni.hideLoading();
  233. });
  234. },
  235. processParkInfo(areas,parkInfo,parkId){
  236. if(!parkInfo.pic_url){
  237. parkInfo.pic_url="../../static/img/header_bg.png"
  238. }
  239. let siteAry=null
  240. if(parkId=='1'){ //荆鹏停车场
  241. siteAry=areas.map(item=>{
  242. let {areaName,area,totalParkingNumber,surplusParkingNumber}=item
  243. return {areaName,area,totalParkingNumber,surplusParkingNumber}
  244. })
  245. }
  246. else{
  247. siteAry=[{areaName:'全域停车场',totalParkingNumber:parkInfo.total_parking_number,surplusParkingNumber:parkInfo.surplus_parking_number}]
  248. }
  249. parkInfo['sites']=siteAry
  250. this.parkingSite=parkInfo
  251. this.editSites=JSON.parse(JSON.stringify(siteAry))
  252. //console.log(this.parkingSite)
  253. },
  254. processRuleDatas(chargeRule,othchargeRule){
  255. if(!othchargeRule){
  256. othchargeRule=[]
  257. }
  258. let othRuleTxt={ryc:[],xny:[]};
  259. othchargeRule.forEach((item) => {
  260. if(item.car_type=='1'){ //燃油车
  261. othRuleTxt.ryc.push(`${item.min_section}-${item.max_section}分钟:${item.parking_cost}元`);
  262. }
  263. else if(item.car_type=='2'){ //新能源车
  264. othRuleTxt.xny.push(`${item.min_section}-${item.max_section}分钟:${item.parking_cost}元`);
  265. }
  266. })
  267. this.chargeRule=chargeRule||{}
  268. this.chargeRule['rule_txt']=`燃油车\n 免费时长:${this.chargeRule.free_duration}分钟,每小时费用:${this.chargeRule.hour_cost}元,${othRuleTxt.ryc.join(',')} \n新能源车\n 免费时长:${this.chargeRule.new_energy_free_duration}分钟,每小时费用:${this.chargeRule.new_energy_hour_cost}元,${othRuleTxt.xny.join(',')} \n每日封顶费用:${this.chargeRule.day_capping_cost}元`;
  269. },
  270. //设备(通道设备-摄像头),分级显示(停车场-区域-出口、入口),根据所属道闸合并显示
  271. /*
  272. {
  273. area:{
  274. 'areaName':xxx,
  275. 'gate':{
  276. channelFlag:{
  277. 'gateName':xxx,
  278. 'gateStatus':xxx , //[true:online ,false:offline]
  279. 'onlineDevId':'',
  280. 'channels':[]
  281. }
  282. }
  283. }
  284. }*/
  285. processDevDatas(devs,parkId){
  286. if(!devs){
  287. return []
  288. }
  289. //console.log(devs)
  290. if(parkId!='1'){ //非荆鹏停车场
  291. devs.forEach(dev=>{
  292. dev['gateName']=dev['channel_name']
  293. dev['gateStatus']=dev['channel_status']=='1'
  294. dev['onlineDevId']=dev['id']
  295. })
  296. return devs
  297. }
  298. //荆鹏停车场(按道闸合并处理)
  299. let glbDev={},areaKey=null,gateNameStr=null
  300. devs.forEach(dev=>{ //dev.area=['0','1','2',null] 大楼院内(0)、公寓(1)、大楼前门(2)、全部区域(null)
  301. if(!dev.channel_flag){
  302. dev.channel_flag='1'
  303. }
  304. areaKey=dev.area || 'all'
  305. if(!glbDev[areaKey]){ //按区域分组
  306. glbDev[areaKey]={'areaName':dev.area_name||'','gate':{}} //gate 道闸下的通道设备
  307. }
  308. if(!glbDev[areaKey]['gate'][dev.channel_flag]){ //按所属道闸合并显示,道闸名=区域名+道闸序号+'入口/出口'
  309. gateNameStr=`${glbDev[areaKey]['areaName']}道闸${dev.channel_flag||'1'}`
  310. //gateNameStr=gateNameStr.replace('全部区域','')
  311. glbDev[areaKey]['gate'][dev.channel_flag]={'gateName':gateNameStr,'gateStatus':false,'onlineDevId':null, 'channels':[]}
  312. }
  313. glbDev[areaKey]['gate'][dev.channel_flag]['channels'].push(dev)
  314. if(dev.channel_status=="1"){
  315. glbDev[areaKey]['gate'][dev.channel_flag]['gateStatus']=true
  316. glbDev[areaKey]['gate'][dev.channel_flag]['onlineDevId']=dev.id
  317. }
  318. })
  319. console.log(glbDev)
  320. let gateAry=[]
  321. for(let are in glbDev){
  322. for(let gateIdx in glbDev[are]['gate']){
  323. gateAry.push(glbDev[are]['gate'][gateIdx])
  324. }
  325. }
  326. return gateAry
  327. }
  328. }
  329. }
  330. </script>
  331. <style>
  332. page{
  333. background-color: #f4f4f4;
  334. font-family: '华文行楷';
  335. }
  336. .parking-panel{
  337. background-color: #ffffff;
  338. border-radius: 10rpx;
  339. padding:20rpx;
  340. display: flex;
  341. flex-flow: row nowrap;
  342. justify-content: space-between;
  343. align-items: center;
  344. }
  345. .parking-panel .panel-left{
  346. display: flex;
  347. flex-flow: column nowrap;
  348. justify-content: space-between;
  349. align-items: flex-start;
  350. font-family: '华文行楷';
  351. width:480rpx;
  352. }
  353. .parking-panel .panel-left .panel-row,.edit-row{
  354. display: flex;
  355. flex-flow: row nowrap;
  356. justify-content: space-between;
  357. align-items: center;
  358. width:100%;
  359. padding:10rpx 0rpx;
  360. box-sizing: border-box;
  361. font-size:28rpx;
  362. }
  363. .parking-panel .panel-left .panel-row .num-txt{
  364. font-size: 28rpx;
  365. font-weight: bold;
  366. margin:0rpx 10rpx;
  367. }
  368. .parking-panel .panel-left .panel-row .item-title{
  369. font-size:24rpx;
  370. font-weight: bold;
  371. color:#5d5454;
  372. }
  373. .parking-panel .panel-left .left-title{
  374. font-weight: bold;
  375. font-size:32rpx;
  376. color:#000000;
  377. }
  378. .newpower-txt{
  379. color:#27bf3e;
  380. margin:0rpx 10rpx;
  381. }
  382. .parking-adr{
  383. background-color: #ffffff;
  384. /* padding:15rpx 20rpx; */
  385. font-size: 28rpx;
  386. height: 60rpx;
  387. }
  388. .li-title{
  389. margin:30rpx 20rpx 15rpx;
  390. border-left:6rpx solid #1b68e3;
  391. padding:0rpx 20rpx;
  392. }
  393. .li-con{
  394. background-color: #ffffff;
  395. padding:15rpx;
  396. font-size: 26rpx;
  397. color:#4a4a4a;
  398. margin-bottom: 5rpx;
  399. }
  400. .dev-tit{
  401. display: flex;
  402. flex-flow: row nowrap;
  403. justify-content: space-between;
  404. align-items: center;
  405. }
  406. .dev-tit>text{
  407. font-size:32rpx;
  408. font-weight: bold;
  409. }
  410. .dev-tit .dev-view>text{
  411. font-size: 24rpx;
  412. color:#1B68E3;
  413. margin-right:10rpx;
  414. }
  415. .dev-stat{
  416. font-size:24rpx;
  417. color:#646464;
  418. margin:20rpx 0rpx 0rpx;
  419. }
  420. /deep/.u-textarea-inner{
  421. background-color: #ececec;
  422. }
  423. .eidt-content{
  424. padding:10rpx 20rpx;
  425. box-sizing: border-box;
  426. }
  427. .edit-row /deep/.u-field{
  428. width:160rpx !important;
  429. }
  430. </style>