Newer
Older
smartwell_front / src / views / mobile / operation / index.vue
liyaguang on 26 Feb 12 KB 新装设备完成
<!--
  Description: 设备运维
  Author: 李亚光
  Date: 2024-01-03
 -->
<script lang="ts" setup name="H5DeviceOperation">
import { keepSearchParams } from '@/utils/keepQuery'
import dayjs from 'dayjs'
import { showToast, showImagePreview, showLoadingToast, closeToast } from 'vant'
import { getDictByCode } from '@/api/system/dict'
import { addDeviceInstall, getDeviceInstall, uploadApi } from '@/api/mobile/operation'
import useUserStore from '@/store/modules/user'
const $router = useRouter()
const userInfo = useUserStore()
const baseInfo = ref({
  repairType: '',
  repairTypeName: '',
  devcode: '',
  ledgerNumber: '',
  position: '',
  repairTime: '',
  repairPerson: '',
  repairContent: '',
  deptid: '',
  deviceType: '',
  ledgerName: '',
  photo: [] as string[]
})
baseInfo.value.repairPerson = userInfo.name
const disabledPosition = ref(true) // 是否禁用安装位置
const isRequiredPhoto = ref(true) // 是否必传照片
watch(() => baseInfo.value.repairTypeName, (newVal) => {
  disabledPosition.value = true
  isRequiredPhoto.value = true
  // 设备回装支持更改安装位置
  // 拆下返厂可不传现场照片
  if (newVal) {
    if (newVal.includes('回装')) {
      disabledPosition.value = false
    }
    else if (newVal.includes('返厂')) {
      isRequiredPhoto.value = false
    }
  }
}, {
  deep: true
})
// 运维类型
const showRepairType = ref(false)
const repairTypeValue = ref([])
const onConfirmRepairType = ({ selectedValues, selectedOptions }) => {
  baseInfo.value.repairType = selectedOptions[0]?.value
  baseInfo.value.repairTypeName = selectedOptions[0]?.text
  repairTypeValue.value = selectedValues
  showRepairType.value = false
}
// 根据设备编号查询设备信息
const searchDeviceInfo = () => {
  if (!baseInfo.value.devcode) {
    return
  }
  getDeviceInstall(baseInfo.value.devcode).then(res => {
    if (res.data) {
      baseInfo.value.ledgerNumber = res.data.tagNumber
      baseInfo.value.position = res.data.position
      baseInfo.value.deptid = res.data.deptid
      baseInfo.value.deviceType = res.data.devTypeId
      baseInfo.value.ledgerName = res.data.ledgerName
      if (!res.data.tagNumber || !res.data.position) {
        showToast('该设备缺少关键位置信息')
      }
    }
    else {
      baseInfo.value.ledgerNumber = ''
      baseInfo.value.position = ''
      showToast('未查询到设备信息,请检查设备编号是否正确')
    }
  })
}

// 运维日期
const showDatePicker = ref(false)
const pickerValueRepairDate = ref<string[]>([])
pickerValueRepairDate.value = dayjs().format('YYYY-MM-DD').split('-')
baseInfo.value.repairTime = pickerValueRepairDate.value.join('-')
const onConfirmRepairDate = ({ selectedValues }) => {
  baseInfo.value.repairTime = selectedValues.join('-')
  pickerValueRepairDate.value = selectedValues
  showDatePicker.value = false
}

// 现场照片
// const showCamera = ref(false)
// 拍照
const takePictures = () => {
  if (baseInfo.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()
    showLoadingToast({
      duration: 0,
      message: '加载中...',
      forbidClick: true,
      loadingType: 'spinner',
    })
    fd.append('file', file)
    uploadApi(fd).then(res => {
      baseInfo.value.photo.push(res.data as string)
      fileRef.value.value = ''
      closeToast()
    }).catch(() => {
      fileRef.value.value = ''
      closeToast()
    })

    // const reader = new FileReader() // 实例化FileReader
    // reader.readAsDataURL(file)
    // 读取成功以后执行的方法
    // reader.onload = (e) => {
    // formRef.value.resetValidation('photo')
    // let img = new Image()
    // // base64
    // img.src = e.target.result
    // console.log(img.src, 'img.src')
    // img.onload = () => {
    //   imagetoCanvas(img) //Image 对象转变为一个 Canvas 类型对象,i为遍历的下标
    // }
    // }
  }
}
// 删除图片
const deletePhoto = (index: number) => {
  baseInfo.value.photo.splice(index, 1)
}
// 图片地址
const getPhotoUrl = computed(() => {
  return (url: string) => {
    return `${window.localStorage.getItem('url-bj-well')}/static/${url}`
  }
})
// 预览图片
const previewPhoto = (index: number) => {
  showImagePreview({
    images: baseInfo.value.photo.map((item) => getPhotoUrl.value(item)),
    startPosition: index
  })
}

// 获取字典
const repairTypeColumns = ref<{ text: string; value: string }[]>([]) // 运维类型
const fetchDict = () => {
  getDictByCode('repairType').then(res => {
    repairTypeColumns.value = res.data.filter((item: { id: string; name: string; value: string }) => !item.name.includes('新装')).map((item: { id: string; name: string; value: string }) => ({ text: item.name, value: item.value }))
  })
}
fetchDict()

