Newer
Older
smartwell_front / src / views / mobile / device / add.vue
<!--
  Description: h5-新装设备
  Author: 李亚光
  Date: 2024-12-27
 -->
<script lang="ts" setup name="H5DeviceAdd">
import dayjs from 'dayjs'
import { Toast, showImagePreview } from 'vant'
import { getProductListPage } from '@/api/home/device/product'
import { getDeviceTypeListPage } from '@/api/home/device/type'
import { showToast, showLoadingToast, closeToast, showConfirmDialog } from 'vant'
import { getWellListPage } from '@/api/home/well/well'
import { getStationListPage } from '@/api/home/station/station'
import AMap from '@/components/map/index.vue'
import { keepSearchParams } from '@/utils/keepQuery'
import { uploadApi } from '@/api/mobile/operation'
const $router = useRouter()
const deciceInfo = ref({
  productId: '',
  productName: '',
  devcode: '',
  tagNumber: '',
  watchObject: '',
  installDate: '',
})

// 产品相关
const showProduct = ref(false)
const productValue = ref([])
const productColumns = ref([])
const onConfirm = ({ selectedValues, selectedOptions }) => {
  deciceInfo.value.productId = selectedOptions[0]?.value
  deciceInfo.value.productName = selectedOptions[0]?.text
  productValue.value = selectedValues
  showProduct.value = false
}
// 安装位置 -- 闸井/场站
const searchForWell = ref(false)
const searchForInput = ref('')
const resultForWell = ref(false)
// 搜索安装位置
const searchTagNumber = (action: string) => {
  if (!action) {
    return true
  }
  showLoadingToast({
    duration: 0,
    message: '加载中...',
    forbidClick: true,
    loadingType: 'spinner',
  });
  // 搜索场站或闸井
  (deciceInfo.value.watchObject === '1' ? getWellListPage : getStationListPage)({ offset: 1, limit: 1, tagNumber: searchForInput.value }).then(res => {
    closeToast()
    searchForWell.value = false
    let message = ''
    if (!res.data.rows.length) {
      message = `未找到位号为 ${searchForInput.value} ${deciceInfo.value.watchObject === '1' ? '闸井' : '场站'} ,请确认位号后重新搜索`
    }
    else {
      // 判断位置
      // 存在同类设备
      // 正常
    }
    // 展示查询结果
    showConfirmDialog({
      title: '搜索位置',
      message: '123123123232121'
    })
      .then(() => {

      })
      .catch(() => {

      })
  })

}
// 选择安装位置
const selectTagNumber = () => {
  if (!deciceInfo.value.productId) {
    showToast('请先选择产品')
    return
  }
  //1闸井 2场站 3管线
  if (deciceInfo.value.watchObject == '1' || deciceInfo.value.watchObject == '2') {
    searchForWell.value = true
    searchForInput.value = ''
  }
  // else {

  // }
}
// 安装日期
const showDatePicker = ref(false)
const pickerValueInstallDate = ref<string[]>([])
// 默认日期
pickerValueInstallDate.value = dayjs().format('YYYY-MM-DD').split('-')
deciceInfo.value.installDate = pickerValueInstallDate.value.join('-')
const onConfirmInstallDate = ({ selectedValues }) => {
  deciceInfo.value.installDate = selectedValues.join('-')
  pickerValueInstallDate.value = selectedValues
  showDatePicker.value = false
}
// 现场照片
const photo = ref<string[]>([])
// 拍照
const takePictures = () => {
  if (deciceInfo.value.photo.length >= 3) {
    showToast('最多上传三张照片')
    return
  }
  // 调用摄像头
  const camera = document.getElementById('camera-photo')
  camera?.click()
}
const fileRef = ref() // 文件上传input,获取input的引用
const onFileChange = (event: any) => {
  // 原生上传
  if (event.target.files?.length !== 0) {
    const file = event.target.files[0]
    const fd = new FormData()
    fd.append('file', file)
    uploadApi(fd).then(res => {
      photo.value.push(res.data as string)
      fileRef.value.value = ''
    }).catch(() => {
      fileRef.value.value = ''
    })
    // const reader = new FileReader() // 实例化FileReader
    // reader.readAsDataURL(file)
    // 读取成功以后执行的方法
    // reader.onload = (e) => {
    //   deciceInfo.value.photo.push(e.target.result)
      // let img = new Image()
      // // base64
      // img.src = e.target.result
      // console.log(img.src, 'img.src')
      // img.onload = () => {
      //   imagetoCanvas(img) //Image 对象转变为一个 Canvas 类型对象,i为遍历的下标
      // }
    // }
  }
}
// 图片地址
const getPhotoUrl = computed(() => {
  return (url: string) => {
    return `${window.localStorage.getItem('url-bj-well')}/static/${url}`
  }
})
// 删除图片
const deletePhoto = (index: number) => {
  photo.value.splice(index, 1)
}
// 预览图片
const previewPhoto = (index: number) => {
  showImagePreview({
    images: photo.value,
    startPosition: index
  })
}
// 获取字典
const deviceTypeList = ref<any[]>([]) // 设备类型列表
const fetchDict = () => {
  getProductListPage({ offset: 1, limit: 9999 }).then(res => {
    productColumns.value = res.data.rows.map((item: any) => ({
      text: `${item.productName}-${item.productCode}`,
      value: item.id,
      deviceType: item.deviceType,
    }))
  })
  getDeviceTypeListPage({ limit: 9999, offset: 1 }).then((res) => {
    deviceTypeList.value = res.data.rows
  })
}
fetchDict()
// 监听产品变化,判断该设备的 监测对象
watch(() => deciceInfo.value.productId, (newVal) => {
  if (newVal) {
    const select = productColumns.value.filter((item: any) => item.value === newVal) as any
    const watchObject = deviceTypeList.value.filter((item: any) => item.id === select[0].deviceType)
    deciceInfo.value.watchObject = watchObject[0].watchObject
  }
  else {
    deciceInfo.value.tagNumber = ''
    deciceInfo.value.watchObject = ''
  }
})


