checkTdMap.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. <template>
  2. <view class="container">
  3. <view class="top"></view>
  4. <view class="head">
  5. <view class="handle">
  6. <view class="head_left">
  7. <span class="cuIcon-back" @click="back"></span>
  8. </view>
  9. <span class="center">选择检测站</span>
  10. <span class="submit-btn" @click="submit">确定</span>
  11. </view>
  12. </view>
  13. <!-- 地图容器 -->
  14. <view id="mapContainer" class="map-container"></view>
  15. <!-- 搜索功能区域 -->
  16. <view class="search-panel" v-if="showSearch">
  17. <view class="search-input-group">
  18. <input class="search-input" v-model="searchKeyword" placeholder="输入关键词搜索地点" @confirm="handleSearch"
  19. @input="onSearchInput" />
  20. <button class="search-btn" @click="handleSearch">搜索</button>
  21. </view>
  22. <view class="search-results" v-if="dataTips.length > 0">
  23. <view class="result-header">
  24. <text>搜索结果 ({{ dataTips.length }} 个)</text>
  25. <text class="clear-results" @click="clearSearchResults">清除搜索结果</text>
  26. </view>
  27. <scroll-view class="results-list" scroll-y>
  28. <view v-for="(result, index) in dataTips" :key="index"
  29. class="result-item"
  30. @click="selectSearchResult(result)"
  31. :class="{'selected': result.check}">
  32. <view class="left">
  33. <view class="result-name">
  34. <text v-show="result.check" class="selected-tag">已选</text>
  35. {{ result.name }}
  36. </view>
  37. <view class="result-address">{{ result.address }}</view>
  38. </view>
  39. <view class="right">
  40. <image src="/static/coupon/danxuan.png" mode="" v-if="result.check"></image>
  41. <image src="/static/product/round.png" mode="" v-else></image>
  42. </view>
  43. </view>
  44. </scroll-view>
  45. </view>
  46. </view>
  47. </view>
  48. </template>
  49. <script>
  50. export default {
  51. props: {
  52. initialPosition: {
  53. type: Object,
  54. default: () => ({
  55. lnglat: null,
  56. address: ''
  57. })
  58. },
  59. allowSelection: {
  60. type: Boolean,
  61. default: true
  62. },
  63. showCoordinates: {
  64. type: Boolean,
  65. default: true
  66. },
  67. showSearch: {
  68. type: Boolean,
  69. default: true
  70. }
  71. },
  72. data() {
  73. return {
  74. tk: '9bcf63358817bfb878e8236de8bf1423',
  75. searchKeyword: '',
  76. dataTips: [], // 存储:已选检测站 + 搜索结果(合并去重)
  77. selectedResult: null,
  78. renderjsReady: false,
  79. merchantId: uni.getStorageSync('login_user_info')?.merchantId || '',
  80. originalSelected: [] // 新增:存储原始已选检测站(用于去重和保留)
  81. };
  82. },
  83. mounted() {
  84. console.log('组件mounted');
  85. // 1. 先获取已选检测站(保留原有数据)
  86. this.getShopList();
  87. // 2. 等待renderjs初始化
  88. setTimeout(() => {
  89. this.waitForRenderjs();
  90. }, 1000);
  91. },
  92. methods: {
  93. // 核心:获取已选检测站(保留到originalSelected,避免被搜索覆盖)
  94. getShopList() {
  95. if (!this.merchantId) {
  96. console.warn('商户ID不存在');
  97. return;
  98. }
  99. this.$http.get(`/ts/localTsMerchantLinkInspection/list?merchantId=${this.merchantId}`).then(res => {
  100. if (res.data.code == 200) {
  101. // 存储原始已选数据(用于去重)
  102. this.originalSelected = res.data.result.map(item => ({
  103. ...item,
  104. check: true, // 强制设置为已选
  105. lonlat: `${item.inspectionStationLongitude},${item.inspectionStationLatitude}`,
  106. address: item.detailedAddress,
  107. name: item.inspectionStationName,
  108. // 新增:用ID作为唯一标识(避免重复添加)
  109. uniqueKey: item.id || `${item.inspectionStationLongitude}-${item.inspectionStationLatitude}`
  110. }));
  111. // 初始数据 = 原始已选数据
  112. this.dataTips = [...this.originalSelected];
  113. console.log(this.dataTips)
  114. // 自动定位第一个已选检测站(传入isInit=true,不切换check状态)
  115. if (this.dataTips.length > 0) {
  116. this.selectSearchResult(this.dataTips[0], true); // 修改:添加isInit参数
  117. }
  118. }
  119. }).catch(err => {
  120. console.error('获取已选检测站失败:', err);
  121. });
  122. },
  123. // 等待renderjs就绪
  124. waitForRenderjs() {
  125. if (this.renderjsReady) return;
  126. const checkInterval = setInterval(() => {
  127. if (this.$refs && this.$refs.renderjsMap) {
  128. clearInterval(checkInterval);
  129. this.renderjsReady = true;
  130. console.log('renderjs就绪');
  131. if (this.initialPosition && this.isValidPosition(this.initialPosition)) {
  132. this.setMapCenterFromProps();
  133. }
  134. }
  135. }, 100);
  136. setTimeout(() => {
  137. clearInterval(checkInterval);
  138. console.warn('等待renderjs超时');
  139. }, 10000);
  140. },
  141. setMapCenterFromProps() {
  142. const mapData = {
  143. lng: this.initialPosition.lng ||
  144. (this.initialPosition.lnglat && this.initialPosition.lnglat.lng) ||
  145. (this.initialPosition.lnglat && this.initialPosition.lnglat.longitude),
  146. lat: this.initialPosition.lat ||
  147. (this.initialPosition.lnglat && this.initialPosition.lnglat.lat) ||
  148. (this.initialPosition.lnglat && this.initialPosition.lnglat.latitude),
  149. address: this.initialPosition.address || ''
  150. };
  151. this.callRenderjsMethod('updateMapWithMarker', mapData);
  152. },
  153. callRenderjsMethod(methodName, data) {
  154. if (!this.renderjsReady) {
  155. console.warn('renderjs未就绪,延迟执行');
  156. setTimeout(() => {
  157. this.callRenderjsMethod(methodName, data);
  158. }, 300);
  159. return;
  160. }
  161. try {
  162. if (this.$refs.renderjsMap) {
  163. this.$refs.renderjsMap.callMethod(methodName, data);
  164. return;
  165. }
  166. const ownerInstance = this.$ownerInstance;
  167. if (ownerInstance && ownerInstance.callMethod) {
  168. ownerInstance.callMethod('callRenderjsMethod', {
  169. method: methodName,
  170. data: data
  171. });
  172. return;
  173. }
  174. console.error('无法调用renderjs方法');
  175. } catch (error) {
  176. console.error(`调用renderjs方法 ${methodName} 失败:`, error);
  177. setTimeout(() => {
  178. if (this.renderjsReady) {
  179. this.callRenderjsMethod(methodName, data);
  180. }
  181. }, 500);
  182. }
  183. },
  184. // 选择检测站:新增isInit参数,区分初始化和用户点击
  185. selectSearchResult(result, isInit = false) {
  186. console.log('选择搜索结果:', result);
  187. // 只有非初始化场景,才切换check状态(用户点击时)
  188. if (!isInit) {
  189. result.check = !result.check;
  190. this.selectedResult = result.check ? result : null;
  191. } else {
  192. // 初始化场景:强制保持check=true,仅定位不切换
  193. result.check = true;
  194. this.selectedResult = result;
  195. }
  196. // 提取经纬度并定位
  197. const coords = this.extractCoordinates(result);
  198. if (!coords) {
  199. uni.showToast({
  200. title: '无法获取位置坐标',
  201. icon: 'none'
  202. });
  203. console.error('无法解析坐标:', result);
  204. return;
  205. }
  206. const { lng, lat } = coords;
  207. const mapData = {
  208. lng: lng,
  209. lat: lat,
  210. address: result.address || result.name,
  211. name: result.name,
  212. fromSearch: true
  213. };
  214. this.callRenderjsMethod('updateMapWithMarker', mapData);
  215. console.log('地图已定位到:', lng, lat, result.name);
  216. },
  217. // 核心提交:带上原有已选 + 当前新选
  218. submit() {
  219. // 过滤所有选中的检测站(包括原有已选和当前新选)
  220. const selectedItems = this.dataTips.filter(item => item.check);
  221. if (selectedItems.length === 0) {
  222. uni.showToast({
  223. title: '请至少选择一个检测站',
  224. icon: 'none'
  225. });
  226. return;
  227. }
  228. // 构造提交数据(兼容原有已选和新选)
  229. const submitData = selectedItems.map(item => {
  230. const locationParts = item.lonlat ? item.lonlat.split(",") : [];
  231. return {
  232. // 原有已选数据带id,新选数据可能没有,保留id(便于后端更新/去重)
  233. id: item.id || '',
  234. country: item.adcode || item.country || '',
  235. detailedAddress: item.address || item.detailedAddress || '',
  236. inspectionStationName: item.name || item.inspectionStationName || '',
  237. locality: item.district || item.locality || '',
  238. inspectionStationLongitude: item.inspectionStationLongitude || (locationParts[0] || null),
  239. inspectionStationLatitude: item.inspectionStationLatitude || (locationParts[1] || null),
  240. merchantId: this.merchantId
  241. };
  242. });
  243. // 调用保存接口(后端需支持:存在id则更新,不存在则新增)
  244. this.$http.post("/ts/localTsMerchantLinkInspection/add", submitData).then(res => {
  245. console.log('保存检测站结果:', res);
  246. if (res.data.code == 200) {
  247. uni.showToast({
  248. icon: 'none',
  249. title: '保存成功(包含原有已选)'
  250. });
  251. this.back();
  252. } else {
  253. uni.showToast({
  254. icon: 'none',
  255. title: '保存失败:' + (res.data.msg || '未知错误')
  256. });
  257. }
  258. }).catch(err => {
  259. console.error('保存检测站失败:', err);
  260. uni.showToast({
  261. icon: 'none',
  262. title: '网络错误,请重试'
  263. });
  264. });
  265. },
  266. // 提取坐标信息
  267. extractCoordinates(item) {
  268. let lng, lat;
  269. if (item.lonlat) {
  270. const coords = item.lonlat.split(',');
  271. if (coords.length >= 2) {
  272. lng = parseFloat(coords[0]);
  273. lat = parseFloat(coords[1]);
  274. }
  275. } else if (item.longitude && item.latitude) {
  276. lng = item.longitude;
  277. lat = item.latitude;
  278. } else if (item.lng && item.lat) {
  279. lng = item.lng;
  280. lat = item.lat;
  281. } else if (item.inspectionStationLongitude && item.inspectionStationLatitude) {
  282. lng = item.inspectionStationLongitude;
  283. lat = item.inspectionStationLatitude;
  284. }
  285. if (lng !== undefined && lat !== undefined &&
  286. !isNaN(lng) && !isNaN(lat) &&
  287. lng >= -180 && lng <= 180 &&
  288. lat >= -90 && lat <= 90) {
  289. return { lng, lat };
  290. }
  291. console.warn('无法提取有效坐标:', item);
  292. return null;
  293. },
  294. back() {
  295. uni.navigateBack({
  296. delta: 1
  297. });
  298. },
  299. isValidPosition(position) {
  300. const lng = position.lng ||
  301. (position.lnglat && (position.lnglat.lng || position.lnglat.longitude));
  302. const lat = position.lat ||
  303. (position.lnglat && (position.lnglat.lat || position.lnglat.latitude));
  304. return lng && lat && !isNaN(parseFloat(lng)) && !isNaN(parseFloat(lat));
  305. },
  306. // 搜索:合并搜索结果与原有已选(去重)
  307. handleSearch() {
  308. if (!this.searchKeyword.trim()) {
  309. uni.showToast({
  310. title: '请输入搜索关键词',
  311. icon: 'none'
  312. });
  313. return;
  314. }
  315. this.searchByRestAPI(this.searchKeyword);
  316. },
  317. searchByRestAPI(keyword) {
  318. let cityCode = uni.getStorageSync('cityCode') || '140100';
  319. let postStr = {
  320. "keyWord": keyword,
  321. "queryType": 12,
  322. "start": 0,
  323. "count": 10,
  324. "specify": "156" + cityCode
  325. };
  326. uni.request({
  327. url: `https://api.tianditu.gov.cn/v2/search?postStr=${encodeURIComponent(JSON.stringify(postStr))}&type=query&tk=${this.tk}`,
  328. success: (res) => {
  329. if (res.statusCode === 200 && res.data) {
  330. // 处理搜索结果:添加唯一标识,避免与原有已选重复
  331. const searchResults = res.data.pois.map(item => ({
  332. ...item,
  333. location: item.lonlat,
  334. check: false, // 新搜索结果默认未选中
  335. detailedAddress: item.address,
  336. inspectionStationName: item.name,
  337. locality: item.district || '',
  338. // 唯一标识:用经纬度拼接(避免重复添加同一检测站)
  339. uniqueKey: `${item.lonlat}`
  340. }));
  341. // 合并:原有已选 + 新搜索结果(去重)
  342. const allData = [...this.originalSelected];
  343. searchResults.forEach(searchItem => {
  344. // 去重:判断uniqueKey是否已存在
  345. const isDuplicate = allData.some(
  346. item => item.uniqueKey === searchItem.uniqueKey
  347. );
  348. if (!isDuplicate) {
  349. allData.push(searchItem);
  350. }
  351. });
  352. // 更新显示列表(保留原有已选)
  353. this.dataTips = allData;
  354. } else {
  355. uni.showToast({
  356. title: '搜索失败,请重试',
  357. icon: 'none'
  358. });
  359. }
  360. },
  361. fail: (error) => {
  362. console.error('搜索请求失败:', error);
  363. uni.showToast({
  364. title: '网络错误,请重试',
  365. icon: 'none'
  366. });
  367. }
  368. });
  369. },
  370. onSearchInput(e) {
  371. this.searchKeyword = e.detail.value;
  372. },
  373. // 清除搜索结果:只清除新搜索的,保留原有已选
  374. clearSearchResults() {
  375. this.searchKeyword = '';
  376. this.selectedResult = null;
  377. // 恢复为原始已选数据(清除新搜索结果)
  378. this.dataTips = [...this.originalSelected];
  379. }
  380. }
  381. };
  382. </script>
  383. <!-- renderjs模块不变 -->
  384. <script module="renderjsMap" lang="renderjs">
  385. let mapInstance = null;
  386. let markerInstance = null;
  387. let labelInstance = null;
  388. export default {
  389. data() {
  390. return {
  391. mapLoaded: false,
  392. lastDataHash: ''
  393. };
  394. },
  395. methods: {
  396. updateMapWithMarker(mapData) {
  397. console.log('【RenderJS】updateMapWithMarker 被调用', mapData);
  398. if (!this.mapLoaded || !mapInstance) {
  399. console.warn('地图未加载,延迟执行');
  400. setTimeout(() => {
  401. this.updateMapWithMarker(mapData);
  402. }, 300);
  403. return;
  404. }
  405. const dataHash = JSON.stringify(mapData);
  406. if (dataHash === this.lastDataHash) {
  407. console.log('数据未变化,跳过更新');
  408. return;
  409. }
  410. this.lastDataHash = dataHash;
  411. const lng = Number(mapData.lng);
  412. const lat = Number(mapData.lat);
  413. const address = mapData.address || mapData.name || '未知位置';
  414. if (isNaN(lng) || isNaN(lat)) {
  415. console.error('坐标无效:', mapData);
  416. return;
  417. }
  418. const targetLngLat = new window.T.LngLat(lng, lat);
  419. mapInstance.panTo(targetLngLat);
  420. if (mapData.fromSearch) {
  421. mapInstance.setZoom(15);
  422. }
  423. this.createMarker(targetLngLat, address, mapData.name || '');
  424. },
  425. clearMarkers() {
  426. if (markerInstance && mapInstance) {
  427. mapInstance.removeOverLay(markerInstance);
  428. markerInstance = null;
  429. }
  430. if (labelInstance && mapInstance) {
  431. mapInstance.removeOverLay(labelInstance);
  432. labelInstance = null;
  433. }
  434. },
  435. createMarker(lngLat, address, name) {
  436. try {
  437. const T = window.T;
  438. this.clearMarkers();
  439. const iconUrl = this.generateMarkerIcon('#ff0000');
  440. const icon = new T.Icon({
  441. iconUrl: iconUrl,
  442. iconSize: new T.Point(30, 30),
  443. iconAnchor: new T.Point(15, 30)
  444. });
  445. markerInstance = new T.Marker(lngLat, {
  446. icon: icon,
  447. title: name || address
  448. });
  449. labelInstance = new T.Label({
  450. text: address,
  451. position: lngLat,
  452. style: {
  453. color: '#333',
  454. backgroundColor: 'rgba(255, 255, 255, 0.9)',
  455. borderColor: '#ff0000',
  456. borderWidth: 1,
  457. borderRadius: 4,
  458. fontSize: '14px',
  459. fontWeight: '500',
  460. padding: '6px 10px'
  461. },
  462. offset: new T.Point(0, -40)
  463. });
  464. mapInstance.addOverLay(markerInstance);
  465. mapInstance.addOverLay(labelInstance);
  466. markerInstance.addEventListener('click', () => {
  467. this.sendToVue('showLocationInfo', {
  468. lng: lngLat.getLng().toFixed(6),
  469. lat: lngLat.getLat().toFixed(6),
  470. address: address,
  471. name: name
  472. });
  473. });
  474. console.log('标记创建成功');
  475. } catch (error) {
  476. console.error('创建标记失败:', error);
  477. }
  478. },
  479. generateMarkerIcon(color) {
  480. const size = 30;
  481. const canvas = document.createElement('canvas');
  482. canvas.width = size;
  483. canvas.height = size;
  484. const ctx = canvas.getContext('2d');
  485. ctx.beginPath();
  486. ctx.arc(size/2, size/2, size/2 - 1, 0, Math.PI * 2);
  487. ctx.fillStyle = '#ffffff';
  488. ctx.fill();
  489. ctx.beginPath();
  490. ctx.arc(size/2, size/2, size/2 - 4, 0, Math.PI * 2);
  491. ctx.fillStyle = color;
  492. ctx.fill();
  493. return canvas.toDataURL();
  494. },
  495. async initMap() {
  496. try {
  497. console.log('【RenderJS】开始初始化地图');
  498. await this.loadTiandituAPI();
  499. const container = document.getElementById('mapContainer');
  500. if (!container) throw new Error('地图容器不存在');
  501. const T = window.T;
  502. mapInstance = new T.Map(container);
  503. const center = new T.LngLat(112.55, 37.87);
  504. mapInstance.centerAndZoom(center, 12);
  505. const vecLayer = new T.TileLayer(
  506. `https://t{s}.tianditu.gov.cn/vec_c/wmts?tk=9bcf63358817bfb878e8236de8bf1423`, {
  507. subdomains: ['0', '1', '2', '3', '4', '5', '6', '7']
  508. }
  509. );
  510. const cvaLayer = new T.TileLayer(
  511. `https://t{s}.tianditu.gov.cn/cva_c/wmts?tk=9bcf63358817bfb878e8236de8bf1423`, {
  512. subdomains: ['0', '1', '2', '3', '4', '5', '6', '7']
  513. }
  514. );
  515. mapInstance.addLayer(vecLayer);
  516. mapInstance.addLayer(cvaLayer);
  517. mapInstance.addControl(new T.Control.Zoom());
  518. mapInstance.addEventListener('click', (e) => this.handleMapClick(e));
  519. this.mapLoaded = true;
  520. console.log('【RenderJS】地图初始化完成');
  521. } catch (error) {
  522. console.error('【RenderJS】地图初始化失败:', error);
  523. }
  524. },
  525. loadTiandituAPI() {
  526. return new Promise((resolve, reject) => {
  527. if (window.T && window.T.Map) {
  528. resolve();
  529. return;
  530. }
  531. const script = document.createElement('script');
  532. script.src = 'https://api.tianditu.gov.cn/api?v=4.0&tk=9bcf63358817bfb878e8236de8bf1423';
  533. script.onload = () => {
  534. const checkInterval = setInterval(() => {
  535. if (window.T && window.T.Map) {
  536. clearInterval(checkInterval);
  537. resolve();
  538. }
  539. }, 100);
  540. setTimeout(() => {
  541. clearInterval(checkInterval);
  542. reject(new Error('T对象初始化超时'));
  543. }, 5000);
  544. };
  545. script.onerror = reject;
  546. document.head.appendChild(script);
  547. });
  548. },
  549. handleMapClick(e) {
  550. if (!this.mapLoaded) return;
  551. const lng = e.lnglat.lng;
  552. const lat = e.lnglat.lat;
  553. const mapData = { lng, lat, address: '点击位置' };
  554. this.updateMapWithMarker(mapData);
  555. this.sendToVue('onMapClick', { lng, lat });
  556. },
  557. sendToVue(method, data) {
  558. try {
  559. if (this.$ownerInstance && this.$ownerInstance.callMethod) {
  560. this.$ownerInstance.callMethod(method, data);
  561. }
  562. } catch (error) {
  563. console.error('发送消息到Vue失败:', error);
  564. }
  565. },
  566. cleanupMap() {
  567. this.clearMarkers();
  568. if (mapInstance) {
  569. try { mapInstance.destroy(); } catch (e) {}
  570. mapInstance = null;
  571. }
  572. this.mapLoaded = false;
  573. }
  574. },
  575. mounted() {
  576. console.log('【RenderJS】模块挂载');
  577. setTimeout(() => this.initMap(), 500);
  578. },
  579. beforeDestroy() {
  580. console.log('【RenderJS】模块销毁');
  581. this.cleanupMap();
  582. }
  583. };
  584. </script>
  585. <style scoped lang="scss">
  586. .top {
  587. width: 100%;
  588. height: var(--status-bar-height);
  589. background: linear-gradient(87deg, #FFFFFF 0%, #A3CDFF 100%), linear-gradient(360deg, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%);
  590. }
  591. .head {
  592. width: 100%;
  593. background: #ffffff;
  594. .handle {
  595. height: 112rpx;
  596. display: flex;
  597. justify-content: space-between;
  598. align-items: center;
  599. padding: 0px 24rpx;
  600. position: relative;
  601. .head_left {
  602. font-size: 40rpx;
  603. }
  604. .center {
  605. position: absolute;
  606. left: 50%;
  607. top: 50%;
  608. transform: translate(-50%, -50%);
  609. font-size: 30rpx;
  610. font-weight: 600;
  611. }
  612. .submit-btn {
  613. display: flex;
  614. width: 104rpx;
  615. height: 49rpx;
  616. background: #2D88F4;
  617. border-radius: 8rpx;
  618. align-items: center;
  619. justify-content: center;
  620. font-size: 28rpx;
  621. color: #FFFFFF;
  622. }
  623. }
  624. }
  625. .container {
  626. width: 100%;
  627. height: 100vh;
  628. display: flex;
  629. flex-direction: column;
  630. position: relative;
  631. }
  632. .map-container {
  633. width: 100%;
  634. height: 300px;
  635. background-color: #f8f8f8;
  636. position: relative;
  637. }
  638. .search-panel {
  639. margin-top: 20rpx;
  640. padding: 20rpx;
  641. background-color: #f8f9fa;
  642. border-radius: 8rpx;
  643. flex: 1;
  644. display: flex;
  645. flex-direction: column;
  646. }
  647. .search-input-group {
  648. display: flex;
  649. gap: 10rpx;
  650. margin-bottom: 20rpx;
  651. }
  652. .search-input {
  653. flex: 1;
  654. height: 70rpx;
  655. padding: 0 20rpx;
  656. border: 1px solid #ddd;
  657. border-radius: 8rpx;
  658. background-color: white;
  659. font-size: 28rpx;
  660. }
  661. .search-btn {
  662. height: 70rpx;
  663. padding: 0 20rpx;
  664. background-color: #1890ff;
  665. color: white;
  666. border-radius: 8rpx;
  667. display: flex;
  668. align-items: center;
  669. justify-content: center;
  670. font-size: 28rpx;
  671. border: none;
  672. }
  673. .search-results {
  674. border: 1px solid #e8e8e8;
  675. border-radius: 8rpx;
  676. flex: 1;
  677. background-color: white;
  678. }
  679. .result-header {
  680. display: flex;
  681. justify-content: space-between;
  682. align-items: center;
  683. padding: 20rpx;
  684. border-bottom: 1px solid #f0f0f0;
  685. font-weight: bold;
  686. font-size: 28rpx;
  687. }
  688. .clear-results {
  689. color: #1890ff;
  690. font-size: 24rpx;
  691. }
  692. .results-list {
  693. max-height: 700rpx;
  694. }
  695. .result-item {
  696. padding: 20rpx;
  697. border-bottom: 1px solid #f5f5f5;
  698. cursor: pointer;
  699. display: flex;
  700. justify-content: space-between;
  701. align-items: center;
  702. &.selected {
  703. background-color: #e6f7ff;
  704. border-left: 4rpx solid #1890ff;
  705. }
  706. .left {
  707. flex: 1;
  708. margin-right: 20rpx;
  709. }
  710. .selected-tag {
  711. display: inline-flex;
  712. align-items: center;
  713. justify-content: center;
  714. width: 80rpx;
  715. height: 43rpx;
  716. background: rgba(253,73,18,0.05);
  717. border-radius: 4rpx ;
  718. font-size: 24rpx;
  719. color: #FD4912;
  720. margin-right: 12rpx;
  721. }
  722. .right {
  723. image {
  724. width: 40rpx;
  725. height: 40rpx;
  726. }
  727. }
  728. }
  729. .result-name {
  730. font-weight: bold;
  731. margin-bottom: 5rpx;
  732. color: #333;
  733. font-size: 28rpx;
  734. display: flex;
  735. align-items: center;
  736. }
  737. .result-address {
  738. font-size: 24rpx;
  739. color: #666;
  740. }
  741. </style>