// 查看设备数据
const deviceData = () => {
  if (!baseInfo.value.devcode) {
    showToast('设备编号不能为空')
    return
  }
  $router.push({
    name: 'OperationData',
    query: {
      devcode: baseInfo.value.devcode
    }
  })
}
// 保存
const formRef = ref()
const loading = ref(false)
const save = () => {
  // 表单验证
  formRef.value.validate(['repairType', 'devcode', 'tagNumber', 'position', 'repairTime', 'repairPerson', 'repairContent']).then(() => {
    // 验证现场照片
    if (isRequiredPhoto.value && !baseInfo.value.photo.length) {
      showToast('请上传现场照片')
      return
    }
    loading.value = true
    const data = JSON.parse(JSON.stringify(baseInfo.value))
    // 将图片放在单个属性中
    if (data.photo.length) {
      data.photo.forEach((element: string, index: number) => {
        data[`photo${index + 1}`] = element
      })
    }
    // 清空图片数组
    data.photo = undefined
    addDeviceInstall(data).then(() => {
      loading.value = false
      $router.push({
        name: 'OperationDataSuccess',
        query: {
          row: JSON.stringify(baseInfo.value)
        }
      })
    }).catch(() => {
      loading.value = false
    })
  })

}
// 页面缓存
onBeforeRouteLeave((to: any) => {
  keepSearchParams(to.path, 'H5DeviceOperation')
})
onActivated(() => {
  if (!($router.options.history.state.forward as string || '').includes('operation/data')) {
    baseInfo.value = {
      repairType: '',
      repairTypeName: '',
      devcode: '',
      ledgerNumber: '',
      position: '',
      repairTime: '',
      repairPerson: '',
      repairContent: '',
      photo: [] as string[],
      deptid: '',
      deviceType: '',
      ledgerName: '',
    }
  }
})

</script>

<template>
  <div v-loading="loading" class="device-container">
    <!-- 设备信息 -->
    <div class="device-info">
      <van-form ref="formRef">
        <van-cell-group>
          <!-- 运维类型 -->
          <van-field v-model="baseInfo.repairTypeName" label="运维类型" is-link readonly name="repairType"
            placeholder="选择运维类型" required @click="showRepairType = true" input-align="right"
            :rules="[{ required: true, message: '请选择运维类型' }]" />
          <van-popup v-model:show="showRepairType" destroy-on-close position="bottom">
            <van-picker :columns="repairTypeColumns" title="运维类型" :model-value="repairTypeValue"
              @confirm="onConfirmRepairType" @cancel="showRepairType = false" />
          </van-popup>
          <!-- 设备编号 -->
          <van-field v-model="baseInfo.devcode" label="设备编号" name="devcode" placeholder="输入设备编号" required
            input-align="right" @blur="searchDeviceInfo" clearable :rules="[{ required: true, message: '请输入设备编号' }]" />
          <!-- 安装位置 -->
          <van-field v-model="baseInfo.ledgerNumber" :readonly="disabledPosition" label="安装位置" name="tagNumber"
            placeholder="安装位置" required input-align="right" :rules="[{ required: true, message: '请确认设备编号是否正确' }]" />
          <!-- 详细位置 -->
          <van-field v-model="baseInfo.position" :readonly="disabledPosition" label="详细位置" name="position"
            placeholder="详细位置" required input-align="right" :rules="[{ required: true, message: '请确认设备编号是否正确' }]" />
          <!-- 运维日期 -->
          <van-field v-model="baseInfo.repairTime" is-link label="运维日期" name="repairTime" required placeholder="选择运维日期"
            @click="showDatePicker = true" input-align="right" :rules="[{ required: true, message: '请选择运维日期' }]" />
          <van-popup v-model:show="showDatePicker" destroy-on-close position="bottom">
            <van-date-picker :model-value="pickerValueRepairDate" @confirm="onConfirmRepairDate"
              @cancel="showDatePicker = false" />
          </van-popup>
          <!-- 运维人员 -->
          <van-field v-model="baseInfo.repairPerson" label="运维人员" name="repairPerson" placeholder="输入运维人员" required
            input-align="right" clearable :rules="[{ required: true, message: '请输入运维人员' }]" />
          <!-- 运维内容 -->
          <van-field v-model="baseInfo.repairContent" label="运维内容" name="repairContent" placeholder="输入运维内容" required
            input-align="right" clearable :rules="[{ required: true, message: '请输入运维内容' }]" />
          <!-- 现场照片 -->
          <van-field readonly name="photo" label="现场照片" :required="isRequiredPhoto"
            :rules="[{ required: isRequiredPhoto, message: '请上传现场照片' }]" input-align="center">
            <template #input>
              <div v-for="(item, index) in baseInfo.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>
  <!-- 按钮 -->
  <div class="btn-container">
    <el-button type="primary" :disabled="loading" style="width: 48%;" @click="save">保存</el-button>
    <el-button type="primary" :disabled="loading" plain style="width: 48%;" @click="deviceData">查看设备数据</el-button>
  </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;
  position: relative;

  .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.1rem;
      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;
  }
}
</style>