| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- <template>
- <div>
- <el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
- <div class="form-section-title">基础信息</div>
- <el-row :gutter="16">
- <el-col :span="12">
- <el-form-item label="设备编码" prop="equipmentCode">
- <el-input v-model="form.equipmentCode" placeholder="请输入设备编码" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="设备名称" prop="equipmentName">
- <el-input v-model="form.equipmentName" placeholder="请输入设备名称" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="设备类型" prop="equipmentTypeId">
- <el-tree-select
- v-model="form.equipmentTypeId"
- :disabled="typeLocked"
- :data="types"
- node-key="id"
- :props="{ label: 'typeName', children: 'children', disabled: 'disabled' }"
- default-expand-all
- :render-after-expand="false"
- placeholder="请选择设备类型"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="所属片区" prop="district">
- <el-select v-model="form.district" placeholder="请选择所属片区" style="width: 100%">
- <el-option v-for="item in districtOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="设备型号" prop="equipmentModel">
- <el-input v-model="form.equipmentModel" placeholder="请输入设备型号" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="制造商" prop="manufacturer">
- <el-input v-model="form.manufacturer" placeholder="请输入制造商" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="生产日期" prop="productionDate">
- <el-date-picker v-model="form.productionDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择生产日期" style="width: 100%" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="规格参数" prop="equipmentSpec">
- <el-input v-model="form.equipmentSpec" placeholder="请输入设备规格参数" />
- </el-form-item>
- </el-col>
- </el-row>
- <div class="form-section-title">资产信息</div>
- <el-row :gutter="16">
- <el-col :span="12">
- <el-form-item label="资产状态" prop="currentStatus">
- <el-select v-model="form.currentStatus" placeholder="请选择资产状态" style="width: 100%">
- <el-option v-for="item in equipmentStatusOptions" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="资产价值(元)" prop="assetValue">
- <el-input-number v-model="form.assetValue" :precision="2" :step="100" style="width: 100%" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="使用年限(年)" prop="useLife">
- <el-input-number v-model="form.useLife" :precision="0" :step="1" style="width: 100%" />
- </el-form-item>
- </el-col>
- </el-row>
- <div class="form-section-title">部署运维</div>
- <el-row :gutter="16">
- <el-col :span="24">
- <el-form-item label="安装位置" prop="equipmentLocation">
- <el-input v-model="form.equipmentLocation" placeholder="请输入或通过地图选择安装位置" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="地图坐标">
- <div class="coordinate-row">
- <el-input-number v-model="form.longitude" :precision="6" :step="0.000001" controls-position="right" placeholder="经度" />
- <el-input-number v-model="form.latitude" :precision="6" :step="0.000001" controls-position="right" placeholder="纬度" />
- <el-button type="primary" plain @click="openMapPicker">地图选点</el-button>
- </div>
- <div class="coordinate-tip">{{ locationTip || "点击地图获取经纬度,地址将自动回填到安装位置,也可以直接手工修改。" }}</div>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="安装时间" prop="installTime">
- <el-date-picker
- v-model="form.installTime"
- type="datetime"
- value-format="YYYY-MM-DD HH:mm:ss"
- placeholder="请选择安装时间"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="维护人员" prop="maintainer">
- <el-input v-model="form.maintainer" placeholder="请输入维护人员" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="联系电话" prop="maintainerPhone">
- <el-input v-model="form.maintainerPhone" placeholder="请输入联系电话" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="设备图片" prop="equipmentImage">
- <image-upload v-model="form.equipmentImage" :limit="1" />
- </el-form-item>
- </el-col>
- </el-row>
- <slot />
- </el-form>
- <!-- 地图选点弹窗 -->
- <el-dialog v-model="mapOpen" title="地图选点" width="760px" append-to-body>
- <div class="map-picker">
- <GisMapCanvas
- :center="mapCenter"
- :points="mapPoints"
- :enable-clustering="false"
- :show-marker-name="false"
- @map-click="handleMapClick"
- />
- </div>
- <div class="map-picker-coordinates">
- 当前坐标:经度 {{ form.longitude ?? "-" }},纬度 {{ form.latitude ?? "-" }}
- </div>
- <div class="map-picker-coordinates">
- 解析地址:{{ form.equipmentLocation || "点击地图后自动解析" }}
- </div>
- <template #footer>
- <el-button @click="mapOpen = false">关 闭</el-button>
- <el-button type="primary" @click="mapOpen = false">使用当前坐标</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import { computed, ref } from 'vue'
- import GisMapCanvas from '@/components/GisMapCanvas.vue'
- import { bd09ToWgs84 } from '@/utils/coordTransform'
- const props = defineProps({ modelValue: { type: Object, required: true }, types: { type: Array, default: () => [] }, typeLocked: Boolean })
- const emit = defineEmits(['update:modelValue'])
- const form = computed({ get: () => props.modelValue, set: value => emit('update:modelValue', value) })
- const formRef = ref(), mapOpen = ref(false), mapCenter = ref({ lng: 110.3965, lat: 28.4638 }), mapPoints = ref([]), locationTip = ref('')
- const districtOptions = [{ label: '城南', value: 0 }, { label: '城北', value: 1 }, { label: '太常', value: 2 }]
- const equipmentStatusOptions = [{ label: '在用', value: 0 }, { label: '维修', value: 1 }, { label: '报废', value: 2 }]
- const rules = {
- equipmentCode: [{ required: true, message: '设备编码不能为空', trigger: 'blur' }],
- equipmentName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
- equipmentTypeId: [{ required: true, message: '设备类型不能为空', trigger: 'change' }],
- district: [{ required: true, message: '所属片区不能为空', trigger: 'change' }]
- }
- // 逆地理编码:传入百度 BD-09 坐标,返回结构化地址文本,失败时返回空串
- function reverseGeocode(lng, lat) {
- return new Promise((resolve) => {
- const BMapGL = window.BMapGL;
- if (!BMapGL || typeof BMapGL.Geocoder !== "function") {
- resolve("");
- return;
- }
- try {
- const geocoder = new BMapGL.Geocoder();
- geocoder.getLocation(new BMapGL.Point(lng, lat), (result) => {
- resolve(extractAddress(result));
- });
- } catch (error) {
- resolve("");
- }
- });
- }
- function extractAddress(result) {
- const content = result?.content || result || {};
- const address = result?.address || content.address;
- if (address) {
- return String(address);
- }
- const components = result?.addressComponents || content.address_detail || {};
- return [components.province, components.city, components.district, components.street, components.streetNumber]
- .filter(Boolean)
- .join("");
- }
- // 地图选点后按坐标回填安装位置,解析失败时保留原值
- async function fillLocationByPoint(lng, lat) {
- locationTip.value = "正在解析地址...";
- const address = await reverseGeocode(lng, lat);
- if (address) {
- form.value.equipmentLocation = address;
- locationTip.value = "已按选点回填安装位置,可手工修改。";
- } else {
- locationTip.value = "地址解析失败,请手动填写安装位置。";
- }
- }
- function openMapPicker() {
- const longitude = Number(form.value.longitude);
- const latitude = Number(form.value.latitude);
- mapCenter.value = Number.isFinite(longitude) && Number.isFinite(latitude)
- ? { lng: longitude, lat: latitude }
- : { lng: 110.3965, lat: 28.4638 };
- mapPoints.value = Number.isFinite(longitude) && Number.isFinite(latitude)
- ? [{ lng: longitude, lat: latitude, name: form.value.equipmentName || "设备位置" }]
- : [];
- locationTip.value = "";
- mapOpen.value = true;
- }
- function handleMapClick(point) {
- if (!point) return;
- const [longitude, latitude] = bd09ToWgs84(point.lng, point.lat);
- form.value.longitude = Number(longitude.toFixed(6));
- form.value.latitude = Number(latitude.toFixed(6));
- mapPoints.value = [{ lng: form.value.longitude, lat: form.value.latitude, name: form.value.equipmentName || "设备位置" }];
- fillLocationByPoint(point.lng, point.lat);
- }
- defineExpose({ validate: (...args) => formRef.value.validate(...args), resetFields: () => formRef.value?.resetFields() })
- </script>
- <style scoped>
- .form-section-title {
- margin: 8px 0 12px;
- padding-left: 10px;
- border-left: 3px solid #014db2;
- color: #1f2937;
- font-size: 14px;
- font-weight: 600;
- }
- .coordinate-row {
- display: flex;
- align-items: center;
- gap: 10px;
- width: 100%;
- }
- .coordinate-row :deep(.el-input-number) {
- flex: 1;
- }
- .coordinate-tip {
- margin-top: 6px;
- color: #9ca3af;
- font-size: 12px;
- }
- .map-picker {
- height: 420px;
- overflow: hidden;
- border: 1px solid #e5e7eb;
- border-radius: 6px;
- }
- .map-picker-coordinates {
- margin-top: 10px;
- color: #6b7280;
- font-size: 13px;
- }
- </style>
|