<!-- 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 { getSyncListPage } from '@/api/home/ledger/location' // import { showLoadingToast, closeToast } from 'vant' import { getDeviceListPage } from '@/api/home/device/device' 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' import { getDeptTreeList } from '@/api/system/dept' import { getTypeListByWellId } from '@/api/home/well/well' import useUserStore from '@/store/modules/user' import { findParentPids, toTreeList, findParentPids1 } from '@/utils/structure' import { addDeviceInstall } from '@/api/mobile/operation' import { addPosition, editPosition, getPositionListPage } from '@/api/home/device/device' import { getSyncListPage } from '@/api/home/ledger/location' import { addDevice, editDevice } from '@/api/mobile/device' const userInfo = useUserStore() const $router = useRouter() const deviceInfo = ref({ productId: '', productName: '', devcode: '', tagNumber: '', watchObject: '', installDate: '', tagName: '', typeName: '', photo1: '', photo2: '', photo3: '', deptid: '', deptName: '', position: '', userName: '', coordinate: '', lng: '', lat: '', ledgerId: '', ledgerIds: [], pipeCode: '', }) const mapRef = ref() const mapCenter = ref([116.397428, 39.90923]) deviceInfo.value.coordinate = '116.397428, 39.90923' deviceInfo.value.lng = '116.397428' deviceInfo.value.lat = '39.90923' deviceInfo.value.userName = userInfo.name // 产品相关 const showProduct = ref(false) const productValue = ref([]) const productColumns = ref([]) const onConfirm = ({ selectedValues, selectedOptions }) => { deviceInfo.value.productId = selectedOptions[0]?.value deviceInfo.value.productName = selectedOptions[0]?.text deviceInfo.value.typeName = selectedOptions[0]?.deviceTypeName productValue.value = selectedValues showProduct.value = false } // 验证设备编号是否存在 const valiateDevcode = () => { // if (!deviceInfo.value.devcode) { // const flag = document.getElementById('tag-flag') // if (flag) { // flag.style.top = '120px' // } // return // } // const flag = document.getElementById('tag-flag') // if (flag) { // flag.style.top = '99px' // } // 查询系统中是否有该设备 // getDeviceListPage({ devCode: deviceInfo.value.devcode, offset: '1', limit: '1' }).then(res => { // if (res.data.rows.length) { // deviceInfo.value.devcode = '' // showToast('该设备编号已存在,请重新输入') // } // }) } // 安装位置 -- 闸井/场站 const addType = ref('新建') // 新建/ 既有 const changeAddType = () => { if (addType.value === '新建') { addType.value = '既有' } else { addType.value = '新建' } // 清空 安装位置 闸井名称 详细位置 管理单位 deviceInfo.value.deptName = '' deviceInfo.value.deptid = '' deviceInfo.value.tagNumber = '' deviceInfo.value.tagName = '' deviceInfo.value.coordinate = '' deviceInfo.value.ledgerId = '' deviceInfo.value.ledgerIds = [] } const searchForWell = ref(false) const searchForInput = ref('') const resultForWell = ref(false) // 多个安装位置 const showmultipleResult = ref(false) // 选择弹窗 const checkedResult = ref('') const multipleResultList = ref([]) const cancelMultipleResult = () => { searchForWell.value = true } const confirmMultipleResult = () => { // 获取选中的 const result = multipleResultList.value.filter((item: any) => item.value === checkedResult.value)[0] as any showLoadingToast({ duration: 0, message: '加载中...', forbidClick: true, loadingType: 'spinner', }) // 判断当前闸井下是否含有同类设备 getTypeListByWellId({ id: result.id }).then(res => { closeToast() // 获取当前产品的设备类型 if (res.data.includes(deviceInfo.value.typeName)) { // 已有设备类型 showConfirmDialog({ title: '搜索位置', message: `位号为 ${result.tagNumber} 闸井中已存在在用的同类设备,无法保存。请重新选择或与系统管理员确认解除原绑定关系。` }) .then(() => { searchForWell.value = true }) .catch(() => { searchForWell.value = true }) } else { showConfirmDialog({ title: '搜索位置', message: `已找到位号为 ${result.tagNumber} 的${deviceInfo.value.watchObject === '1' ? '闸井' : '场站'}, 名称为${result.ledgerName},管理单位为${result.deptName},详细位置为${result.position}` }).then(() => { // 将选中的信息填充 deviceInfo.value.tagNumber = result.tagNumber deviceInfo.value.tagName = result.ledgerName deviceInfo.value.position = result.position deviceInfo.value.deptid = result.deptid deviceInfo.value.deptName = result.deptName deviceInfo.value.lng = result.lngGaode deviceInfo.value.lat = result.latGaode deviceInfo.value.ledgerId = result.id deviceInfo.value.ledgerIds = [result.id] // deviceInfo.value.coordinate = `${result.lngGaode},${result.latGaode}` // TODO: 设置地图位置 if (!result.lngGaode || !result.latGaode) { showToast('位置信息无效,请联系管理员') mapCenter.value = [116.397428, 39.90923] } else { deviceInfo.value.lng = result.lngGaode deviceInfo.value.lat = result.latGaode deviceInfo.value.coordinate = `${result.lngGaode},${result.latGaode}` // TODO: 设置地图位置 mapRef.value.removeMarker() mapRef.value.map.setCenter([result.lngGaode, result.latGaode]) mapRef.value.map.setZoom(16) mapRef.value.addMarker({ position: [result.lngGaode, result.latGaode], content: '', label: '', }) mapCenter.value = [result.lngGaode, result.latGaode] } // 清空多选和多选结果 showmultipleResult.value = false checkedResult.value = '' multipleResultList.value = [] // 设置管理单位组件默认选中状态 const deptName = allDeptList.value.filter(item => item.id === result.deptid)[0].name deviceInfo.value.deptName = deptName // 找到所有父级管理单位 let ParentPids = findParentPids1(allDeptList.value.filter(item => item.id !== '0'), deviceInfo.value.deptid) if (ParentPids.length) { ParentPids = ParentPids.reverse() // console.log(ParentPids, 'ParentPids') ParentPids.push(result.deptid) const dict = { 0: pickerGroupDept, 1: pickerUnitDept, 2: pickerDivisionDept, 3: pickerTeamDept, 4: pickerAreaDept } as { [key: string]: any } const listDict = { 0: groupDeptList, 1: unitDeptList, 2: divisionDeptList, 3: teamDeptList, 4: areaDeptList } as { [key: string]: any } ParentPids.forEach((item, index) => { dict[index].value = [item] if (index !== 0) { listDict[index].value = allDeptList.value.filter(item => item.pid === ParentPids[index - 1]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) } }) } deptTabs.value = ['集团', '单位', '部门', '班组', '片区'].slice(0, ParentPids.length) deptActiveTab.value = deptTabs.value.length - 1 onConfirmDept( ParentPids.map((item, index) => ({ selectedIndexes: [index], selectedValues: [item], selectedOptions: allDeptList.value.filter((citem) => citem.id === item).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) })) ) }) .catch(() => { showmultipleResult.value = true }) } }).catch(() => { closeToast() showmultipleResult.value = true }) } const valiateMultipleResult = (action: string) => { // console.log(action, 'action') if (action === 'cancel') { return true } else { if (checkedResult.value) { return true } else { return false } } } // 搜索安装位置 const searchTagNumber = (action: string) => { if (!action) { return true } showLoadingToast({ duration: 0, message: '加载中...', forbidClick: true, loadingType: 'spinner', }); const requestFunction = (watchObject: string, data: Object) => { return (watchObject === '1' ? getWellListPage : watchObject === '2' ? getStationListPage : getPositionListPage)(data) // 1: getWellListPage, // 2: getStationListPage, // 3: getPositionListPage } // 搜索场站或闸井 // (deviceInfo.value.watchObject === '1' ? getWellListPage : getStationListPage)({ offset: 1, limit: 10, tagNumber: searchForInput.value }) requestFunction(deviceInfo.value.watchObject, { offset: 1, limit: 10, tagNumber: searchForInput.value }).then(res => { closeToast() searchForWell.value = false if (!res.data.rows.length) { // 未找到 showConfirmDialog({ title: '搜索位置', message: `未找到位号为 ${searchForInput.value} ${deviceInfo.value.watchObject === '1' ? '闸井' : deviceInfo.value.watchObject === '2' ? '场站' : '位置'} ,请确认位号后重新搜索` }) .then(() => { searchForWell.value = true }) .catch(() => { searchForWell.value = true }) } else { if (res.data.rows.some((item: any) => item.tagNumber === searchForInput.value)) { const data = res.data.rows.filter((item: any) => item.tagNumber === searchForInput.value) if (data.length > 1) { // 让用户选择 showmultipleResult.value = true // 闸井 场站 // if (deviceInfo.value.watchObject === '1' || deviceInfo.value.watchObject === '2') { multipleResultList.value = data.map((item: any) => ({ ...item, value: item.id, name: `${item.tagNumber}-${item.ledgerName}` })) // } // 场站 // else if () { // multipleResultList.value = data.map((item: any) => ({ // ...item, // value: item.id, // name: `${item.tagNumber}-${item.ledgerName}` // })) // } } else { const result = data[0] showLoadingToast({ duration: 0, message: '加载中...', forbidClick: true, loadingType: 'spinner', }) if (deviceInfo.value.watchObject === '1') { // 判断是否存在同类设备 getTypeListByWellId({ id: result.id }).then(res => { closeToast() // 获取当前产品的设备类型 if (res.data.includes(deviceInfo.value.typeName)) { // 已有设备类型 showConfirmDialog({ title: '搜索位置', message: `位号为 ${result.tagNumber} 闸井中已存在在用的同类设备,无法保存。请重新选择或与系统管理员确认解除原绑定关系。` }) .then(() => { searchForWell.value = true }) .catch(() => { searchForWell.value = true }) } else { showConfirmDialog({ title: '搜索位置', message: `已找到位号为 ${result.tagNumber} 的${deviceInfo.value.watchObject === '1' ? '闸井' : '场站'}, 名称为${result.ledgerName},管理单位为${result.deptName},详细位置为${result.position}` }).then(() => { // 将选中的信息填充 deviceInfo.value.tagNumber = result.tagNumber deviceInfo.value.tagName = result.ledgerName deviceInfo.value.position = result.position deviceInfo.value.deptid = result.deptid deviceInfo.value.deptName = result.deptName deviceInfo.value.ledgerId = result.id deviceInfo.value.ledgerIds = [result.id] if (!result.lngGaode || !result.latGaode) { showToast('位置信息无效,请联系管理员') mapCenter.value = [116.397428, 39.90923] } else { deviceInfo.value.lng = result.lngGaode deviceInfo.value.lat = result.latGaode deviceInfo.value.coordinate = `${result.lngGaode},${result.latGaode}` // TODO: 设置地图位置 mapRef.value.removeMarker() mapRef.value.map.setCenter([result.lngGaode, result.latGaode]) mapRef.value.map.setZoom(16) mapRef.value.addMarker({ position: [result.lngGaode, result.latGaode], content: '', label: '', }) mapCenter.value = [result.lngGaode, result.latGaode] } // 设置管理单位组件默认选中状态 const deptName = allDeptList.value.filter(item => item.id === result.deptid)[0].name deviceInfo.value.deptName = deptName // 找到所有父级管理单位 let ParentPids = findParentPids1(allDeptList.value.filter(item => item.id !== '0'), deviceInfo.value.deptid) if (ParentPids.length) { ParentPids = ParentPids.reverse() // console.log(ParentPids, 'ParentPids') ParentPids.push(result.deptid) const dict = { 0: pickerGroupDept, 1: pickerUnitDept, 2: pickerDivisionDept, 3: pickerTeamDept, 4: pickerAreaDept } as { [key: string]: any } const listDict = { 0: groupDeptList, 1: unitDeptList, 2: divisionDeptList, 3: teamDeptList, 4: areaDeptList } as { [key: string]: any } ParentPids.forEach((item, index) => { dict[index].value = [item] if (index !== 0) { listDict[index].value = allDeptList.value.filter(item => item.pid === ParentPids[index - 1]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) } }) } deptTabs.value = ['集团', '单位', '部门', '班组', '片区'].slice(0, ParentPids.length) deptActiveTab.value = deptTabs.value.length - 1 onConfirmDept( ParentPids.map((item, index) => ({ selectedIndexes: [index], selectedValues: [item], selectedOptions: allDeptList.value.filter((citem) => citem.id === item).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) })) ) }) .catch(() => { // showmultipleResult.value = true searchForWell.value = true }) } }).catch(() => { closeToast() searchForWell.value = true }) } else if (deviceInfo.value.watchObject === '2' || deviceInfo.value.watchObject === '3') { closeToast() showConfirmDialog({ title: '搜索位置', message: `已找到位号为 ${result.tagNumber} 的${deviceInfo.value.watchObject === '2' ? '场站' : '位置'}, 名称为${result.ledgerName},管理单位为${result.deptName},详细位置为${result.position}` }).then(() => { // 将选中的信息填充 deviceInfo.value.tagNumber = result.tagNumber deviceInfo.value.tagName = result.ledgerName deviceInfo.value.position = result.position deviceInfo.value.deptid = result.deptid deviceInfo.value.deptName = result.deptName deviceInfo.value.ledgerId = result.id deviceInfo.value.ledgerIds = [result.id] if (deviceInfo.value.watchObject === '3') { deviceInfo.value.pipeCode = result.pipeCode } if (!result.lngGaode || !result.latGaode) { showToast('位置信息无效,请联系管理员') mapCenter.value = [116.397428, 39.90923] } else { deviceInfo.value.lng = result.lngGaode deviceInfo.value.lat = result.latGaode deviceInfo.value.coordinate = `${result.lngGaode},${result.latGaode}` // TODO: 设置地图位置 mapRef.value.removeMarker() mapRef.value.map.setCenter([result.lngGaode, result.latGaode]) mapRef.value.map.setZoom(16) mapRef.value.addMarker({ position: [result.lngGaode, result.latGaode], content: '', label: '', }) mapCenter.value = [result.lngGaode, result.latGaode] } searchForWell.value = false // 设置管理单位组件默认选中状态 const deptName = allDeptList.value.filter(item => item.id === result.deptid)[0].name deviceInfo.value.deptName = deptName // 找到所有父级管理单位 let ParentPids = findParentPids1(allDeptList.value.filter(item => item.id !== '0'), deviceInfo.value.deptid) if (ParentPids.length) { ParentPids = ParentPids.reverse() // console.log(ParentPids, 'ParentPids') ParentPids.push(result.deptid) const dict = { 0: pickerGroupDept, 1: pickerUnitDept, 2: pickerDivisionDept, 3: pickerTeamDept, 4: pickerAreaDept } as { [key: string]: any } const listDict = { 0: groupDeptList, 1: unitDeptList, 2: divisionDeptList, 3: teamDeptList, 4: areaDeptList } as { [key: string]: any } ParentPids.forEach((item, index) => { dict[index].value = [item] if (index !== 0) { listDict[index].value = allDeptList.value.filter(item => item.pid === ParentPids[index - 1]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) } }) } deptTabs.value = ['集团', '单位', '部门', '班组', '片区'].slice(0, ParentPids.length) deptActiveTab.value = deptTabs.value.length - 1 onConfirmDept( ParentPids.map((item, index) => ({ selectedIndexes: [index], selectedValues: [item], selectedOptions: allDeptList.value.filter((citem) => citem.id === item).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) })) ) }) .catch(() => { // showmultipleResult.value = true searchForWell.value = true }) } } } else { showConfirmDialog({ title: '搜索位置', message: `未找到位号为 ${searchForInput.value} ${deviceInfo.value.watchObject === '1' ? '闸井' : deviceInfo.value.watchObject === '2' ? '场站' : '位置'} ,请确认位号后重新搜索` }) .then(() => { searchForWell.value = true }) .catch(() => { searchForWell.value = true }) } } }) } // 选择安装位置 const selectTagNumber = (event: any) => { // console.log(event.target.classList, 'event') if(event.target.innerText === '既有' || (Array(event.target.classList || [])).includes('el-tag')) { return } if (!deviceInfo.value.productId) { showToast('请先选择产品') return } //1闸井 2场站 3管线 // if (deviceInfo.value.watchObject == '1' || deviceInfo.value.watchObject == '2') { searchForWell.value = true searchForInput.value = '' // } } // 安装日期 const showDatePicker = ref(false) const pickerValueInstallDate = ref<string[]>([]) // 默认日期 pickerValueInstallDate.value = dayjs().format('YYYY-MM-DD').split('-') deviceInfo.value.installDate = pickerValueInstallDate.value.join('-') const onConfirmInstallDate = ({ selectedValues }) => { deviceInfo.value.installDate = selectedValues.join('-') pickerValueInstallDate.value = selectedValues showDatePicker.value = false } // 管理单位 const showDept = ref(false) const deptActiveTab = ref(0) const deptTabs = ref<string[]>(['集团']) const loadingDept = ref(false) const allDeptList = ref<{ name: string; id: string; pid: string }[]>([]) // 管理单位 const groupDeptList = ref<{ text: string; value: string; pValue: string }[]>([]) // 集团 const unitDeptList = ref<{ text: string; value: string; pValue: string }[]>([]) // 单位 const divisionDeptList = ref<{ text: string; value: string; pValue: string }[]>([]) // 部门 const teamDeptList = ref<{ text: string; value: string; pValue: string }[]>([]) // 班组 const areaDeptList = ref<{ text: string; value: string; pValue: string }[]>([]) // 片区 // 选择集团 const pickerGroupDept = ref<string[]>([]) // 选中的集团 const pickerUnitDept = ref<string[]>([]) // 选中的单位 const pickerDivisionDept = ref<string[]>([]) // 选中的部门 const pickerTeamDept = ref<string[]>([]) // 选中的班组 const pickerAreaDept = ref<string[]>([]) // 选中的片区 // 集团选项变化 const changeGroupDept = ({ selectedValues, selectedOptions }: any) => { // 清空 单位 部门 班组 unitDeptList.value = [] divisionDeptList.value = [] teamDeptList.value = [] areaDeptList.value = [] pickerUnitDept.value = [] pickerDivisionDept.value = [] pickerTeamDept.value = [] pickerAreaDept.value = [] if (!selectedOptions[0].text.includes('全部')) { // 填充单位 unitDeptList.value = allDeptList.value.filter(item => item.pid === selectedValues[0]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) unitDeptList.value.unshift({ text: '全部', value: selectedOptions[0].value, pValue: selectedOptions[0].pValue }) pickerUnitDept.value = [selectedOptions[0].value as string] deptTabs.value = ['集团', '单位'] } else { deptTabs.value = ['集团'] } } // 点击集团直接确定选项 const clickGroupDept = ({ selectedValues, selectedOptions }: any) => { if (!selectedOptions[0].text.includes('全部')) { changeGroupDept({ selectedValues, selectedOptions }) deptTabs.value = ['集团', '单位'] setTimeout(() => { deptActiveTab.value = 1 }, 300) } else { deptTabs.value = ['集团'] } } // 单位选项变化 const changeUnitDept = ({ selectedValues, selectedOptions }: any) => { // 清空 部门 班组 divisionDeptList.value = [] teamDeptList.value = [] areaDeptList.value = [] pickerDivisionDept.value = [] pickerTeamDept.value = [] pickerAreaDept.value = [] if (!selectedOptions[0].text.includes('全部')) { // 填充 部门 divisionDeptList.value = allDeptList.value.filter(item => item.pid === selectedValues[0]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) divisionDeptList.value.unshift({ text: '全部', value: selectedOptions[0].value, pValue: selectedOptions[0].pValue }) pickerDivisionDept.value = [selectedOptions[0].value as string] deptTabs.value = ['集团', '单位', '部门'] } else { deptTabs.value = ['集团', '单位'] } } // 点击单位直接确定选项 const clickUnitDept = ({ selectedValues, selectedOptions }: any) => { if (selectedOptions[0].text.includes('全部')) { deptTabs.value = ['集团', '单位'] // showDept.value = false // 确定 // searchQuery.value.deptid = selectedOptions[0].value // searchQueryForNames.value.deptName = allDeptList.value.filter(item => item.id === selectedOptions[0].value)[0].name } else { changeUnitDept({ selectedValues, selectedOptions }) deptTabs.value = ['集团', '单位', '部门'] setTimeout(() => { deptActiveTab.value = 2 }, 300) } } // 部门选项变化 const changeDivisionDept = ({ selectedValues, selectedOptions }: any) => { // 清空 班组 teamDeptList.value = [] areaDeptList.value = [] pickerTeamDept.value = [] pickerAreaDept.value = [] if (!selectedOptions[0].text.includes('全部')) { // 填充 班组 teamDeptList.value = allDeptList.value.filter(item => item.pid === selectedValues[0]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) teamDeptList.value.unshift({ text: '全部', value: selectedOptions[0].value, pValue: selectedOptions[0].pValue }) pickerTeamDept.value = [selectedOptions[0].value as string] deptTabs.value = ['集团', '单位', '部门', '班组'] } else { deptTabs.value = ['集团', '单位', '部门'] } } // 点击部门直接确定选项 const clickDivisionDept = ({ selectedValues, selectedOptions }: any) => { if (selectedOptions[0].text.includes('全部')) { deptTabs.value = ['集团', '单位', '部门'] } else { changeDivisionDept({ selectedValues, selectedOptions }) deptTabs.value = ['集团', '单位', '部门', '班组'] setTimeout(() => { deptActiveTab.value = 3 }, 300) } } // 班组选项变化 const changeTeamDept = ({ selectedValues, selectedOptions }: any) => { areaDeptList.value = [] pickerAreaDept.value = [] if (!selectedOptions[0].text.includes('全部')) { // 填充 片区 areaDeptList.value = allDeptList.value.filter(item => item.pid === selectedValues[0]).map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) areaDeptList.value.unshift({ text: '全部', value: selectedOptions[0].value, pValue: selectedOptions[0].pValue }) pickerAreaDept.value = [selectedOptions[0].value as string] deptTabs.value = ['集团', '单位', '部门', '班组', '片区'] } else { deptTabs.value = ['集团', '单位', '部门', '班组'] } } // 点击班组 const clickTeamDept = ({ selectedValues, selectedOptions }: any) => { if (selectedOptions[0].text.includes('全部')) { deptTabs.value = ['集团', '单位', '部门', '班组'] } else { changeTeamDept({ selectedValues, selectedOptions }) deptTabs.value = ['集团', '单位', '部门', '班组', '片区'] setTimeout(() => { deptActiveTab.value = 4 }, 300) } } // 选择管理单位 const selectDept = () => { if (deviceInfo.value.watchObject === '2' || addType.value === '既有') { return } showDept.value = true } // 确认管理单位 const onConfirmDept = (data: any[]) => { const dict = { 0: pickerGroupDept, 1: pickerUnitDept, 2: pickerDivisionDept, 3: pickerTeamDept, 4: pickerAreaDept } as { [key: string]: any } data.forEach((item: any, index: number) => { dict[index].value = item.selectedValues }) deviceInfo.value.deptid = data[deptTabs.value.length - 1].selectedValues deviceInfo.value.deptName = allDeptList.value.filter(item => item.id === data[deptTabs.value.length - 1].selectedValues[0])[0].name showDept.value = false } // 现场照片 const photo = ref<string[]>([]) // 拍照 const takePictures = () => { if (photo.value.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) showLoadingToast({ duration: 0, message: '加载中...', forbidClick: true, loadingType: 'spinner', }) uploadApi(fd).then(res => { photo.value.push(res.data as string) fileRef.value.value = '' resizePage() closeToast() }).catch(() => { fileRef.value.value = '' closeToast() }) // const reader = new FileReader() // 实例化FileReader // reader.readAsDataURL(file) // 读取成功以后执行的方法 // reader.onload = (e) => { // deviceInfo.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) resizePage() } // 预览图片 const previewPhoto = (index: number) => { showImagePreview({ images: photo.value.map((item: string) => getPhotoUrl.value(item)), startPosition: index }) } // 获取字典 const deviceTypeList = ref<any[]>([]) // 设备类型列表 const loadingProduct = ref(true) const fetchDict = () => { getProductListPage({ offset: 1, limit: 9999 }).then(res => { productColumns.value = res.data.rows.filter((item: any) => userInfo.avatar.includes(item.manufacturerId)).map((item: any) => ({ text: `${item.productName}-${item.productCode}`, value: item.id, deviceType: item.deviceType, deviceTypeName: item.deviceTypeName, })) loadingProduct.value = false }) getDeviceTypeListPage({ limit: 9999, offset: 1 }).then((res) => { deviceTypeList.value = res.data.rows }) // 获取管理单位 loadingDept.value = true getDeptTreeList().then(res => { allDeptList.value = res.data groupDeptList.value = res.data.filter((item: { name: string; id: string; pid: string }) => item.pid === '0').map((item: { name: string; id: string; pid: string }) => ({ text: item.name, value: item.id, pValue: item.pid })) // groupDeptList.value.unshift({ text: '全部', value: '', pValue: '' }) loadingDept.value = false }).catch(() => { loadingDept.value = false }) } fetchDict() // 监听产品变化,判断该设备的 监测对象 watch(() => deviceInfo.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) deviceInfo.value.watchObject = watchObject[0].watchObject //1闸井 2场站 3管线 // console.log(deviceInfo.value.watchObject, '1闸井 2场站 3管线') if (deviceInfo.value.watchObject === '2') { addType.value = '既有' } else { addType.value = '新建' } } // else { deviceInfo.value.tagNumber = '' deviceInfo.value.tagName = '' deviceInfo.value.position = '' deviceInfo.value.ledgerId = '' deviceInfo.value.ledgerIds = [] // deviceInfo.value.watchObject = '' // } }) // 计算地图区域高度 const scrollHeight = ref(0) function 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() }) function resizePage() { setTimeout(() => { const resize = new Event('resize') window.dispatchEvent(resize) }) } onBeforeUnmount(() => { window.addEventListener('resize', () => { }) }) // 地图操作 const completeMap = () => { mapRef.value.map.setCenter(mapCenter.value) mapRef.value.map.setZoom(16) mapRef.value.addMarker({ position: mapCenter.value, content: '', label: '', }) // 地图移动 mapRef.value.map.on('moveend', () => { mapRef.value.removeMarker() mapRef.value.addMarker({ position: mapRef.value.map.getCenter(), content: '', label: '', }) mapCenter.value = [mapRef.value.map.getCenter().lng, mapRef.value.map.getCenter().lat] deviceInfo.value.coordinate = `${mapCenter.value[0]},${mapCenter.value[1]}` deviceInfo.value.lng = `${mapCenter.value[0]}` deviceInfo.value.lat = `${mapCenter.value[1]}` }) // 获取当前位置 mapRef.value.getLocation((a, b) => { // console.log('success', a, b) }, (a, b) => { // console.log('error', a, b) }) } // 当前状态 收起retract/展开expand const mapStatus = ref('expand') const changeStatus = () => { if (mapStatus.value === 'expand') { mapStatus.value = 'retract' } else { mapStatus.value = 'expand' } resizePage() } // 重置地图到初始状态 const resetMap = () => { mapRef.value.map.setCenter(mapCenter.value) mapRef.value.map.setZoom(16) } // 保存 const formRef = ref() const loading = ref(false) const save = () => { if (!photo.value.length) { showToast('请上传现场照片') return } if ((!deviceInfo.value.coordinate || !deviceInfo.value.lat || !deviceInfo.value.lng)) { if (addType.value === '新建') { showToast('请选择位置') return } showToast('位置信息无效,请联系管理员') return } formRef.value.validate(['productId', 'devcode', 'tagNumber', 'tagName', 'position', 'deptName', 'installDate']).then(async () => { loading.value = true // 判断设备是否存在 const response = await getDeviceListPage({ devCode: deviceInfo.value.devcode, offset: '1', limit: '1' }) if (response.data.rows.length && response.data.rows[0]?.validName === '在用') { showToast('设备已经存在系统中,并且状态为在用,不支持再次新装') loading.value = false return } else if (response.data.rows.length) { const data = response.data.rows[0] if (data.productId !== deviceInfo.value.productId || data.typeName !== deviceInfo.value.typeName) { showToast('该设备已经存在系统,并且产品或设备类型和当前设备不一致,请确认') loading.value = false return } } const add = () => { const data = { watchObject: deviceInfo.value.watchObject, typeName: deviceInfo.value.typeName, tagNumber: deviceInfo.value.tagNumber, tagName: deviceInfo.value.tagName, position: deviceInfo.value.position, lng: deviceInfo.value.lng, lat: deviceInfo.value.lat, installDate: deviceInfo.value.installDate, devcode: deviceInfo.value.devcode, deptid: deviceInfo.value.deptid[0], deptName: deviceInfo.value.deptName, productId: deviceInfo.value.productId, ledgerIds: deviceInfo.value.ledgerIds, ledgerId: deviceInfo.value.ledgerId, deviceType: deviceTypeList.value.filter((item: any) => item.typeName === deviceInfo.value.typeName)[0].id, photo1: '', photo2: '', photo3: '', } photo.value.forEach((item: any, index: number) => { data[`photo${index + 1}`] = item }); (response.data.rows.length ? editDevice : addDevice)({ ...data, valid: '1', id: response.data.rows.length ? response.data.rows[0].id : undefined }).then(res => { // console.log(res.data, '新增成功') // 添加运维记录 addDeviceInstall({ repairType: '1', repairTypeName: '新装', devcode: deviceInfo.value.devcode, ledgerNumber: deviceInfo.value.tagNumber, position: deviceInfo.value.position, repairTime: deviceInfo.value.installDate, repairPerson: deviceInfo.value.userName, repairContent: '新装设备', deptid: data.deptid, deviceType: data.deviceType, ledgerName: data.tagName, photo1: data.photo1, photo2: data.photo2, photo3: data.photo3, }).then(res => { showToast('新增成功') loading.value = false $router.push({ name: 'DeviceAddSuccess', query: { row: JSON.stringify(deviceInfo.value) } }) }) }) } // add() if (addType.value === '新建') { if (deviceInfo.value.watchObject === '1' || deviceInfo.value.watchObject === '3') { // 闸井 // 先查找是否含有该点位 (deviceInfo.value.watchObject === '1' ? getSyncListPage : getPositionListPage)({ tagNumber: deviceInfo.value.tagNumber, deptId: deviceInfo.value.deptid[0], offset: 1, limit: 1 }).then(res => { if (res.data.rows.length) { // 已经含有 showConfirmDialog({ title: '提示', message: `该点位已经存在,确认编辑该点位信息?` }) .then(() => { editPosition({ deptid: deviceInfo.value.deptid[0], latGaode: deviceInfo.value.lat, lngGaode: deviceInfo.value.lng, ledgerName: deviceInfo.value.tagName, position: deviceInfo.value.position, tagNumber: deviceInfo.value.tagNumber, id: res.data.rows[0].id, pipeCode: deviceInfo.value.pipeCode, type: deviceInfo.value.watchObject === '1' ? '1' : '3', }).then(() => { deviceInfo.value.ledgerId = res.data.rows[0].id deviceInfo.value.ledgerIds = [res.data.rows[0].id] add() }).catch(() => { loading.value = false }) }) .catch(() => { loading.value = false }) } else { // 没有该点位 addPosition({ deptid: deviceInfo.value.deptid[0], latGaode: deviceInfo.value.lat, lngGaode: deviceInfo.value.lng, ledgerName: deviceInfo.value.tagName, position: deviceInfo.value.position, tagNumber: deviceInfo.value.tagNumber, pipeCode: deviceInfo.value.pipeCode, type: deviceInfo.value.watchObject === '1' ? '1' : '3', }).then(res => { deviceInfo.value.ledgerId = res.data deviceInfo.value.ledgerIds = [res.data] add() }) } }) } } else { add() } }) } // 查看数据 const deviceData = () => { if (!deviceInfo.value.devcode) { showToast('设备编号不能为空') return } $router.push({ name: 'OperationData', query: { devcode: deviceInfo.value.devcode } }) } // 页面缓存 onBeforeRouteLeave((to: any) => { keepSearchParams(to.path, 'H5DeviceAdd') }) </script> <template> <div v-loading="loading" class="device-container"> <!-- 设备信息 --> <div id="info-area" class="device-info"> <span class="title">设备信息</span> <van-form ref="formRef"> <van-cell-group> <!-- 产品 --> <van-field v-model="deviceInfo.productName" is-link readonly label="产品" name="productId" placeholder="选择产品" required @click="showProduct = true" input-align="right" :rules="[{ required: true, message: '请选择产品' }]"> </van-field> <van-popup v-model:show="showProduct" destroy-on-close position="bottom"> <van-picker :columns="productColumns" :loading="loadingProduct" title="产品" :model-value="productValue" @confirm="onConfirm" @cancel="showProduct = false" /> </van-popup> <!-- 设备编号 --> <van-field v-model="deviceInfo.devcode" label="设备编号" name="devcode" placeholder="输入设备编号" required input-align="right" @blur="valiateDevcode" clearable :rules="[{ required: true, message: '输入设备编号' }]" /> <!-- 安装位置 --> <van-field v-if="addType === '既有'" v-model="deviceInfo.tagNumber" is-link readonly label="安装位置" name="tagNumber" placeholder="去搜索" required @click="(event) => selectTagNumber(event)" input-align="right" :rules="[{ required: true, message: '请选择安装位置' }]"> <!-- 新建/既有 --> <template #label> <span style="position: relative;"> 安装位置 <template v-if="deviceInfo.watchObject !== '2'"> <!-- <div id="tag-flag" v-if="addType === '新建'" style="position: absolute;top: 99px; left: 100px;z-index: 10;"> <el-tag type="success" @click="changeAddType">新建</el-tag> </div> --> <div id="tag-flag" v-if="addType === '既有'" style="position: absolute;top: -4px; right: -80%;z-index: 10;"> <el-tag type="primary" @click="changeAddType">既有</el-tag> </div> </template> </span> </template> </van-field> <van-dialog v-model:show="showmultipleResult" title="安装位置" show-cancel-button @cancel="cancelMultipleResult" @confirm="confirmMultipleResult" :before-close="valiateMultipleResult"> <van-radio-group v-model="checkedResult"> <van-radio class="radio" v-for="item in multipleResultList" :name="item.value">{{ item.name }}</van-radio> </van-radio-group> </van-dialog> <!-- 安装位置 闸井/场站查询--> <van-dialog v-if="addType === '既有'" v-model:show="searchForWell" title="搜索位置" confirm-button-text="搜索" :closeOnClickOverlay="true" :before-close="searchTagNumber"> <van-field v-model="searchForInput" placeholder="请输入安装位号" /> </van-dialog> <van-field v-if="addType === '新建'" v-model="deviceInfo.tagNumber" label="安装位置" name="devcode" placeholder="请输入安装位号" required input-align="right" :rules="[{ required: true, message: '请输入安装位置' }]"> <template #label> <span style="position: relative;"> 安装位置 <template v-if="deviceInfo.watchObject !== '2'"> <div id="tag-flag" v-if="addType === '新建'" style="position: absolute;top: -4px; right: -80%;z-index: 10;"> <el-tag type="success" @click="changeAddType">新建</el-tag> </div> <!-- <div id="tag-flag" v-if="addType === '既有'" style="position: absolute;top: 99px; left: 100px;z-index: 10;"> <el-tag type="primary" @click="changeAddType">既有</el-tag> </div> --> </template> </span> </template> </van-field> <!-- 名称 --> <van-field v-if="deviceInfo.watchObject !== '3'" v-model="deviceInfo.tagName" :label="deviceInfo.watchObject === '1' ? '闸井名称' : '场站名称'" name="tagName" :placeholder="deviceInfo.watchObject === '1' ? '闸井名称' : '场站名称'" required input-align="right" :rules="[{ required: true, message: `请输入${deviceInfo.watchObject === '1' ? '闸井' : '场站'}名称` }]" :readonly="deviceInfo.watchObject === '2' || addType === '既有'" /> <!-- 详细位置 --> <van-field v-model="deviceInfo.position" label="详细位置" name="position" placeholder="详细位置" required input-align="right" :rules="[{ required: true, message: '请输入详细位置' }]" :readonly="deviceInfo.watchObject === '2' || addType === '既有'" /> <!-- 关联管线 --> <van-field v-if="deviceInfo.watchObject === '3'" v-model="deviceInfo.pipeCode" label="关联管线" name="pipeCode" placeholder="关联管线" input-align="right" :rules="[{ required: true, message: '请输入关联管线' }]" :readonly="addType === '既有'" /> <!-- 管理单位 --> <van-popup v-model:show="showDept" destroy-on-close position="bottom"> <!-- 树形选择 --> <van-picker-group v-model:active-tab="deptActiveTab" title="管理单位" :tabs="deptTabs" @confirm="onConfirmDept" @cancel="showDept = false"> <!-- 集团 --> <van-picker v-show="deptTabs.includes('集团')" :loading="loadingDept" :swipe-duration="500" :columns="groupDeptList" :model-value="pickerGroupDept" @change="changeGroupDept" @click-option="clickGroupDept" /> <!-- 单位 --> <van-picker v-show="deptTabs.includes('单位')" :swipe-duration="500" :columns="unitDeptList" :model-value="pickerUnitDept" @change="changeUnitDept" @click-option="clickUnitDept" /> <!-- 部门 --> <van-picker v-show="deptTabs.includes('部门')" :swipe-duration="500" :columns="divisionDeptList" :model-value="pickerDivisionDept" @change="changeDivisionDept" @click-option="clickDivisionDept" /> <!-- 班组 --> <van-picker v-show="deptTabs.includes('班组')" :swipe-duration="500" :columns="teamDeptList" :model-value="pickerTeamDept" @change="changeTeamDept" @click-option="clickTeamDept" /> <!-- 片区 --> <van-picker v-show="deptTabs.includes('片区')" :swipe-duration="500" :columns="areaDeptList" :model-value="pickerAreaDept" /> </van-picker-group> </van-popup> <van-field v-model="deviceInfo.deptName" label="管理单位" name="position" placeholder="管理单位" required input-align="right" readonly is-link :rules="[{ required: true, message: '请选择管理单位' }]" @click="selectDept" /> <!-- 安装日期 --> <van-field v-model="deviceInfo.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-field v-if="mapStatus !== 'expand'" v-model="deviceInfo.coordinate" label="坐标" readonly name="position" placeholder="坐标" required input-align="right" /> <van-field v-if="mapStatus !== 'expand'" v-model="deviceInfo.userName" label="操作人" readonly name="position" placeholder="操作人" required input-align="right" /> </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%;" @complete="completeMap" :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" :disabled="loading" style="width: 48%;" @click="save">保存</el-button> <el-button type="primary" :disabled="loading" plain style="width: 48%;" @click="deviceData">查看设备数据</el-button> </div> </div> </template> <style lang="scss" scoped> .show-photo { position: relative; margin-left: 10px; } .radio { margin-left: 5px; margin-top: 3px; margin-bottom: 3px; } .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>