// 计算地图区域高度
const scrollHeight = ref(0)
const calcHeight = () => {
  // 公共头部高度40
  // 边距安全 30
  // 底部按钮
  const exportBtnHeight = document.getElementById('handler-btn')?.offsetHeight || 0
  // 头部
  const searchHeaderHeight = document.getElementById('info-area')?.offsetHeight || 0
  scrollHeight.value = window.innerHeight - 40 - exportBtnHeight - searchHeaderHeight - 30
}
onMounted(() => {
  calcHeight()
})

window.addEventListener('resize', () => {
  calcHeight()
})
onBeforeUnmount(() => {
  window.addEventListener('resize', () => { })
})
// 地图操作
const mapRef = ref()
// 当前状态  收起retract/展开expand
const mapStatus = ref('expand')
const changeStatus = () => {
  if (mapStatus.value === 'expand') {
    mapStatus.value = 'retract'
  }
  else {
    mapStatus.value = 'expand'
  }

}
// 重置地图到初始状态
const resetMap = () => {
  // mapRef.value.map.setCenter(position.value)
  // mapRef.value.map.setZoom(17.5)
}

// 查看数据
const deviceData = () => {
  if (!deciceInfo.value.devcode) {
    showToast('设备编号不能为空')
    return
  }
  $router.push({
    name: 'OperationData',
    query: {
      devcode: deciceInfo.value.devcode
    }
  })
}
// 页面缓存
onBeforeRouteLeave((to: any) => {
  keepSearchParams(to.path, 'H5DeviceAdd')
})
</script>

<template>
  <div class="device-container">
    <!-- 设备信息 -->
    <div id="info-area" class="device-info">
      <span class="title">设备信息</span>
      <van-form>
        <van-cell-group>
          <!-- 产品 -->
          <van-field v-model="deciceInfo.productName" is-link readonly label="产品" name="productId" placeholder="选择产品"
            required @click="showProduct = true" input-align="right">
          </van-field>
          <van-popup v-model:show="showProduct" destroy-on-close position="bottom">
            <van-picker :columns="productColumns" title="产品" :model-value="productValue" @confirm="onConfirm"
              @cancel="showProduct = false" />
          </van-popup>
          <!-- 设备编号 -->
          <van-field v-model="deciceInfo.devcode" label="设备编号" name="devcode" placeholder="输入设备编号" required
            input-align="right" />
          <!-- 安装位置 -->
          <van-field v-model="deciceInfo.tagNumber" is-link readonly label="安装位置" name="tagNumber" placeholder="去搜索"
            required @click="selectTagNumber" input-align="right" />
          <!-- 安装位置  闸井/场站查询-->
          <van-dialog v-model:show="searchForWell" title="搜索位置" confirm-button-text="搜索" :closeOnClickOverlay="true"
            :before-close="searchTagNumber">
            <van-field v-model="searchForInput" placeholder="请输入安装位号" />
          </van-dialog>
          <!-- 安装日期 -->
          <van-field v-model="deciceInfo.installDate" is-link readonly name="installDate" label="安装日期"
            placeholder="点击选择时间" @click="showDatePicker = true" required input-align="right" />
          <van-popup v-model:show="showDatePicker" destroy-on-close position="bottom">
            <van-date-picker :model-value="pickerValueInstallDate" @confirm="onConfirmInstallDate"
              @cancel="showDatePicker = false" />
          </van-popup>
          <!-- 现场照片 -->
          <van-field readonly name="photo" label="现场照片" required input-align="center">
            <template #input>
              <!-- 展示照片 -->
              <div v-for="(item, index) in photo" :key="index" class="show-photo">
                <div class="del_d">
                  <div class="del" @click="deletePhoto(index)"></div>
                </div>
                <img :src="getPhotoUrl(item)" alt="" srcset="" width="30px" height="30px" @click="previewPhoto(index)">
              </div>
            </template>
            <template #right-icon>
              <div class="camera" @click="takePictures" />
            </template>
          </van-field>

          <!-- 照相组件 -->
          <input ref="fileRef" style="display: none;opacity: 0;" multiple id="camera-photo" type="file" accept="image/*"
            @change="onFileChange">
        </van-cell-group>
      </van-form>
    </div>
    <!-- 地图组件 -->
    <div class="map" :class="mapStatus === 'retract' ? 'retract1' : ''"
      :style="{ width: '96%', margin: '0 auto', height: scrollHeight + 'px', marginTop: '5px', borderRadius: '10px', overflow: 'hidden' }">
      <a-map ref="mapRef" :class="mapStatus === 'retract' ? 'retract2' : ''" style="width: 100%;height: 100%;"
        :zoom="15" />
      <!-- 重置按钮 -->
      <div v-if="mapStatus === 'expand'" class="reset-icon" @click="resetMap">
        <div class="icon"></div>
      </div>
      <!-- 收起/展开按钮 -->
      <div class="expand-icon" @click="changeStatus">
        <div v-if="mapStatus === 'expand'" class="icon1"></div>
        <div v-if="mapStatus === 'retract'" class="icon2"></div>
      </div>
      <!-- 遮罩 -->
      <div v-if="mapStatus === 'retract'" class="mask"></div>
    </div>
    <!-- 按钮 -->
    <div id="handler-btn" class="btn-container">
      <el-button type="primary" style="width: 48%;" @click="save">保存</el-button>
      <el-button type="primary" plain style="width: 48%;" @click="deviceData">查看设备数据</el-button>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.show-photo {
  position: relative;
  margin-left: 10px;
}

