| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- <template>
- <view class="page-container">
- <uv-navbar title="门店详情" bgColor="#C6171E" leftIconColor="#FFFFFF" :titleStyle="{ color: '#FFFFFF' }" :autoBack="true" :placeholder="true"></uv-navbar>
- <!-- 内容区域 -->
- <scroll-view class="content-scroll" scroll-y="true">
- <!-- 轮播图 -->
- <view class="swiper-wrapper" v-if="swiperImages.length">
- <swiper
- class="station-swiper"
- indicator-dots
- indicator-color="rgba(255, 255, 255, 0.5)"
- indicator-active-color="#C6171E"
- autoplay
- circular
- >
- <swiper-item v-for="(img, index) in swiperImages" :key="index">
- <image :src="img" mode="aspectFill" class="swiper-image"></image>
- </swiper-item>
- </swiper>
- </view>
- <!-- 站点信息 -->
- <view class="station-section">
- <WashStation :item="state.station" ref="station_ref"></WashStation>
- </view>
- <!-- 设备列表 -->
- <view class="device-section">
- <view class="section-header">
- <view class="header-dot"></view>
- <text class="header-title">可用设备</text>
- <text class="header-count" v-if="state.deviceList.length">{{ state.deviceList.length }}台</text>
- </view>
- <!-- 加载中 -->
- <view class="status-wrapper" v-if="deviceLoading">
- <uv-loading-icon mode="spinner" size="32" color="#C6171E" text="加载设备中..." textSize="13"></uv-loading-icon>
- </view>
- <!-- 空状态 -->
- <view class="status-wrapper" v-else-if="!state.deviceList.length">
- <uv-empty mode="data" text="暂无可用设备" :marginTop="60"></uv-empty>
- </view>
- <!-- 设备列表 -->
- <view class="device-list" v-else>
- <view
- class="device-card"
- v-for="device in state.deviceList"
- :key="device.id"
- @click="handleClickDevice(device)"
- >
- <view class="device-header">
- <view class="device-name">
- <uv-icon name="car" size="18" color="#C6171E"></uv-icon>
- <text>{{ device.seqName }}</text>
- </view>
- <view class="device-status" :class="'status-' + getDeviceStatusClass(device.state)">
- {{ fmtDictName('WashDevice.state', device.state) }}
- </view>
- </view>
- <view class="device-info">
- <view class="info-row">
- <text class="info-label">设备编号</text>
- <text class="info-value">{{ device.shortId }}</text>
- </view>
- </view>
- <view class="device-functions" v-if="device.functionList && device.functionList.length">
- <view class="function-tag" v-for="(f, i) in device.functionList" :key="i">{{ f }}</view>
- </view>
- <view class="device-action">
- <uv-icon name="arrow-right" size="14" color="#C0C4CC"></uv-icon>
- <text>点击选择此设备</text>
- </view>
- </view>
- </view>
- </view>
- <view class="bottom-spacer"></view>
- </scroll-view>
- <!-- 底部操作栏 -->
- <view class="bottom-bar">
- <view class="bottom-buttons">
- <view class="btn-nav">
- <uv-button
- shape="circle"
- type="info"
- text="门店导航"
- @click="handleNavStation"
- icon="map"
- ></uv-button>
- </view>
- <view class="btn-scan">
- <uv-button
- shape="circle"
- type="primary"
- icon="scan"
- iconColor="#FFFFFF"
- color="#C6171E"
- text="扫码洗车"
- @click="handleClickScan"
- ></uv-button>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { computed, reactive, ref } from "vue";
- import { onLoad } from "@dcloudio/uni-app";
- import { get } from "@/utils/https";
- import { fmtDictName } from "@/utils/common";
- import WashStation from "@/components/station/index.vue";
- const station_ref = ref();
- const deviceLoading = ref(false);
- const initState = () => ({
- deviceList: [] as any[],
- station: {} as any,
- currentUserId: 0,
- });
- const state = reactive(initState());
- // 安全解析轮播图片列表
- const swiperImages = computed(() => {
- const pictures = state.station.pictures;
- if (!pictures) return [];
- return pictures.split("|").filter(Boolean);
- });
- onLoad((options: any) => {
- const id = options?.id;
- const cached = getApp<any>().globalData.last?.station;
- if (cached && String(cached.id) === String(id)) {
- state.station = cached;
- } else if (id) {
- state.station.id = id;
- }
- loadStationDeviceList();
- });
- const handleClickScan = () => {
- uni.navigateTo({ url: "/pages-wash/scan/index" });
- };
- const loadStationDeviceList = () => {
- const stationId = state.station.stationId || state.station.id;
- if (!stationId) return;
- deviceLoading.value = true;
- get("/wash-device/listWashDevice", { stationId })
- .then((deviceList: any) => {
- deviceList.forEach((item: any) => {
- item.functionList = item.functions ? item.functions.split("|") : [];
- });
- state.deviceList = deviceList;
- })
- .catch(() => {
- uni.showToast({ title: "加载失败,下拉重试", icon: "none" });
- })
- .finally(() => {
- deviceLoading.value = false;
- });
- };
- const handleNavStation = () => {
- station_ref.value?.handleNav();
- };
- const handleClickDevice = (device: any) => {
- if (device.currentUserId && device.currentUserId !== state.currentUserId) {
- uni.showToast({ title: "设备已被他人占用", icon: "none" });
- return;
- }
- getApp<any>().globalData.last.device = device;
- uni.navigateTo({
- url:
- "/pages-wash/device/index?shortId=" +
- device.shortId +
- "&stationId=" +
- device.stationId,
- });
- };
- const getDeviceStatusClass = (stateVal: string) => {
- switch (stateVal) {
- case "idle":
- return "success";
- case "working":
- case "busy":
- return "warning";
- case "fault":
- case "error":
- return "error";
- default:
- return "success";
- }
- };
- </script>
- <style lang="scss" scoped>
- .page-container {
- width: 100vw;
- height: 100vh;
- background: $uni-bg-color-page;
- display: flex;
- flex-direction: column;
- position: relative;
- }
- .content-scroll {
- flex: 1;
- width: 100%;
- box-sizing: border-box;
- }
- // 轮播图
- .swiper-wrapper {
- padding: 16rpx 30rpx 24rpx;
- .station-swiper {
- height: 360rpx;
- border-radius: 24rpx;
- overflow: hidden;
- }
- .swiper-image {
- width: 100%;
- height: 100%;
- display: block;
- }
- }
- // 站点信息 — 组件自带卡片样式,这里只做外边距
- .station-section {
- margin: 0 30rpx 24rpx;
- }
- // 设备区域
- .device-section {
- margin: 0 30rpx;
- .section-header {
- display: flex;
- align-items: center;
- gap: 12rpx;
- margin-bottom: 24rpx;
- padding: 0 8rpx;
- .header-dot {
- width: 10rpx;
- height: 10rpx;
- background: $uni-color-primary;
- border-radius: 50%;
- flex-shrink: 0;
- }
- .header-title {
- font-size: 30rpx;
- font-weight: $uni-font-weight-semibold;
- color: $uni-text-color-dark;
- flex: 1;
- }
- .header-count {
- font-size: 24rpx;
- color: $uni-text-color-hint;
- background: $uni-bg-color-page;
- padding: 6rpx 16rpx;
- border-radius: 12rpx;
- }
- }
- }
- .status-wrapper {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 80rpx 0;
- }
- // 设备卡片
- .device-list {
- .device-card {
- padding: 28rpx;
- margin-bottom: 20rpx;
- @include card-interactive(24rpx);
- .device-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20rpx;
- .device-name {
- display: flex;
- align-items: center;
- gap: 8rpx;
- font-size: 28rpx;
- font-weight: $uni-font-weight-semibold;
- color: $uni-text-color-dark;
- }
- .device-status {
- font-size: 22rpx;
- padding: 6rpx 16rpx;
- border-radius: 20rpx;
- font-weight: $uni-font-weight-medium;
- &.status-success {
- background: rgba($uni-color-success, 0.1);
- color: $uni-color-success;
- }
- &.status-warning {
- background: rgba($uni-color-warning, 0.1);
- color: $uni-color-warning;
- }
- &.status-error {
- background: rgba($uni-color-error, 0.1);
- color: $uni-color-error;
- }
- }
- }
- .device-info {
- padding: 16rpx 0;
- border-top: 1rpx solid $uni-border-color-light;
- border-bottom: 1rpx solid $uni-border-color-light;
- .info-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- .info-label {
- font-size: 24rpx;
- color: $uni-text-color-hint;
- }
- .info-value {
- font-size: 26rpx;
- color: $uni-text-color-dark;
- font-weight: $uni-font-weight-medium;
- }
- }
- }
- .device-functions {
- display: flex;
- flex-wrap: wrap;
- gap: 12rpx;
- margin: 16rpx 0;
- .function-tag {
- font-size: 22rpx;
- padding: 6rpx 16rpx;
- background: rgba($uni-color-primary, 0.08);
- color: $uni-color-primary;
- border-radius: 16rpx;
- font-weight: $uni-font-weight-medium;
- }
- }
- .device-action {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 4rpx;
- font-size: 24rpx;
- color: $uni-text-color-hint;
- margin-top: 12rpx;
- }
- }
- }
- .bottom-spacer {
- height: 160rpx;
- }
- // 底部操作栏
- .bottom-bar {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- background: $uni-bg-color-card;
- padding: 20rpx 30rpx;
- padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
- padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
- box-shadow: 0 -2rpx 12rpx rgba($uni-text-color, 0.04);
- z-index: 100;
- .bottom-buttons {
- display: flex;
- gap: 20rpx;
- .btn-nav {
- flex: 1;
- }
- .btn-scan {
- flex: 2;
- }
- }
- }
- </style>
|