chargeSiteDetail.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <script setup lang="ts">
  2. import { ScanCodeUtil, formatStatusName } from '../utils/index'
  3. import router from '@/router'
  4. import { StaticUrl } from '@/config'
  5. const { statusBarHeight, MenuButtonHeight } = storeToRefs(useSysStore())
  6. const { Location } = storeToRefs(useAddressStore())
  7. const { opcity } = storeToRefs(useSysStore())
  8. const stationId = ref()
  9. onLoad((options: any) => {
  10. console.log(options)
  11. stationId.value = Number(options.stationId)
  12. })
  13. definePage({
  14. name: 'charge-site-detail',
  15. islogin: true,
  16. style: {
  17. navigationBarTitleText: '站点详情',
  18. navigationStyle: 'custom',
  19. },
  20. })
  21. const activeFilter = ref('0')
  22. onMounted(() => {
  23. getStationDetail()
  24. opcity.value = 0
  25. })
  26. /**
  27. * 获取电站详情
  28. */
  29. const stationDetail = ref<Api.chargeStationDetail>()
  30. async function getStationDetail() {
  31. useGlobalLoading().loading({})
  32. const res = await Apis.charge.detail({ data: { stationId: stationId.value, latitude: Location.value.latitude, longitude: Location.value.longitude } })
  33. stationDetail.value = res.data
  34. useGlobalLoading().close()
  35. }
  36. // 使用计算属性动态计算筛选选项
  37. const filterOptions = computed(() => {
  38. const counts = {
  39. 0: 0, // 离线
  40. 1: 0, // 空闲
  41. 2: 0, // 占用
  42. }
  43. // 遍历充电站连接器列表,统计各状态数量
  44. if (stationDetail.value?.connectorList) {
  45. stationDetail.value.connectorList.forEach((item) => {
  46. // 检查status是否为有效键值
  47. if (item.status === 0 || item.status === 1 || item.status === 2) {
  48. counts[item.status as keyof typeof counts]++
  49. }
  50. })
  51. }
  52. return [
  53. { key: '0', label: `离线(${counts['0']})` },
  54. { key: '1', label: `空闲(${counts['1']})` },
  55. { key: '2', label: `占用(${counts['2']})` },
  56. ]
  57. })
  58. // 添加计算属性来过滤设备列表
  59. const filteredConnectors = computed(() => {
  60. if (!stationDetail.value?.connectorList)
  61. return []
  62. // 根据当前选中的状态过滤设备,并限制为前3个
  63. return stationDetail.value.connectorList.filter(
  64. item => String(item.status) === activeFilter.value,
  65. ).slice(0, 3)
  66. })
  67. /**
  68. * 处理站点设备状态
  69. *status 状态:0-离线 1-空闲 2-占用
  70. */
  71. function getStatusImageByStatus(deviceStatus: number) {
  72. switch (deviceStatus) {
  73. case 1: // 空闲
  74. return 'kx'
  75. case 2: // 占用
  76. return 'zy'
  77. case 0: // 离线
  78. return 'lx'
  79. default:
  80. return 'unknown'
  81. }
  82. }
  83. onPageScroll((e) => {
  84. const calculatedOpacity = e.scrollTop / 100
  85. opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
  86. })
  87. // 处理筛选项点击的方法
  88. function handleFilterClick(filterKey: string) {
  89. activeFilter.value = filterKey
  90. console.log(`选择了: ${filterKey}`)
  91. }
  92. function openMap() {
  93. uni.openLocation({
  94. latitude: Number(stationDetail.value?.latitude),
  95. longitude: Number(stationDetail.value?.longitude),
  96. })
  97. }
  98. async function getDeviceInfo(connectorCode: string) {
  99. useGlobalLoading().loading({})
  100. const res = await Apis.charge.connectorDetail({ data: { connectorCode } })
  101. useGlobalLoading().close()
  102. if (res.data.status === 0 || res.data.status === 255) {
  103. useGlobalMessage().alert('此设备异常或被占用,请更换其他设备')
  104. }
  105. else {
  106. router.push({ name: 'charge-start', params: { connectorCode } })
  107. }
  108. }
  109. async function scanCode() {
  110. try {
  111. const connectorCode = await ScanCodeUtil.scanAndGetConnectorCode()
  112. if (!connectorCode) {
  113. useGlobalMessage().alert('二维码不正确')
  114. return
  115. }
  116. // 获取设备信息
  117. getDeviceInfo(connectorCode)
  118. }
  119. catch (error) {
  120. console.error('扫码失败:', error)
  121. }
  122. }
  123. </script>
  124. <template>
  125. <view class="site-detail-page min-h-screen bg-#F6FAFF">
  126. <wd-navbar
  127. title="站点详情" :custom-style="`background-color: rgba(226, 255, 145, ${opcity})`" :bordered="false"
  128. :z-index="999" safe-area-inset-top left-arrow fixed @click-left="router.back()"
  129. />
  130. <view :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }" />
  131. <view class="site-detail-content">
  132. <!-- <view>
  133. <wd-swiper :list="swiperList" :height="260" :indicator="{ type: 'fraction' }" value-key="advertImg" />
  134. </view> -->
  135. <view class="bg-#FFF p-20rpx">
  136. <view class="mt-28rpx box-border px24rpx">
  137. <view class="text-32rpx font-800">
  138. {{ stationDetail?.stationName }}
  139. </view>
  140. <view class="mt-20rpx flex items-center gap-20rpx">
  141. <view class="h-30rpx w-30rpx rounded-4rpx bg-#5BE7FF text-center text-24rpx text-#fff line-height-[30rpx]">
  142. P
  143. </view>
  144. <view class="text-24rpx text-#AAA">
  145. {{ stationDetail?.tips || '--' }}
  146. </view>
  147. </view>
  148. </view>
  149. <view class="ml-10rpx">
  150. <view
  151. class="cardBg-set mt-20rpx box-border h-138rpx w-680rpx flex items-center justify-between rounded-16rpx"
  152. :style="{ backgroundImage: `url(${StaticUrl}/site-detail-navBg.png)` }"
  153. >
  154. <view class="ml-24rpx">
  155. <view class="text-28rpx text-#2B303A font-bold">
  156. 距离您{{ stationDetail?.distance || '--' }}km
  157. </view>
  158. <view class="mt-8rpx w-408rpx overflow-hidden text-ellipsis whitespace-nowrap text-24rpx text-#AAA">
  159. {{ stationDetail?.address }}
  160. </view>
  161. </view>
  162. <view class="mr-24rpx" @click="openMap">
  163. <view>
  164. <image class="h-40rpx w-40rpx" :src="`${StaticUrl}/site-detail-nav.png`" />
  165. </view>
  166. <view class="mt-8rpx text-24rpx">
  167. 导航
  168. </view>
  169. </view>
  170. </view>
  171. </view>
  172. </view>
  173. </view>
  174. <view class="mt20rpx box-border px24rpx">
  175. <view class="rounded-24rpx bg-#FFF p-24rpx">
  176. <view class="flex items-center justify-between">
  177. <view class="text-32rpx font-bold">
  178. 费用信息
  179. </view>
  180. <view class="flex items-center" @click="router.push({ name: 'charge-detail', params: { stationId: String(stationDetail?.stationId), type: 'price' } })">
  181. <view class="text-24rpx text-#AAA">
  182. 查看全部
  183. </view>
  184. <wd-icon name="chevron-right" size="22px" color="#AAAAAA" />
  185. </view>
  186. </view>
  187. <view class="mt-24rpx rounded-16rpx bg-[linear-gradient(90deg,#FEE4C6_0%,rgba(251,235,198,0.23)_100%)] p-24rpx">
  188. <view class="relative flex items-center justify-between">
  189. <view class="text-28rpx font-bold">
  190. 当前价
  191. </view>
  192. <view class="absolute -right-20rpx -top-20rpx">
  193. <image class="h-52rpx w-125rpx" :src="`${StaticUrl}/site-price-tag.png`" />
  194. </view>
  195. </view>
  196. <view class="mt-24rpx flex items-center justify-between">
  197. <view>
  198. <view class="flex items-center">
  199. <text class="text-48rpx text-#FF6464 font-800">
  200. {{ stationDetail?.currentPrice }}
  201. </text>
  202. <text class="text-24rpx">
  203. 元/度
  204. </text>
  205. </view>
  206. <view class="mt-12rpx text-28rpx">
  207. 当前时段:
  208. </view>
  209. <view class="text-bold mt-16rpx text-28rpx">
  210. {{ stationDetail?.currentPeriod }}
  211. </view>
  212. </view>
  213. <view>
  214. <image class="h-182rpx w-88rpx" :src="`${StaticUrl}/site-price-icon.png`" />
  215. </view>
  216. </view>
  217. </view>
  218. </view>
  219. <view class="mt-20rpx rounded-24rpx bg-#FFF p-24rpx">
  220. <view class="flex items-center justify-between">
  221. <view class="text-32rpx font-bold">
  222. 充电终端
  223. </view>
  224. <view class="flex items-center" @click="router.push({ name: 'charge-detail', params: { stationId: String(stationDetail?.stationId), type: 'terminal' } })">
  225. <view class="text-24rpx text-#AAA">
  226. 查看全部
  227. </view>
  228. <wd-icon name="chevron-right" size="22px" color="#AAAAAA" />
  229. </view>
  230. </view>
  231. <view class="mt-28rpx flex items-center gap-20rpx">
  232. <view
  233. v-for="item in filterOptions" :key="item.key"
  234. class="select-item h-60rpx w-152rpx text-28rpx line-height-[60rpx]" :class="[{ 'select-item-active': activeFilter === item.key }]" @click="handleFilterClick(item.key)"
  235. >
  236. {{ item.label }}
  237. </view>
  238. </view>
  239. <view class="mt-24rpx">
  240. <view v-for="item in filteredConnectors" :key="item.connectorId" class="mb-20rpx flex items-center gap-20rpx rounded-16rpx bg-#F6F6F6 p-20rpx" @click="router.push({ name: 'charge-start', params: { connectorCode: item.connectorCode } })">
  241. <view
  242. class="h-116rpx w-116rpx text-center"
  243. :style="{ backgroundImage: `url(${StaticUrl}/site-status-${getStatusImageByStatus(item.status)}.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
  244. >
  245. <image
  246. class="mt-20rpx h-38rpx w-27.18rpx"
  247. :src="`${StaticUrl}/terminal-icon.png`"
  248. />
  249. <view class="text-24rpx font-bold">
  250. {{ formatStatusName(item.statusName) }}
  251. </view>
  252. </view>
  253. <view>
  254. <view class="text-bold text-28rpx">
  255. {{ item.connectorName }}
  256. </view>
  257. <view class="mt-4rpx text-24rpx text-#AAA">
  258. 电类分类:{{ item.equipmentType }}
  259. </view>
  260. <view class="mt-4rpx w-300rpx overflow-hidden truncate whitespace-nowrap text-24rpx text-#AAA">
  261. 终端编号:{{ item.connectorCode }}
  262. </view>
  263. </view>
  264. </view>
  265. <view v-if="filteredConnectors.length < 1" class="h-100rpx w-full text-center text-24rpx text-#AAA line-height-[100rpx]">
  266. 暂无终端信息
  267. </view>
  268. </view>
  269. </view>
  270. </view>
  271. <view class="h-170rpx" />
  272. <view class="fixed bottom-0 left-0 right-0 h-166rpx w-full rounded-[30rpx_30rpx_0_0] bg-#FFF">
  273. <view
  274. class="h-166rpx"
  275. :style="{ backgroundImage: `url(${StaticUrl}/site-price-bg.png)`, backgroundSize: 'cover', backgroundPosition: 'center' }"
  276. >
  277. <view class="h-166rpx flex items-center justify-center gap-32rpx">
  278. <view class="ml-248rpx">
  279. <text class="text-bold text-#F5531A">
  280. </text>
  281. <text class="text-bold text-40rpx text-#F5531A">
  282. {{ stationDetail?.currentPrice }}
  283. </text>
  284. <text class="text-24rpx text-#AAA">
  285. 元/度
  286. </text>
  287. </view>
  288. <view class="scan-qrcode" @click="scanCode">
  289. 扫码充电
  290. </view>
  291. </view>
  292. </view>
  293. </view>
  294. </view>
  295. </template>
  296. <style lang="scss" scoped>
  297. .cardBg-set {
  298. background-size: cover;
  299. background-position: center;
  300. }
  301. .select-item {
  302. background: #f5f3f3;
  303. border-radius: 16rpx;
  304. color: #2B303A;
  305. text-align: center;
  306. }
  307. .select-item-active {
  308. background: #9ED605;
  309. box-shadow: inset 0rpx 20rpx 40rpx 2rpx rgba(100, 255, 218, 0.26);
  310. border-radius: 0rpx 16rpx 0rpx 16rpx;
  311. font-weight: bold;
  312. color: #FFFFFF;
  313. }
  314. .scan-qrcode {
  315. width: 220rpx;
  316. height: 100rpx;
  317. background: linear-gradient(90deg, #DBFC81 0%, #9ED605 100%);
  318. box-shadow: inset 0rpx 6rpx 20rpx 2rpx #FFFFFF;
  319. border-radius: 16rpx;
  320. font-weight: 800;
  321. font-size: 28rpx;
  322. line-height: 112rpx;
  323. text-align: center;
  324. }
  325. </style>