.del_d {
  position: absolute;
  width: 16px;
  height: 16px;
  background: red;
  border-radius: 50%;
  top: -10px;
  right: -10px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;

  .del {
    width: 10px;
    height: 3px;
    background: white;
  }
}

$primary: #0D76D4;
$--van-primary-color: #0D76D4;

::v-deep(.van-picker-column__item--selected) {
  color: $primary !important;
}

.device-container {
  width: 100%;
  height: calc(100vh - 40px);
  overflow: hidden;

  .device-info {
    background-color: #fff;
    width: 96%;
    margin: 0 auto;
    margin-top: 1vh;
    border-radius: 6px;
    padding: 4px;

    .title {
      font-weight: 700;
      font-size: 1.2rem;
      padding-left: 0.5rem;
      margin-top: 0.5rem;
    }

    ::v-deep(.van-cell__title) {
      font-weight: 700;
      font-size: 1rem;
    }

    ::v-deep(.van-cell__value) {
      // font-weight: 700;
      font-size: 1rem;
    }
  }
}

.camera {
  width: 24px;
  height: 24px;
  background: url('@/assets/icons/icon-camera.svg') no-repeat center center / cover;
}

.btn-container {
  position: absolute;
  width: 96%;
  bottom: 1vh;
  display: flex;
  justify-content: space-around;
  // margin: 0 auto;
  left: 50%;
  transform: translateX(-50%);

  ::v-deep(.el-button) {
    font-size: 18px;
  }
}

.map {
  position: relative;

  .mask {
    width: 100px !important;
    height: 100px !important;
    position: absolute;
    z-index: 1;
    top: 0;
    left: 0;
  }

  .reset-icon {
    width: 40px;
    height: 40px;
    position: absolute;
    z-index: 2;
    bottom: 10px;
    right: 16px;
    border-radius: 6px;
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
    background-color: #fff;

    .icon {
      width: 30px;
      height: 30px;
      background: url('@/assets/icons/icon-location_current.svg') no-repeat center center / cover;
    }
  }

  .expand-icon {
    width: 40px;
    height: 40px;
    position: absolute;
    top: 10px;
    right: 16px;
    border-radius: 6px;
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
    background-color: #fff;
    z-index: 2;

    .icon1 {
      width: 30px;
      height: 30px;
      background: url('@/assets/mobile/retract.svg') no-repeat center center / cover;
    }

    .icon2 {
      width: 30px;
      height: 30px;
      background: url('@/assets/mobile/expand.svg') no-repeat center center / cover;
    }
  }

}

.retract1 {
  width: 100px !important;
  height: 100px !important;
  overflow: hidden;
  position: absolute;
  right: 0;
  bottom: 50px;
}

.retract2 {
  width: 100px !important;
  height: 100px !important;
  overflow: hidden;
  opacity: 0.5;
}
</style>