Showing
5 changed files
with
132 additions
and
47 deletions
... | ... | @@ -72,9 +72,17 @@ export const deviceProfile = () => { |
72 | 72 | }); |
73 | 73 | }; |
74 | 74 | |
75 | +// 创建或编辑设备 | |
75 | 76 | export const createOrEditDevice = (data) => { |
76 | 77 | return defHttp.post({ |
77 | 78 | url: DeviceManagerApi.DEVICE_URL, |
78 | 79 | data, |
79 | 80 | }); |
80 | 81 | }; |
82 | + | |
83 | +// 获取设备唯一token | |
84 | +export const getDeviceToken = () => { | |
85 | + return defHttp.get({ | |
86 | + url: '/common', | |
87 | + }); | |
88 | +}; | ... | ... |
... | ... | @@ -2,8 +2,8 @@ |
2 | 2 | <BasicModal |
3 | 3 | v-bind="$attrs" |
4 | 4 | width="55rem" |
5 | - @register="register" | |
6 | 5 | :title="getTitle" |
6 | + @register="register" | |
7 | 7 | @cancel="handleCancel" |
8 | 8 | @ok="handleOk" |
9 | 9 | centered |
... | ... | @@ -15,25 +15,30 @@ |
15 | 15 | </a-steps> |
16 | 16 | </div> |
17 | 17 | <div class="mt-5"> |
18 | - <DeviceStep1 @next="handleStep1Next" v-show="current === 0" ref="DeviceStep1Ref" /> | |
18 | + <DeviceStep1 | |
19 | + @next="handleStep1Next" | |
20 | + v-show="current === 0" | |
21 | + ref="DeviceStep1Ref" | |
22 | + :deviceInfo="deviceInfo" | |
23 | + /> | |
19 | 24 | <DeviceStep2 |
20 | 25 | ref="DeviceStep2Ref" |
21 | 26 | @prev="handleStepPrev" |
22 | 27 | @next="handleStep2Next" |
23 | 28 | v-show="current === 1" |
24 | - v-if="initStep2" | |
25 | 29 | /> |
26 | 30 | </div> |
27 | 31 | </BasicModal> |
28 | 32 | </template> |
29 | 33 | <script lang="ts"> |
30 | - import { defineComponent, ref, computed, unref, reactive, toRefs } from 'vue'; | |
34 | + import { defineComponent, ref, computed, unref } from 'vue'; | |
31 | 35 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
32 | - import { createOrEditDevice } from '/@/api/device/deviceManager'; | |
36 | + import { createOrEditDevice, getDeviceToken } from '/@/api/device/deviceManager'; | |
33 | 37 | import DeviceStep1 from '/@/views/device/step/DeviceStep1.vue'; |
34 | 38 | import DeviceStep2 from '/@/views/device/step/DeviceStep2.vue'; |
35 | 39 | import { Steps } from 'ant-design-vue'; |
36 | 40 | import { useMessage } from '/@/hooks/web/useMessage'; |
41 | + | |
37 | 42 | export default defineComponent({ |
38 | 43 | name: 'DeviceModal', |
39 | 44 | components: { |
... | ... | @@ -46,27 +51,31 @@ |
46 | 51 | props: { |
47 | 52 | userData: { type: Object }, |
48 | 53 | }, |
54 | + emits: ['reload'], | |
49 | 55 | setup(_, { emit }) { |
50 | 56 | const DeviceStep1Ref = ref<InstanceType<typeof DeviceStep1>>(); |
51 | 57 | const DeviceStep2Ref = ref<InstanceType<typeof DeviceStep2>>(); |
52 | 58 | const { createMessage } = useMessage(); |
53 | - const state = reactive({ | |
54 | - initStep2: false, | |
55 | - }); | |
56 | 59 | const current = ref(0); |
57 | 60 | const isUpdate = ref(true); |
61 | + const deviceInfo = ref({}); | |
58 | 62 | const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备')); |
59 | 63 | // 所有参数 |
60 | 64 | let stepState = ref(); |
61 | 65 | // 编辑回显 |
62 | 66 | const [register, { closeModal }] = useModalInner((data) => { |
63 | 67 | if (data.isUpdate) { |
64 | - DeviceStep1Ref.value?.parentSetFieldsValue(data.record); | |
65 | - DeviceStep1Ref.value?.parentSetFieldsValue({ | |
68 | + DeviceStep1Ref?.value?.parentSetFieldsValue(data.record); | |
69 | + DeviceStep1Ref?.value?.parentSetFieldsValue({ | |
66 | 70 | profile: data.record.deviceProfile.name, |
67 | 71 | remark: data.record.deviceInfo.description, |
68 | 72 | profileId: data.record.profileId, |
69 | 73 | }); |
74 | + deviceInfo.value = data.record.deviceInfo; | |
75 | + } else { | |
76 | + DeviceStep1Ref?.value?.parentResetDevicePic(); | |
77 | + DeviceStep1Ref?.value?.parentResetPositionState(); | |
78 | + deviceInfo.value = {}; | |
70 | 79 | } |
71 | 80 | isUpdate.value = !!data?.isUpdate; |
72 | 81 | }); |
... | ... | @@ -78,12 +87,11 @@ |
78 | 87 | // 下一步 |
79 | 88 | function handleStep1Next(step1Values: any) { |
80 | 89 | current.value++; |
81 | - state.initStep2 = true; | |
82 | - stepState = { ...step1Values }; | |
90 | + stepState.value = { ...step1Values }; | |
83 | 91 | } |
84 | 92 | // |
85 | 93 | function handleStep2Next(step2Values: any) { |
86 | - stepState = { ...stepState, ...step2Values }; | |
94 | + stepState.value = { ...stepState, ...step2Values }; | |
87 | 95 | } |
88 | 96 | function handleCancel() { |
89 | 97 | current.value = 0; |
... | ... | @@ -111,17 +119,40 @@ |
111 | 119 | } |
112 | 120 | // 验证成功 --掉新增或者编辑接口 |
113 | 121 | const msg = computed(() => (stepState.value.id ? '更新设备成功' : '新增设备成功')); |
114 | - await createOrEditDevice(stepState.value); | |
122 | + console.log(stepState); | |
123 | + if (stepState.value.id) { | |
124 | + const editData = { | |
125 | + ...stepState.value, | |
126 | + deviceInfo: { | |
127 | + avatar: DeviceStep1Ref.value?.devicePic, | |
128 | + ...DeviceStep1Ref.value?.positionState, | |
129 | + }, | |
130 | + }; | |
131 | + await createOrEditDevice(editData); | |
132 | + } else { | |
133 | + let deviceToken = await getDeviceToken(); | |
134 | + // 需要携带唯一的设备token | |
135 | + const createData = { | |
136 | + ...stepState.value, | |
137 | + deviceToken, | |
138 | + deviceInfo: { | |
139 | + avatar: DeviceStep1Ref.value?.devicePic, | |
140 | + ...DeviceStep1Ref.value?.positionState, | |
141 | + }, | |
142 | + }; | |
143 | + | |
144 | + await createOrEditDevice(createData); | |
145 | + } | |
115 | 146 | createMessage.success(msg.value); |
116 | 147 | emit('reload'); |
117 | 148 | } |
118 | 149 | return { |
119 | - register, | |
120 | 150 | getTitle, |
121 | 151 | current, |
122 | 152 | DeviceStep1Ref, |
123 | 153 | DeviceStep2Ref, |
124 | - ...toRefs(state), | |
154 | + deviceInfo, | |
155 | + register, | |
125 | 156 | handleStepPrev, |
126 | 157 | handleStep1Next, |
127 | 158 | handleStep2Next, | ... | ... |
... | ... | @@ -162,12 +162,12 @@ |
162 | 162 | handleDelete, |
163 | 163 | handleSuccess, |
164 | 164 | goDeviceProfile, |
165 | - DeviceTypeEnum, | |
166 | - DeviceState, | |
167 | 165 | handleSelect, |
168 | - searchInfo, | |
169 | 166 | registerModal, |
170 | 167 | handleReload, |
168 | + DeviceTypeEnum, | |
169 | + DeviceState, | |
170 | + searchInfo, | |
171 | 171 | }; |
172 | 172 | }, |
173 | 173 | }); | ... | ... |
... | ... | @@ -41,12 +41,12 @@ |
41 | 41 | <a-row :gutter="20" class="pt-4 pl-6"> |
42 | 42 | <a-col :span="8"> |
43 | 43 | <a-form-item label="经度"> |
44 | - <Input type="input" v-model:value="positionState.lng" disabled /> | |
44 | + <Input type="input" v-model:value="positionState.longitude" disabled /> | |
45 | 45 | </a-form-item> |
46 | 46 | </a-col> |
47 | 47 | <a-col :span="8"> |
48 | 48 | <a-form-item label="纬度"> |
49 | - <Input type="input" v-model:value="positionState.lat" disabled /> | |
49 | + <Input type="input" v-model:value="positionState.latitude" disabled /> | |
50 | 50 | </a-form-item> |
51 | 51 | </a-col> |
52 | 52 | </a-row> |
... | ... | @@ -57,11 +57,10 @@ |
57 | 57 | </div> |
58 | 58 | </template> |
59 | 59 | <script lang="ts"> |
60 | - import { defineComponent, ref, nextTick, unref, reactive } from 'vue'; | |
60 | + import { defineComponent, ref, nextTick, unref, reactive, watch } from 'vue'; | |
61 | 61 | import { BasicForm, useForm } from '/@/components/Form'; |
62 | 62 | import { step1Schemas } from './data'; |
63 | 63 | import { useScript } from '/@/hooks/web/useScript'; |
64 | - import { ScrollActionType } from '/@/components/Container/index'; | |
65 | 64 | import { Input, Divider, Upload, message, Modal, Form, Row, Col } from 'ant-design-vue'; |
66 | 65 | import { EnvironmentTwoTone, PlusOutlined } from '@ant-design/icons-vue'; |
67 | 66 | import { upload } from '/@/api/oss/ossFileUploader'; |
... | ... | @@ -82,12 +81,23 @@ |
82 | 81 | [Row.name]: Row, |
83 | 82 | [Col.name]: Col, |
84 | 83 | }, |
84 | + props: { | |
85 | + deviceInfo: { | |
86 | + type: Object, | |
87 | + default: () => ({}), | |
88 | + }, | |
89 | + }, | |
85 | 90 | emits: ['next'], |
86 | - setup(_, { emit }) { | |
91 | + setup(props, { emit }) { | |
87 | 92 | const devicePic = ref(''); |
88 | - let positionState = reactive({ | |
89 | - lng: '', | |
90 | - lat: '', | |
93 | + let positionState = reactive<{ | |
94 | + longitude: string; | |
95 | + latitude: string; | |
96 | + description?: string; | |
97 | + address: string; | |
98 | + }>({ | |
99 | + longitude: '', | |
100 | + latitude: '', | |
91 | 101 | address: '', |
92 | 102 | }); |
93 | 103 | const [register, { validate, resetFields, setFieldsValue, getFieldsValue }] = useForm({ |
... | ... | @@ -141,49 +151,62 @@ |
141 | 151 | const visible = ref(false); |
142 | 152 | const selectPosition = () => { |
143 | 153 | visible.value = true; |
144 | - initMap(); | |
154 | + if (!positionState.longitude) { | |
155 | + initMap('104.04666605565338', '30.543516387560476'); | |
156 | + } else { | |
157 | + initMap(positionState.longitude, positionState.latitude); | |
158 | + } | |
145 | 159 | }; |
146 | 160 | |
147 | 161 | // 地图 |
148 | 162 | const BAI_DU_MAP_URL = |
149 | 163 | 'https://api.map.baidu.com/getscript?v=3.0&ak=7uOPPyAHn2Y2ZryeQqHtcRqtIY374vKa'; |
150 | 164 | const wrapRef = ref<HTMLDivElement | null>(null); |
151 | - const scrollRef = ref<Nullable<ScrollActionType>>(null); | |
152 | 165 | const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); |
153 | - async function initMap() { | |
166 | + | |
167 | + async function initMap(longitude, latitude) { | |
154 | 168 | await toPromise(); |
155 | 169 | await nextTick(); |
156 | 170 | const wrapEl = unref(wrapRef); |
157 | 171 | const BMap = (window as any).BMap; |
158 | 172 | if (!wrapEl) return; |
173 | + let preMarker = null; | |
159 | 174 | const map = new BMap.Map(wrapEl); |
160 | - const point = new BMap.Point(104.04813399999999, 30.54348986021446); | |
175 | + let myIcon = new BMap.Icon( | |
176 | + 'http://api.map.baidu.com/img/markers.png', | |
177 | + new BMap.Size(40, 25), | |
178 | + { | |
179 | + offset: new BMap.Size(0, 0), // 指定定位位置 | |
180 | + imageOffset: new BMap.Size(20, -260), // 设置图片偏移 | |
181 | + } | |
182 | + ); | |
183 | + const point = new BMap.Point(Number(longitude), Number(latitude)); | |
184 | + let marker = new BMap.Marker(point, { icon: myIcon }); | |
185 | + if (marker) { | |
186 | + map.removeOverlay(preMarker); | |
187 | + } | |
188 | + map.addOverlay(marker); | |
189 | + preMarker = marker; | |
161 | 190 | map.centerAndZoom(point, 15); |
162 | 191 | map.enableScrollWheelZoom(true); |
163 | - let preMarker = null; | |
164 | 192 | map.addEventListener('click', (e) => { |
165 | - const { lat, lng } = map.he; | |
166 | - positionState.lat = lat + ''; | |
167 | - positionState.lng = lng + ''; | |
193 | + const { lat, lng } = e.point; | |
194 | + console.log(lat, lng); | |
195 | + positionState.latitude = lat + ''; | |
196 | + positionState.longitude = lng + ''; | |
168 | 197 | let gc = new BMap.Geocoder(); |
169 | 198 | let newPoint = new BMap.Point(lng, lat); |
199 | + | |
200 | + // 添加锚点 | |
170 | 201 | if (!e.overlay) { |
171 | - let myIcon = new BMap.Icon( | |
172 | - 'http://api.map.baidu.com/img/markers.png', | |
173 | - new BMap.Size(40, 25), | |
174 | - { | |
175 | - offset: new BMap.Size(0, 0), // 指定定位位置 | |
176 | - imageOffset: new BMap.Size(20, -260), // 设置图片偏移 | |
177 | - } | |
178 | - ); | |
179 | 202 | let marker = new BMap.Marker(e.point, { icon: myIcon }); |
180 | 203 | map.removeOverlay(preMarker); |
181 | 204 | map.addOverlay(marker); |
182 | 205 | preMarker = marker; |
183 | 206 | } |
207 | + //获取详细的地址,精确到街道的名称 | |
184 | 208 | gc.getLocation(newPoint, (rs) => { |
185 | 209 | let addComp = rs.addressComponents; |
186 | - //获取详细的地址,精确到街道的名称 | |
187 | 210 | let addrname = addComp.city + addComp.district + addComp.street + addComp.streetNumber; |
188 | 211 | positionState.address = addrname; |
189 | 212 | }); |
... | ... | @@ -203,16 +226,38 @@ |
203 | 226 | function parentSetFieldsValue(data) { |
204 | 227 | setFieldsValue(data); |
205 | 228 | } |
206 | - | |
229 | + // 父组件调用获取字段值的方法 | |
207 | 230 | function parentGetFieldsValue() { |
208 | 231 | return getFieldsValue(); |
209 | 232 | } |
210 | 233 | |
234 | + // 父组件调用表单验证 | |
211 | 235 | async function parentValidate() { |
212 | 236 | const valid = await validate(); |
213 | 237 | return valid; |
214 | 238 | } |
215 | 239 | |
240 | + // 父组件重置图片 | |
241 | + function parentResetDevicePic() { | |
242 | + devicePic.value = ''; | |
243 | + } | |
244 | + // 父组件重置位置 | |
245 | + function parentResetPositionState() { | |
246 | + for (let key in positionState) { | |
247 | + positionState[key] = ''; | |
248 | + } | |
249 | + } | |
250 | + | |
251 | + watch( | |
252 | + () => props.deviceInfo, | |
253 | + (newValue) => { | |
254 | + positionState.longitude = newValue.longitude; | |
255 | + positionState.latitude = newValue.latitude; | |
256 | + positionState.address = newValue.address; | |
257 | + devicePic.value = newValue.avatar; | |
258 | + } | |
259 | + ); | |
260 | + | |
216 | 261 | return { |
217 | 262 | resetFields, |
218 | 263 | positionState, |
... | ... | @@ -222,7 +267,6 @@ |
222 | 267 | selectPosition, |
223 | 268 | devicePic, |
224 | 269 | visible, |
225 | - scrollRef, | |
226 | 270 | handleOk, |
227 | 271 | handleCancel, |
228 | 272 | wrapRef, |
... | ... | @@ -230,6 +274,8 @@ |
230 | 274 | parentSetFieldsValue, |
231 | 275 | parentGetFieldsValue, |
232 | 276 | parentValidate, |
277 | + parentResetDevicePic, | |
278 | + parentResetPositionState, | |
233 | 279 | }; |
234 | 280 | }, |
235 | 281 | }); | ... | ... |