管灌系统农户端微信小程序(嘉峪关应用)
更新项目配置,添加监测站相关数据和状态管理;优化首页和监测页面的逻辑,提升用户体验;新增SVG图标资源,更新样式以增强可视化效果。
21个文件已添加
1个文件已删除
11个文件已修改
3791 ■■■■ 已修改文件
.lingma/rules/base.md 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/capture.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/error.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/five.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/flow.svg 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/four.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/humidity.svg 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/light.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/mixing.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/no-data.svg 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/one.svg 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/pump.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/rainfall.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/refresh.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/settings-time.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/settings.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/temperature.svg 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/three.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/timer.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/two.svg 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/uv.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/wind-arrow.svg 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/wind-direction.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/wind-speed.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.js 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.js 1349 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.wxml 507 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.wxss 1539 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
project.config.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
project.private.config.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/projectConfig.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.lingma/rules/base.md
New file
@@ -0,0 +1,4 @@
---
trigger: manual
---
中文回答问题
README.md
File was deleted
app.js
@@ -26,6 +26,7 @@
    clientId:"",
    AppID:"wxbc2b6a00dd904ead",
    vcId:"",
    needRefreshIrrigationList: false // 用于标记是否需要刷新灌溉计划列表
    needRefreshIrrigationList: false, // 用于标记是否需要刷新灌溉计划列表
    selectedProject:""
  }
})
images/capture.svg
New file
@@ -0,0 +1 @@
images/error.svg
New file
@@ -0,0 +1 @@
images/five.svg
New file
@@ -0,0 +1 @@
<svg t="1754961303408" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7522" width="200" height="200"><path d="M391.6 64.4h124.5s-3 10.6-12.5 58.1L516.1 596l63.5-480.5s-10.5-47.2-33.5-51.1h69.4L493.5 954l-60.9-821.5s-11.5-58.2-41-68.1z" fill="#3F8BFD" p-id="7523"></path></svg>
images/flow.svg
@@ -1,3 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 14H9v-4h2v4zm4 0h-2V9h2v8zm4 0h-2V7h2v10z" fill="currentColor"/>
</svg>
<svg t="1755143007160" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11483" width="200" height="200"><path d="M512 938.666667c235.648 0 426.666667-191.018667 426.666667-426.666667S747.648 85.333333 512 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667z m0-768a341.333333 341.333333 0 1 1 0 682.666666 341.333333 341.333333 0 0 1 0-682.666666z" p-id="11484" fill="#2c2c2c"></path><path d="M768 554.666667h-50.816q-39.552 0-57.258667-35.413334l-6.485333-13.013333L596.48 733.866667q-8.362667 33.450667-42.837333 32.64-34.474667-0.853333-41.216-34.602667l-47.786667-238.762667-35.754667 143.018667q-8.533333 34.176-43.733333 35.541333-35.157333 1.322667-46.293333-32.085333L310.570667 554.666667H256a42.666667 42.666667 0 0 1 0-85.333334h69.973333q33.92 0 50.773334 23.68l50.773333-202.837333q8.32-33.450667 42.794667-32.64 34.474667 0.853333 41.216 34.602667l47.786666 238.762666 36.48-146.048q7.936-31.701333 40.405334-35.285333 32.512-3.541333 47.104 25.685333L730.368 469.333333h37.589333A42.666667 42.666667 0 1 1 768 554.666667z" p-id="11485" fill="#2c2c2c"></path></svg>
images/four.svg
New file
@@ -0,0 +1 @@
<svg t="1754961278798" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7313" width="200" height="200"><path d="M851.5 63.5H562.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H848s-99.3-2.9-99.7-95.6V156.6S742 71 851.5 63.5z" fill="#3F8BFD" p-id="7314"></path><path d="M722.5 63.5H433.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H719s-99.3-2.9-99.7-95.6V156.6S613 71 722.5 63.5z" fill="#3F8BFD" p-id="7315"></path><path d="M594.5 63.5H305.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H591s-99.3-2.9-99.7-95.6V156.6S485 71 594.5 63.5z" fill="#3F8BFD" p-id="7316"></path><path d="M465.5 63.5H176.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H462s-99.3-2.9-99.7-95.6V156.6S356 71 465.5 63.5z" fill="#3F8BFD" p-id="7317"></path></svg>
images/humidity.svg
@@ -1,3 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M12 2l-4.09 4.09L12 10.18l4.09-4.09L12 2zm0 16.36c-2.76 0-5-2.24-5-5 0-1.38.56-2.63 1.46-3.54L12 6.27l3.54 3.55c.9.9 1.46 2.16 1.46 3.54 0 2.76-2.24 5-5 5z" fill="currentColor"/>
</svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1754642042730" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6293" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M738.844 841.58c-113.108 0-204.8-91.692-204.8-204.8 0-163.161 143.268-310.37 190.135-354.163 0.137 0.137 0.289 0.259 0.431 0.393a19.936 19.936 0 0 1 29.2-0.292C800.981 326.287 943.644 471.7 943.644 636.78c0 113.108-91.692 204.8-204.8 204.8z m14.076-476.424c-0.021 0.02-0.044 0.036-0.065 0.056a16.955 16.955 0 0 0-27.02 0c-0.15-0.138-0.311-0.264-0.457-0.406C689.331 404.651 593.349 521.52 593.349 636.2c0 80.244 65.141 145.294 145.5 145.294S884.344 716.443 884.344 636.2c0-116.98-94.925-231.377-131.424-271.044z m5.424 367.344h-4a110 110 0 0 1-105.54-141h0.471a29.5 29.5 0 0 1 57.069 10.5c0 2.724-2 9.086-2 20.5a50 50 0 0 0 50 50c1.348 0 2.679-0.069 4-0.174v0.174a30 30 0 0 1 0 60z m-358 43a140.354 140.354 0 0 0 29-3.033v0.184c0.987-0.1 1.987-0.151 3-0.151a29.984 29.984 0 0 1 4 59.7v0.059a201.146 201.146 0 0 1-36 3.241c-110.457 0-200-89.543-200-200a200.472 200.472 0 0 1 5.225-45.528 29.982 29.982 0 1 1 59.325 8.528h0.4a140.077 140.077 0 0 0 135.05 177z m173-443a29.95 29.95 0 0 1-25.286-13.9c-0.121 0.157-0.255 0.3-0.368 0.466-51.356-75.812-106.381-131.477-132.256-156.466-0.14 0.161-0.3-0.695-0.445-0.538a17.964 17.964 0 0 0-29.292 0c-0.088-0.095-0.187-0.18-0.274-0.278C330.176 216.364 140.344 419.6 140.344 635.5c0 143.594 116.406 260 260 260a258.778 258.778 0 0 0 147.6-45.952 29.972 29.972 0 1 1 38.88 45.552c0.069 0.094 0.131 0.193 0.2 0.285a318.466 318.466 0 0 1-186.68 60.115c-176.731 0-320-143.269-320-320 0-264.941 241.8-503 305.017-560.713 0.08 0.078 0.169 0.145 0.249 0.222a19.931 19.931 0 0 1 28.46-1.029c0.085-0.093 0.181-0.177 0.265-0.272 31.707 28.469 111.748 104.84 182.017 209.046l-0.22 0.266a29.977 29.977 0 0 1-22.788 49.48z" fill="#2c2c2c" p-id="6294"></path></svg>
images/light.svg
New file
@@ -0,0 +1 @@
 <svg t="1754642435570" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9532" width="200" height="200"><path d="M272.242939 508.6016c0-131.954311 106.96108-238.927671 238.915391-238.927671s238.915391 106.97336 238.915391 238.927671c0 131.953288-106.960057 238.902088-238.915391 238.902088S272.242939 640.554888 272.242939 508.6016z" p-id="9533"></path><path d="M491.401358 71.137177l39.515992 0 0 138.309042-39.515992 0 0-138.309042Z" p-id="9534"></path><path d="M491.401358 813.174364l39.515992 0 0 138.306996-39.515992 0 0-138.306996Z" p-id="9535"></path><path d="M813.028543 488.843604l138.309042 0 0 39.517015-138.309042 0 0-39.517015Z" p-id="9536"></path><path d="M70.980099 488.843604l138.309042 0 0 39.517015-138.309042 0 0-39.517015Z" p-id="9537"></path><path d="M700.967908 123.177776l34.218191 19.756461-69.151451 119.770314-34.218191-19.756461 69.151451-119.770314Z" p-id="9538"></path><path d="M295.011502 905.379369 260.795213 885.619326 329.949222 765.833149 364.165512 785.593192Z" p-id="9539"></path><path d="M343.10894 259.768325 273.96721 139.983171 308.184523 120.224152 377.325229 240.009306Z" p-id="9540"></path><path d="M714.133162 902.382105 644.978129 782.609231 679.195441 762.850212 748.350474 882.622062Z" p-id="9541"></path><path d="M139.85616 274.093527l119.752939 69.163235-19.759901 34.213353-119.752939-69.163235 19.759901-34.213353Z" p-id="9542"></path><path d="M782.460148 645.112992l119.7712 69.151963-19.756461 34.218191-119.7712-69.151963 19.756461-34.218191Z" p-id="9543"></path><path d="M139.851677 748.506529 120.092657 714.290239 239.877811 645.147486 259.637854 679.364799Z" p-id="9544"></path><path d="M882.501028 274.14162l19.760412 34.218191-119.772086 69.166305-19.760412-34.218191 119.772086-69.166305Z" p-id="9545"></path></svg>
images/mixing.svg
New file
@@ -0,0 +1 @@
<svg t="1755143222063" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20253" width="200" height="200"><path d="M479.418182 1010.036364l-232.727273-256-13.963636-32.581819V46.545455l46.545454-46.545455h465.454546l46.545454 46.545455v674.90909l-13.963636 32.581819-232.727273 256h-65.163636zM325.818182 707.490909l186.181818 204.8 186.181818-204.8V93.090909H325.818182v614.4z" fill="#2c2c2c" p-id="20254"></path><path d="M282.763636 626.455273l41.611637-83.316364 412.16 206.103273-41.658182 83.269818zM282.763636 393.728l41.611637-83.316364 412.16 206.103273-41.658182 83.269818zM282.763636 161.000727l41.611637-83.316363 412.16 206.103272-41.611637 83.269819z" fill="#2c2c2c" p-id="20255"></path></svg>
images/no-data.svg
New file
@@ -0,0 +1,6 @@
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
  <circle cx="60" cy="60" r="50" stroke="#E5E5E5" stroke-width="2"/>
  <path d="M40 40L80 80" stroke="#E5E5E5" stroke-width="2" stroke-linecap="round"/>
  <path d="M80 40L40 80" stroke="#E5E5E5" stroke-width="2" stroke-linecap="round"/>
  <text x="60" y="100" text-anchor="middle" fill="#999" font-size="12">暂无数据</text>
</svg>
images/one.svg
New file
@@ -0,0 +1,2 @@
<svg t="1754907458715" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11307" width="200" height="200"><path d="M658.5 63.5H369.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H655s-99.3-2.9-99.7-95.6V156.6S549 71 658.5 63.5z" fill="#3F8BFD" p-id="11308"></path></svg>
images/pump.svg
New file
@@ -0,0 +1 @@
<svg t="1755142945165" class="icon" viewBox="0 0 1031 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9443" width="200" height="200"><path d="M511.853714 943.177143a431.177143 431.177143 0 1 1 0-862.354286 431.177143 431.177143 0 0 1 0 862.354286z m0 79.798857a510.976 510.976 0 1 0 0-1021.952 510.976 510.976 0 0 0 0 1021.952z" fill="#2c2c2c" p-id="9444"></path><path d="M471.917714 272.457143c0-8.777143 7.168-15.945143 16.018286-15.945143h47.908571c8.777143 0 15.945143 7.168 15.945143 15.945143v479.085714c0 8.777143-7.168 15.945143-15.945143 15.945143H487.862857a15.945143 15.945143 0 0 1-16.018286-15.945143v-479.085714z" fill="#2c2c2c" p-id="9445"></path><path d="M751.396571 472.064c8.777143 0 15.945143 7.168 15.945143 16.018286v47.908571c0 8.777143-7.168 15.945143-15.945143 15.945143h-479.085714a15.945143 15.945143 0 0 1-15.945143-15.945143v-47.908571c0-8.850286 7.168-16.018286 15.945143-16.018286h479.085714z" fill="#2c2c2c" p-id="9446"></path></svg>
images/rainfall.svg
New file
@@ -0,0 +1 @@
<svg t="1754643083996" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13658" width="200" height="200"><path d="M772.338983 138.847458a251.661017 251.661017 0 0 0-37.402034 2.776949A321.084746 321.084746 0 0 0 156.20339 247.842712 199.59322 199.59322 0 0 0 0 442.576271a199.59322 199.59322 0 0 0 199.59322 199.593221h572.745763a251.661017 251.661017 0 0 0 0-503.322034z m0 407.864406H199.59322a104.135593 104.135593 0 0 1-22.823051-205.754576l58.576272-13.016949 13.624406-58.402712a225.627119 225.627119 0 0 1 406.823051-74.456949l33.670509 49.811525 59.530847-8.677966A162.538305 162.538305 0 0 1 772.338983 234.305085a156.20339 156.20339 0 1 1 0 312.406779zM112.813559 694.237288h69.423729v190.915254h-69.423729zM295.050847 754.983051h69.423729v190.915254h-69.423729zM477.288136 833.084746h69.423728v190.915254h-69.423728zM659.525424 763.661017h69.423729v190.915254h-69.423729zM841.762712 694.237288h69.423729v190.915254h-69.423729z" p-id="13659"></path></svg>
images/refresh.svg
New file
@@ -0,0 +1 @@
<svg t="1754968007359" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6420" id="mx_n_1754968007360" width="200" height="200"><path d="M512 888c-13.6 0-24-10.4-24-24s10.4-24 24-24c180.8 0 328-147.2 328-328 0-83.2-31.2-162.4-88-224-8.8-9.6-8-24.8 1.6-33.6s24.8-8 33.6 1.6c64.8 70.4 100.8 161.6 100.8 256 0 207.2-168.8 376-376 376zM256.8 778.4c-6.4 0-12.8-2.4-17.6-7.2C172.8 700.8 136 608.8 136 512c0-207.2 168.8-376 376-376 13.6 0 24 10.4 24 24s-10.4 24-24 24c-180.8 0-328 147.2-328 328 0 84 32 164.8 90.4 225.6 8.8 9.6 8.8 24.8-0.8 33.6-4.8 4.8-11.2 7.2-16.8 7.2z" fill="#ffffff" p-id="6421"></path><path d="M428 316c-4.8 0-8.8-1.6-12.8-4-11.2-7.2-14.4-21.6-7.2-32.8l84-132c7.2-11.2 21.6-14.4 32.8-7.2 11.2 7.2 14.4 21.6 7.2 32.8L448 304.8c-4 7.2-12 11.2-20 11.2zM513.6 886.4c-4.8 0-8.8-1.6-12.8-4-11.2-7.2-14.4-21.6-7.2-32.8l84-132c7.2-11.2 21.6-14.4 32.8-7.2 11.2 7.2 14.4 21.6 7.2 32.8l-84 132c-4 7.2-12 11.2-20 11.2z" fill="#ffffff" p-id="6422"></path></svg>
images/settings-time.svg
New file
@@ -0,0 +1 @@
<svg t="1755143164825" class="icon" viewBox="0 0 1026 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17133" width="200" height="200"><path d="M512 352c42.7 0 82.9 16.6 113.1 46.9C655.4 429.1 672 469.3 672 512s-16.6 82.9-46.9 113.1C594.9 655.4 554.7 672 512 672s-82.9-16.6-113.1-46.9C368.6 594.9 352 554.7 352 512s16.6-82.9 46.9-113.1S469.3 352 512 352m0-64c-123.7 0-224 100.3-224 224s100.3 224 224 224 224-100.3 224-224-100.3-224-224-224z" p-id="17134"></path><path d="M658.7 91.7c2.6 0 5.2 0.3 7.8 1 22.7 5.7 47.1 15.8 70.6 29.4 23.5 13.6 44.5 29.6 60.8 46.4 8.4 8.7 11.2 21.2 7.4 32.7-17.6 53-15.3 99.3 6.8 137.5s61 63.4 115.7 74.7c11.9 2.4 21.3 11.2 24.6 22.7 6.4 22.5 9.8 48.7 9.8 75.9 0 27.2-3.4 53.4-9.8 75.9-3.3 11.6-12.8 20.3-24.6 22.7-54.7 11.2-93.6 36.4-115.7 74.7-22.1 38.3-24.4 84.6-6.8 137.5 3.8 11.5 1 24-7.4 32.7-16.2 16.8-37.3 32.9-60.8 46.4-23.5 13.6-47.9 23.7-70.6 29.4-2.6 0.6-5.2 1-7.8 1-9.2 0-18-4-24.2-10.9-37.1-41.7-78.3-62.9-122.5-62.9s-85.4 21.2-122.5 62.9c-6.2 6.9-15 10.9-24.2 10.9-2.6 0-5.2-0.3-7.8-1-22.7-5.7-47.1-15.8-70.6-29.4-23.5-13.6-44.5-29.6-60.8-46.4-8.4-8.7-11.2-21.2-7.4-32.7 17.6-53 15.3-99.3-6.8-137.5-22.1-38.3-61-63.4-115.7-74.7-11.9-2.4-21.3-11.2-24.6-22.7-6.4-22.5-9.8-48.7-9.8-75.9 0-27.2 3.4-53.4 9.8-75.9 3.3-11.6 12.8-20.3 24.6-22.7 54.7-11.2 93.6-36.4 115.7-74.7s24.4-84.6 6.8-137.5c-3.8-11.5-1-24 7.4-32.7 16.2-16.8 37.3-32.9 60.8-46.4 23.5-13.6 47.9-23.7 70.6-29.4 2.6-0.6 5.2-1 7.8-1 9.2 0 18 4 24.2 10.9 37.1 41.7 78.3 62.9 122.5 62.9s85.4-21.2 122.5-62.9c6.2-6.9 15-10.9 24.2-10.9m0-64c-27.2 0-53.5 11.5-72 32.4-24.5 27.6-49.6 41.4-74.7 41.4s-50.1-13.8-74.7-41.4c-18.5-20.9-44.9-32.4-72-32.4-7.8 0-15.6 0.9-23.3 2.9-57.9 14.4-120.5 50.6-161.9 93.5-24.9 25.8-33.4 63.3-22.1 97.3 23.3 70.1-2.3 114.5-74.7 129.3-35.1 7.2-63.3 33.3-73.2 67.8-16.4 57.3-16.4 129.6 0 187 9.9 34.5 38.1 60.6 73.2 67.8 72.3 14.9 97.9 59.3 74.7 129.3-11.3 34.1-2.8 71.5 22.1 97.3 41.4 42.9 104.1 79 161.9 93.5 7.7 1.9 15.5 2.9 23.3 2.9 27.2 0 53.5-11.5 72-32.4 24.5-27.6 49.6-41.4 74.7-41.4s50.1 13.8 74.7 41.4c18.5 20.9 44.9 32.4 72 32.4 7.8 0 15.6-0.9 23.3-2.9 57.9-14.4 120.5-50.6 161.9-93.5 24.9-25.8 33.4-63.3 22.1-97.3-23.3-70.1 2.3-114.5 74.7-129.3 35.1-7.2 63.4-33.3 73.2-67.8 16.4-57.3 16.4-129.6 0-187-9.9-34.5-38.1-60.6-73.2-67.8-72.3-14.9-97.9-59.3-74.7-129.3 11.3-34.1 2.8-71.5-22.1-97.3C802.5 81.2 739.9 45 682 30.6c-7.7-2-15.5-2.9-23.3-2.9z" p-id="17135"></path></svg>
images/settings.svg
New file
@@ -0,0 +1 @@
<svg t="1755143115164" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15966" width="200" height="200"><path d="M927.1 566.2c-2.4 13.9-4.8 27.9-7.1 41.8-18 108.3-71.1 195.7-157.3 263.3-7.9 6.2-15.8 12.3-23.7 18.5-1 0.8-2.1 1.5-4.2 3.1L580.3 697.2c65-38.8 99-95.8 99.2-172.9 16.4 2.2 30.3 3.9 44.2 5.9l195.9 28.2c2.5 0.4 5.1 0.1 7.7 0.1-0.2 2.5-0.2 5.1-0.2 7.7zM747.6 774.4c40.2-41.4 67.7-89 83.2-145-28.2-4.1-55.2-7.9-82.8-11.9-11.1 34.3-28.8 63.9-52.6 89.9 17.7 22.7 34.7 44.5 52.2 67zM528.9 127.2c19.5 2.5 39.1 4.6 58.5 7.8 40.4 6.7 78.2 21.8 116.3 38-30.4 76.7-60.5 152.9-91 230.1-32.9-12.5-64.5-27.4-100.4-27.4-36.1 0-67.8 14.4-101 27.8-30.5-76.6-60.8-152.7-91.8-230.4 21.3-8.2 41.7-16.9 62.6-24 33.8-11.6 68.6-18.2 104.3-20.1 3.2-0.2 6.3-1 9.5-1.6 10.9-0.2 22-0.2 33-0.2z m-100.4 93.7c10.4 27.2 20.3 53 29.8 77.7 18.7-1.5 36.1-4 53.4-4 17.3 0 34.7 2.5 52.8 4 10-25 20.2-50.8 30.9-77.5-55.8-14.2-110.6-14.4-166.9-0.2zM441.8 697.8c-51.4 65.1-102.3 129.5-153.2 194C170.9 811.9 107.8 701.4 98 559.3c80-11.9 160.1-23.8 241.3-35.9 5.4 34.9 8.8 69.6 27.1 100.6 18.3 31.1 47.2 51 75.4 73.8z m-249-68.3c15.5 55.8 42.8 103.5 82.9 144.9 17.5-22.9 34.3-44.9 51.3-67.1-18.9-20.8-34-43.3-44.5-68.6-2.8-6.8-4-16.5-9-19.5-5.2-3-14.3 0.5-21.6 1.6-19.4 2.7-38.8 5.7-59.1 8.7zM511.4 665.7c-68.6 0-124.2-55.4-124.4-123.8-0.1-68.7 56.2-125.1 124.7-124.7 68.4 0.3 124 56.3 123.9 124.6 0 68.4-55.6 123.8-124.2 123.9z m41.2-124c0-23-18.2-41.5-41.1-41.5-22.9-0.1-41.3 18.3-41.3 41.3-0.1 23 18.2 41.6 41.1 41.7 22.7 0 41.2-18.6 41.3-41.5z" p-id="15967"></path></svg>
images/temperature.svg
@@ -1,3 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M15 13V5c0-1.66-1.34-3-3-3S9 3.34 9 5v8c-1.21.91-2 2.37-2 4 0 2.76 2.24 5 5 5s5-2.24 5-5c0-1.63-.79-3.09-2-4zm-4-8c0-.55.45-1 1-1s1 .45 1 1h-2v1h2v1h-2v1h2v4.51c-.6-.29-1.29-.51-2-.51s-1.4.22-2 .51V5z" fill="currentColor"/>
</svg>
<svg t="1754642365274" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7432" width="200" height="200"><path d="M692.029187 551.06339V179.1972c0-98.54246-83.1987-179.1972-184.701114-179.1972S322.626959 80.65474 322.626959 179.1972v380.17006c-53.77516 49.023234-87.67863 118.39815-87.67863 195.83694 0 148.429681 124.046062 268.7958 277.051671 268.7958s277.051671-120.35012 277.051671-268.7958c0-81.790722-37.79141-154.87758-97.022484-204.14081zM512 969.168857c-121.710098 0-220.684552-95.9985-220.684552-214.092655 0-59.487071 24.815612-114.926204 69.886908-155.885564l17.791722-16.127748v-403.993688c0-68.686927 57.5991-124.510055 128.333995-124.510054s128.333995 55.839128 128.333995 124.510054v397.065796l19.727692 16.383744c49.103233 40.815362 77.294792 100.046437 77.294792 162.55746 0 118.078155-98.974454 214.092655-220.684552 214.092655z m106.638334-335.066765l-39.359385-32.767488V179.069202c0-37.807409-32.991485-69.822909-71.998875-69.822909s-71.998875 31.9995-71.998875 69.822909v21.295667h46.895267v33.391479H435.361197v53.935157h46.895268v33.391478H435.361197v53.935157h46.895268v33.391479H435.361197V462.392775h46.895268v33.391478H435.361197v110.894268l-35.583444 32.383494c-33.599475 30.623522-52.095186 71.822878-52.095186 116.062186 0 87.998625 73.59885 159.405509 164.317433 159.405509s164.317433-71.582882 164.317433-159.405509c0-46.559273-21.055671-90.654584-57.679099-121.022109zM512 878.06628c-69.886908 0-126.766019-55.199138-126.766019-122.990078 0-34.031468 14.287777-65.90297 40.255371-89.470602l47.407259-43.199325v-66.686958h68.798925v62.399025l52.47918 43.599319c28.319558 23.567632 44.543304 57.5991 44.543304 93.374541 0.047999 67.774941-56.831112 122.974079-126.71802 122.974078z" fill="#2c2c2c" p-id="7433"></path></svg>
images/three.svg
New file
@@ -0,0 +1 @@
<svg t="1754961266822" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7105" width="200" height="200"><path d="M786.5 63.5H497.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H783s-99.3-2.9-99.7-95.6V156.6S677 71 786.5 63.5z" fill="#3F8BFD" p-id="7106"></path><path d="M658.5 63.5H369.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H655s-99.3-2.9-99.7-95.6V156.6S549 71 658.5 63.5z" fill="#3F8BFD" p-id="7107"></path><path d="M529.5 63.5H240.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H526s-99.3-2.9-99.7-95.6V156.6S420 71 529.5 63.5z" fill="#3F8BFD" p-id="7108"></path></svg>
images/timer.svg
New file
@@ -0,0 +1 @@
<svg t="1755143047361" class="icon" viewBox="0 0 1086 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12575" width="200" height="200"><path d="M814.007218 542.06918a271.03459 271.03459 0 1 1 271.03459-271.03459 271.03459 271.03459 0 0 1-271.03459 271.03459z m150.574772-271.03459h-120.459817V120.459818a30.114954 30.114954 0 0 0-60.229909 0v180.689726a30.114954 30.114954 0 0 0 30.114954 30.114955h150.574772a30.114954 30.114954 0 0 0 0-60.229909z m-480.333523 29.151276c-9.636785 0.331264-19.87587 0.662529-29.211506 1.054023-42.763235-1.535863-81.912676-1.867127-120.459817-4.607588a2329.994024 2329.994024 0 0 1-120.459818-12.256786 711.947638 711.947638 0 0 1-126.181659-26.772195A217.158936 217.158936 0 0 1 18.370122 224.89848a4.216094 4.216094 0 0 1-1.204598-0.993794 32.614496 32.614496 0 0 1 0-57.429218 179.545358 179.545358 0 0 1 51.195423-26.62162 587.633106 587.633106 0 0 1 108.112686-27.555183 1456.961495 1456.961495 0 0 1 75.287386-11.052188c26.50116-3.011495 53.303469-4.938853 80.105779-6.92644 52.70117-3.975174 105.40234-4.637703 158.103511-3.523449 15.057477 0.30115 30.114954 1.445518 44.871282 2.168276A329.969556 329.969556 0 0 0 482.742719 271.03459c0 9.84759 0.602299 19.51449 1.505748 29.151276zM1.204598 273.805166v-2.379082c7.528739 4.366668 13.25058 8.010578 19.574721 11.262993a436.215115 436.215115 0 0 0 96.970153 35.144152 1004.725225 1004.725225 0 0 0 108.413836 20.688974 1630.032138 1630.032138 0 0 0 244.53343 14.545523c7.528739 0 14.756328-0.843219 22.586216-1.023909a329.939441 329.939441 0 0 0 120.459817 182.436394c-28.308057 2.620001-56.616114 4.999082-84.924171 6.022991q-60.982783 2.168277-121.965566 1.264828a1453.558505 1453.558505 0 0 1-91.850611-4.938852 1336.200528 1336.200528 0 0 1-81.611526-8.582762 685.054983 685.054983 0 0 1-165.63225-39.781855 271.03459 271.03459 0 0 1-41.859786-21.983917 52.430136 52.430136 0 0 1-21.682767-24.483458 49.990824 49.990824 0 0 1-3.312645-19.273571c0.602299-47.822548 0.30115-95.67521 0.301149-143.527873v-5.360461z m0.30115 238.480324c9.034486 4.878623 17.165524 9.697015 25.597711 13.913109a478.406166 478.406166 0 0 0 98.777051 34.029898 931.847035 931.847035 0 0 0 110.823032 20.026445c29.813805 3.643909 59.928759 6.022991 90.043714 8.673107a1620.184548 1620.184548 0 0 0 174.365586 3.824599c31.319553-0.602299 62.337956-2.348966 93.356358-5.119542s62.036806-6.203681 93.05521-10.480004a328.734843 328.734843 0 0 0 216.827671 12.377246q-0.451724 36.800474 0 73.600948a49.508985 49.508985 0 0 1-22.586215 41.829672 237.637105 237.637105 0 0 1-68.963246 33.12645 631.480479 631.480479 0 0 1-102.993144 24.483458c-33.427599 5.089427-67.156348 10.20897-100.885097 13.31081a1573.02453 1573.02453 0 0 1-196.951802 6.38437c-26.802309-0.903449-53.604619-1.535863-80.406929-3.523449a1577.722462 1577.722462 0 0 1-89.441414-9.215177c-28.006908-3.674024-55.712666-8.221383-83.117275-13.822764a412.996485 412.996485 0 0 1-120.760967-40.715418 88.447621 88.447621 0 0 1-30.717253-25.928976 34.300933 34.300933 0 0 1-6.324141-20.538399v-151.237301c0-1.565978 0.30115-3.011495 0.30115-4.999082z m0 240.919635c9.034486 4.878623 17.165524 9.697015 25.597711 13.913109a478.406166 478.406166 0 0 0 98.777051 34.029899 931.847035 931.847035 0 0 0 110.823032 20.026444c29.813805 3.643909 59.928759 6.022991 90.043714 8.673107a1620.184548 1620.184548 0 0 0 174.365586 3.824599c31.319553-0.602299 62.337956-2.348966 93.356358-5.119542 36.439095-3.28253 73.179339-7.167359 109.618435-12.648281 20.177019-3.011495 40.052889-6.56506 59.627609-10.871498 18.370122-4.035404 36.439095-8.793567 54.508068-14.425063 14.154029-4.547358 28.308057-9.6669 42.160936-15.509202 11.142533-4.697933 21.682767-10.299314 32.524151-15.960926 3.914944-1.867127 7.528739-3.764369 11.142533-5.631496v5.390577c0 48.364617-0.30115 96.729234 0.301149 145.063735a49.508985 49.508985 0 0 1-22.586215 41.829672 237.637105 237.637105 0 0 1-68.963246 33.12645 631.480479 631.480479 0 0 1-102.993144 24.483458c-33.427599 5.089427-67.156348 10.20897-100.885097 13.310809a1573.02453 1573.02453 0 0 1-196.951802 6.384371c-26.802309-0.903449-53.604619-1.535863-80.406929-3.52345a1577.722462 1577.722462 0 0 1-89.441414-9.215176c-28.006908-3.674024-55.712666-8.221383-83.117275-13.822764a412.996485 412.996485 0 0 1-120.760967-40.715418 88.447621 88.447621 0 0 1-30.717253-25.928976 34.300933 34.300933 0 0 1-6.324141-20.538399v-151.237301c0-1.475633 0.30115-2.921151 0.30115-4.908738z" p-id="12576"></path></svg>
images/two.svg
New file
@@ -0,0 +1,2 @@
<svg t="1754960228563" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11513" width="200" height="200"><path d="M720.5 63.5H431.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H717s-99.3-2.9-99.7-95.6V156.6S611 71 720.5 63.5z" fill="#3F8BFD" p-id="11514"></path><path d="M596.5 63.5H307.1s100.2 3.4 100.2 95.6v705.2s6.5 87.2-100.2 95.6H593s-99.3-2.9-99.7-95.6V156.6S487 71 596.5 63.5z" fill="#3F8BFD" p-id="11515"></path></svg>
images/uv.svg
New file
@@ -0,0 +1 @@
 <svg t="1754642405930" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8520" width="200" height="200"><path d="M186.907091 793.533872l-42.663111 42.663112a30.16282 30.16282 0 0 0 42.663111 42.663111l42.663111-42.663111a30.16282 30.16282 0 0 0-42.663111-42.663112zM835.983668 229.527539l42.663111-42.663111a30.16282 30.16282 0 0 0-42.663111-42.663111l-42.663111 42.663111a30.16282 30.16282 0 0 0 42.663111 42.663111z m-733.805516 248.555287h-68.260978a33.87451 33.87451 0 1 0 0 67.749021h68.260978A33.831847 33.831847 0 0 0 136.052662 511.957337a33.191901 33.191901 0 0 0-33.87451-33.874511z m409.565869-341.304891a34.130489 34.130489 0 0 0 33.917174-34.386468V34.130489a34.130489 34.130489 0 0 0-68.260978 0v68.260978a34.770436 34.770436 0 0 0 34.599783 34.13049zM188.95492 229.527539a30.16282 30.16282 0 0 0 42.663112-42.663111l-42.663112-42.663111a30.16282 30.16282 0 0 0-42.663111 42.663111zM512 887.392717a34.130489 34.130489 0 0 0-33.87451 34.429131v68.260978a33.87451 33.87451 0 0 0 67.791684 0v-68.260978A34.130489 34.130489 0 0 0 512 887.392717z m477.826848-409.309891h-68.260978a33.87451 33.87451 0 1 0 0 67.749021h68.260978a33.87451 33.87451 0 1 0 0-67.749021z m-153.032581 314.256479a30.16282 30.16282 0 0 0-42.663111 42.663111l42.663111 42.663112a30.16282 30.16282 0 0 0 42.663112-42.663112zM512 204.782935a307.174402 307.174402 0 1 0 307.174402 307.174402A307.174402 307.174402 0 0 0 512 204.782935z m-15.401383 356.364969a76.025665 76.025665 0 1 1-152.008666 0v-146.334472a16.425298 16.425298 0 0 1 32.850596 0v146.334472a43.132406 43.132406 0 0 0 86.264811 0v-146.334472a16.425298 16.425298 0 0 1 32.850596 0v146.334472z m180.72094-146.846429l-62.629448 207.982668a16.04133 16.04133 0 0 1-31.314724-1.535872c-0.511957 0.511957-63.141405-206.446796-63.141404-206.446796a16.254645 16.254645 0 0 1 31.314723-8.532622l42.108491 136.521956a5.2049 5.2049 0 0 0 6.655446 3.583701 6.228814 6.228814 0 0 0 3.583701-3.583701l42.108491-136.521956a16.254645 16.254645 0 0 1 31.272061 8.617948z" p-id="8521"></path></svg>
images/wind-arrow.svg
New file
@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M12 2L10 10H14L12 2Z" fill="#EB2F96"/>
  <path d="M12 22L14 14H10L12 22Z" stroke="#EB2F96" stroke-width="2" stroke-linecap="round"/>
</svg>
images/wind-direction.svg
New file
@@ -0,0 +1 @@
 <svg t="1754642528320" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12645" width="200" height="200"><path d="M519.723387 534.475706a19.438636 19.438636 0 0 0-19.438636 19.438636v450.559809a19.438636 19.438636 0 0 0 5.640675 13.79796 19.178297 19.178297 0 0 0 13.797961 5.727455h133.640621a19.525415 19.525415 0 0 0 13.79796-5.727455 19.091517 19.091517 0 0 0 5.640676-13.79796V553.827562a19.438636 19.438636 0 0 0-19.438636-19.438636h-34.104392V232.482613H798.37276v64.477261a19.351856 19.351856 0 0 0 29.244733 16.835247l164.187049-95.457586a19.525415 19.525415 0 0 0 0-33.757274l-164.187049-95.457587-3.210846-1.735592a18.39728 18.39728 0 0 0-6.508472-1.214915A19.525415 19.525415 0 0 0 798.37276 105.697582V173.559248H393.719372L99.710005 2.690168A19.265077 19.265077 0 0 0 89.990687 0H41.741216a19.438636 19.438636 0 0 0-19.438636 19.525415A21.087449 21.087449 0 0 0 23.430715 26.033887l60.745737 168.69959a19.351856 19.351856 0 0 1 0 13.277282l-60.745737 168.69959a19.351856 19.351856 0 0 0 18.223722 26.033887h48.33625a19.265077 19.265077 0 0 0 9.806098-2.603389l287.934793-167.658234h166.182981v301.906313z" p-id="12646"></path></svg>
images/wind-speed.svg
New file
@@ -0,0 +1 @@
 <svg t="1754642502403" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11563" width="200" height="200"><path d="M256 554.666667h-42.666667c-59.733333 0-106.666667-46.933333-106.666666-106.666667s46.933333-106.666667 106.666666-106.666667h42.666667c12.8 0 21.333333 8.533333 21.333333 21.333334s-8.533333 21.333333-21.333333 21.333333h-42.666667c-36.266667 0-64 27.733333-64 64s27.733333 64 64 64h42.666667c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 21.333333-21.333333 21.333334zM469.333333 896h-64c-59.733333 0-106.666667-46.933333-106.666666-106.666667s46.933333-106.666667 106.666666-106.666666h64c12.8 0 21.333333 8.533333 21.333334 21.333333s-8.533333 21.333333-21.333334 21.333333h-64c-36.266667 0-64 27.733333-64 64s27.733333 64 64 64h64c12.8 0 21.333333 8.533333 21.333334 21.333334s-8.533333 21.333333-21.333334 21.333333zM576 341.333333h-64c-59.733333 0-106.666667-46.933333-106.666667-106.666666s46.933333-106.666667 106.666667-106.666667h64c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 21.333333-21.333333 21.333334h-64c-36.266667 0-64 27.733333-64 64s27.733333 64 64 64h64c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 21.333333-21.333333 21.333333z" fill="#333333" p-id="11564"></path><path d="M853.333333 341.333333H512c-12.8 0-21.333333-8.533333-21.333333-21.333333s8.533333-21.333333 21.333333-21.333333h341.333333c12.8 0 21.333333 8.533333 21.333334 21.333333s-8.533333 21.333333-21.333334 21.333333zM896 554.666667H256c-12.8 0-21.333333-8.533333-21.333333-21.333334s8.533333-21.333333 21.333333-21.333333h640c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 21.333333-21.333333 21.333334zM725.333333 725.333333H469.333333c-12.8 0-21.333333-8.533333-21.333333-21.333333s8.533333-21.333333 21.333333-21.333333h256c12.8 0 21.333333 8.533333 21.333334 21.333333s-8.533333 21.333333-21.333334 21.333333z" fill="#333333" p-id="11565"></path></svg>
pages/home/home.js
@@ -61,7 +61,7 @@
          icon: 'error',
          duration: 2000
        });
        // 获取项目配置
        const projectConfig = PROJECT_CONFIG[currentProject];
        if (projectConfig) {
@@ -82,7 +82,7 @@
        return;
      }
    }
    // 已登录或不需要登录的项目,执行开阀操作
    wx.navigateTo({
      url: '/pages/waterIntake/waterIntake',
@@ -226,7 +226,7 @@
          const projectConfig = PROJECT_CONFIG[project];
          if (projectConfig) {
            getApp().globalData.tag = projectConfig.tag;
            // 根据项目是否需要登录,设置不同的userName
            if (projectConfig.needLogin === false) {
              // 不需要登录的项目,显示项目名称
@@ -359,7 +359,7 @@
            this.setData({
              isFromLogin: true
            });
            // 登录成功后刷新数据
            console.log('登录成功后刷新数据');
            this.initData();
@@ -373,7 +373,7 @@
    // 初始化处理
    if (fromLogin || this.data.isFromLogin) {
      console.log('onShow: 从登录页返回,不进行登录检查');
      // 如果是从登录页返回,重新加载数据
      this.initData();
    } else {
@@ -463,7 +463,7 @@
          icon: 'error',
          duration: 2000
        });
        // 获取项目配置
        const projectConfig = PROJECT_CONFIG[currentProject];
        if (projectConfig) {
@@ -484,7 +484,7 @@
        return;
      }
    }
    // 已登录或不需要登录的项目,执行查看记录操作
    wx.navigateTo({
      url: '/pages/valveList/valveList',
@@ -510,7 +510,7 @@
          icon: 'error',
          duration: 2000
        });
        // 获取项目配置
        const projectConfig = PROJECT_CONFIG[currentProject];
        if (projectConfig) {
@@ -529,9 +529,25 @@
          });
        }
        return;
      } else if (!PROJECT_CONFIG[currentProject].monitor) {
        // 未登录,显示提示并阻止操作
        wx.showToast({
          title: '当前项目不可用',
          icon: 'error',
          duration: 2000
        });
        return;
      }
    } else if (!PROJECT_CONFIG[currentProject].monitor) {
      // 未登录,显示提示并阻止操作
      wx.showToast({
        title: '当前项目不可用',
        icon: 'error',
        duration: 2000
      });
      return;
    }
    // 已登录或不需要登录的项目,跳转到综合站监测页面
    wx.navigateTo({
      url: '/pages/stationMonitor/stationMonitor',
@@ -596,7 +612,7 @@
          icon: 'error',
          duration: 2000
        });
        // 获取项目配置
        const projectConfig = PROJECT_CONFIG[currentProject];
        if (projectConfig) {
@@ -617,7 +633,7 @@
        return;
      }
    }
    // 已登录或不需要登录的项目,执行轮灌操作
    wx.navigateTo({
      url: '/pages/irrigation/irrigation',
@@ -882,7 +898,7 @@
          icon: 'error',
          duration: 2000
        });
        // 获取项目配置
        const projectConfig = PROJECT_CONFIG[currentProject];
        if (projectConfig) {
@@ -903,7 +919,7 @@
        return;
      }
    }
    // 已登录或不需要登录的项目,执行扫码操作
    const that = this;
    wx.scanCode({
@@ -1027,7 +1043,7 @@
            app.globalData.clientId = jsonObj.clientId || clientId;
            app.globalData.tag = jsonObj.tag;
            app.globalData.isLoggedIn = true;
            // 直接从userData设置用户信息
            if (jsonObj.clientName && jsonObj.phone) {
              this.setData({
@@ -1038,7 +1054,7 @@
              // 如果userData中没有用户信息,调用接口获取
              this.getUserDataBySession();
            }
            console.log("userData已加载:", userData);
          } catch (e) {
            console.error('userData解析失败:', e);
@@ -1056,14 +1072,14 @@
          app.globalData.isLoggedIn = true;
          this.getUserDataBySession();
        }
        // 无论如何都尝试获取开阀列表
        this.getOpenList();
      }).catch(err => {
        console.error('恢复登录状态失败:', err);
        this.getOpenList();
      });
      return;
    }
@@ -1526,7 +1542,7 @@
          // 此处不做跳转,注释掉原有代码
          // const projectInfo = PROJECT_CONFIG[currentProject];
          // const loginType = projectInfo?.loginType || 'code'; // 默认使用验证码登录
          // if (loginType === 'account') {
          //   // 账号密码登录
          //   wx.navigateTo({
@@ -1568,7 +1584,7 @@
        // 此处不做跳转,注释掉原有代码
        // const projectInfo = PROJECT_CONFIG[currentProject];
        // const loginType = projectInfo?.loginType || 'code'; // 默认使用验证码登录
        // if (loginType === 'account') {
        //   // 账号密码登录
        //   wx.navigateTo({
@@ -1660,7 +1676,7 @@
    const currentProject = getApp().globalData.selectedProject;
    if (currentProject && PROJECT_CONFIG[currentProject]) {
      const projectConfig = PROJECT_CONFIG[currentProject];
      if (!projectConfig.needLogin) {
        console.log('wxLogin: 当前项目不需要登录:', currentProject);
        // 不需要登录的项目,显示项目名称
@@ -1693,7 +1709,7 @@
                  // 未绑定账号,根据项目配置的loginType跳转到相应的登录页面
                  const projectInfo = PROJECT_CONFIG[this.data.selectedProject];
                  const loginType = projectInfo?.loginType || 'code'; // 默认使用验证码登录
                  if (loginType === 'account') {
                    // 账号密码登录
                    wx.navigateTo({
@@ -1753,7 +1769,7 @@
                // 未绑定账号,根据项目配置的loginType跳转到相应的登录页面
                const projectInfo = PROJECT_CONFIG[this.data.selectedProject];
                const loginType = projectInfo?.loginType || 'code'; // 默认使用验证码登录
                if (loginType === 'account') {
                  // 账号密码登录
                  wx.navigateTo({
@@ -1775,11 +1791,11 @@
            }).catch(error => {
              wx.hideLoading();
              console.error('登录请求失败:', error);
              if(error.code==="1003"){
              if (error.code === "1003") {
                // 未绑定账号,根据项目配置的loginType跳转到相应的登录页面
                const projectInfo = PROJECT_CONFIG[this.data.selectedProject];
                const loginType = projectInfo?.loginType || 'code'; // 默认使用验证码登录
                if (loginType === 'account') {
                  // 账号密码登录
                  wx.navigateTo({
@@ -1791,7 +1807,7 @@
                    url: `/pages/login/login?project=${this.data.selectedProject}&projectName=${projectInfo.displayName}`
                  });
                }
              }else{
              } else {
                wx.showToast({
                  title: '登录失败,请重试',
                  icon: 'none'
@@ -2063,7 +2079,7 @@
    const currentProject = app.globalData.selectedProject;
    if (currentProject && PROJECT_CONFIG[currentProject]) {
      const projectConfig = PROJECT_CONFIG[currentProject];
      if (!projectConfig.needLogin) {
        console.log('handleUserTap: 当前项目不需要登录:', currentProject);
        // 不需要登录的项目,显示项目名称
@@ -2072,10 +2088,10 @@
        });
        return;
      }
      // 根据项目配置的loginType决定跳转到哪个登录页面
      const loginType = projectConfig.loginType || 'code'; // 默认使用验证码登录
      if (loginType === 'account') {
        // 账号密码登录
        wx.navigateTo({
pages/stationMonitor/stationMonitor.js
@@ -1,5 +1,7 @@
// pages/stationMonitor/stationMonitor.js
const { get } = require('../../api/request.js');
const {
  get
} = require('../../api/request.js');
Page({
@@ -9,15 +11,120 @@
  data: {
    activeTab: 'weather', // 默认选中气象站
    cameraList: [],
    isLoading: false
    isLoading: false,
    // 气象站相关数据
    weatherStationList: [],
    selectedWeatherStationIndex: 0,
    currentWeatherStation: null,
    // 水肥机相关数据
    fertilizerStationList: [],
    selectedFertilizerStationIndex: 0,
    currentFertilizerStation: null,
    // 土壤墒情站相关数据
    soilStationList: [],
    selectedSoilStationIndex: 0,
    currentSoilStation: null,
    //摄像头相关
    accessToken: 'at.4l27eilo2x0euquw4yrhjxnz9kvr294l-2dp10mcwig-1nnzr8p-7wp71d2bk',
    hslUrl: '',
    // 设备信息
    deviceInfo: null,
    isRealDevice: false,
    deviceSpecificConfig: {
      videoHeight: 400,
      buttonHeight: 72,
      fontSize: 26
    }
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    // 检测设备类型和屏幕信息
    this.detectDeviceInfo();
    // 页面加载时获取摄像头信息
    this.getCameraList();
    // 获取所有设备信息(气象站、土壤墒情站、水肥机)
    this.getAllDeviceInfo();
  },
  /**
   * 检测设备信息
   */
  detectDeviceInfo() {
    try {
      const systemInfo = wx.getSystemInfoSync();
      console.log('设备信息:', systemInfo);
      // 检测是否为真机
      const isRealDevice = systemInfo.platform === 'android' || systemInfo.platform === 'ios';
      // 检测屏幕尺寸
      const screenWidth = systemInfo.screenWidth;
      const screenHeight = systemInfo.screenHeight;
      const pixelRatio = systemInfo.pixelRatio;
      // 检测微信版本
      const version = systemInfo.version;
      this.setData({
        deviceInfo: {
          platform: systemInfo.platform,
          isRealDevice: isRealDevice,
          screenWidth: screenWidth,
          screenHeight: screenHeight,
          pixelRatio: pixelRatio,
          version: version,
          model: systemInfo.model,
          system: systemInfo.system
        }
      });
      console.log('设备检测结果:', {
        isRealDevice,
        screenWidth,
        screenHeight,
        pixelRatio,
        version
      });
      // 根据设备信息调整布局
      this.adjustLayoutForDevice();
    } catch (error) {
      console.error('获取设备信息失败:', error);
    }
  },
  /**
   * 根据设备信息调整布局
   */
  adjustLayoutForDevice() {
    const { deviceInfo } = this.data;
    if (!deviceInfo) return;
    // 真机特殊处理
    if (deviceInfo.isRealDevice) {
      console.log('检测到真机,应用特殊优化');
      // 真机上可能需要调整一些参数
      this.setData({
        isRealDevice: true,
        // 可以根据设备信息调整其他参数
        deviceSpecificConfig: {
          videoHeight: deviceInfo.screenHeight < 700 ? 320 : 400,
          buttonHeight: deviceInfo.screenHeight < 700 ? 64 : 72,
          fontSize: deviceInfo.pixelRatio > 2 ? 24 : 26
        }
      });
    } else {
      console.log('检测到模拟器');
      this.setData({
        isRealDevice: false
      });
    }
  },
  /**
@@ -31,7 +138,28 @@
   * 生命周期函数--监听页面显示
   */
  onShow() {
    console.log('=== 页面显示 ===');
    console.log('当前页面数据:', {
      activeTab: this.data.activeTab,
      cameraList: this.data.cameraList,
      deviceInfo: this.data.deviceInfo,
      deviceSpecificConfig: this.data.deviceSpecificConfig
    });
    // 检查ezplayer组件的状态
    if (this.data.activeTab === 'camera') {
      console.log('摄像头页面激活,检查组件状态');
      this.data.cameraList.forEach(camera => {
        console.log(`摄像头 ${camera.name} 状态:`, {
          id: camera.id,
          online: camera.online,
          hslUrl: camera.hslUrl,
          isLoadingUrl: camera.isLoadingUrl,
          urlError: camera.urlError,
          isPlaying: camera.isPlaying
        });
      });
    }
  },
  /**
@@ -52,9 +180,11 @@
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {
    // 下拉刷新时重新获取摄像头列表
    // 下拉刷新时重新获取数据
    if (this.data.activeTab === 'camera') {
      this.getCameraList();
    } else if (this.data.activeTab === 'weather' || this.data.activeTab === 'soil' || this.data.activeTab === 'fertilizer') {
      this.getAllDeviceInfo();
    }
    wx.stopPullDownRefresh();
  },
@@ -82,11 +212,134 @@
    this.setData({
      activeTab: tab
    });
    // 如果切换到摄像头选项卡,确保有数据
    if (tab === 'camera' && this.data.cameraList.length === 0) {
      this.getCameraList();
    }
    // 如果切换到气象站选项卡,确保有数据
    if (tab === 'weather' && this.data.weatherStationList.length === 0) {
      this.getAllDeviceInfo();
    }
    // 如果切换到土壤墒情站选项卡,确保有数据
    if (tab === 'soil' && this.data.soilStationList.length === 0) {
      this.getAllDeviceInfo();
    }
    // 如果切换到水肥机选项卡,确保有数据
    if (tab === 'fertilizer' && this.data.fertilizerStationList.length === 0) {
      this.getAllDeviceInfo();
    }
  },
  /**
   * 获取所有设备信息(气象站、土壤墒情站、水肥机)
   */
  getAllDeviceInfo() {
    const app = getApp();
    // 检查登录状态
    if (!app.globalData.isLoggedIn) {
      wx.showToast({
        title: '请先登录',
        icon: 'error'
      });
      return;
    }
    console.log('开始调用 /wx/mqtt/allSimple 接口获取设备信息');
    get({url: '/wx/mqtt/allSimple'})
      .then(response => {
        console.log('设备信息接口返回数据:', response);
        if (response.success && response.code === '0001') {
          const content = response.content;
          // 处理气象站数据
          if (content.weathers && content.weathers.length > 0) {
            const weatherStations = content.weathers.map(item => ({
              id: item.id,
              name: item.name,
              no: item.no,
              online: true, // 默认在线
              location: '甘肃省民勤县', // 默认位置
              lastUpdate: new Date().toLocaleString()
            }));
            this.setData({
              weatherStationList: weatherStations
            });
            // 默认选择第一个气象站
            if (weatherStations.length > 0) {
              this.selectWeatherStation(0);
            }
          }
          // 处理土壤墒情站数据
          if (content.soils && content.soils.length > 0) {
            const soilStations = content.soils.map(item => ({
              id: item.id,
              name: item.name,
              no: item.no,
              online: true, // 默认在线
              location: '甘肃省民勤县', // 默认位置
              lastUpdate: new Date().toLocaleString()
            }));
            this.setData({
              soilStationList: soilStations
            });
            // 默认选择第一个土壤墒情站
            if (soilStations.length > 0) {
              this.selectSoilStation(0);
            }
          }
          // 处理水肥机数据
          if (content.manures && content.manures.length > 0) {
            const fertilizerStations = content.manures.map(item => ({
              id: item.id,
              name: item.name,
              no: item.no,
              online: true // 默认在线
            }));
            this.setData({
              fertilizerStationList: fertilizerStations
            });
            // 默认选择第一个水肥机
            if (fertilizerStations.length > 0) {
              this.selectFertilizerStation(0);
            }
          }
          console.log('设备信息处理完成:', {
            weatherStations: this.data.weatherStationList,
            soilStations: this.data.soilStationList,
            fertilizerStations: this.data.fertilizerStationList
          });
        } else {
          console.error('获取设备信息失败:', response.msg);
          wx.showToast({
            title: response.msg || '获取设备信息失败',
            icon: 'none'
          });
        }
      })
      .catch(error => {
        console.error('调用设备信息接口失败:', error);
        wx.showToast({
          title: '获取设备信息失败',
          icon: 'error'
        });
      });
  },
  /**
@@ -94,7 +347,7 @@
   */
  getCameraList() {
    const app = getApp();
    // 检查登录状态
    if (!app.globalData.isLoggedIn) {
      wx.showToast({
@@ -108,115 +361,95 @@
      isLoading: true
    });
    // 模拟接口返回数据
    setTimeout(() => {
      const mockResponse = {
        "code": "0001",
        "content": {
          "itemTotal": 4,
          "obj": [
            {
              "id": "2025070715040300007",
              "name": "民勤01",
              "videoUrl4PcLive": "https://open.ys7.com/console/jssdk/pc.html?url=ezopen://open.ys7.com/FX6737162/1.live&accessToken=at.2o04glgs0q36cjugbvddqujz7tqrghx1-1ovr6lmf3k-03pij3c-304ziif7e&themeId=pcLive&env=&date=",
              "videoUrl4Security": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056878/1.live&themeId=security&date=",
              "videoUrl4Simple": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056878/1.live&themeId=simple&date=",
              "videoUrl4Standard": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056878/1.live&themeId=standard&date="
            },
            {
              "id": "2025070715040300008",
              "name": "民勤02",
              "videoUrl4PcLive": "https://open.ys7.com/console/jssdk/pc.html?url=ezopen://open.ys7.com/FY4056879/1.live&accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&themeId=pcLive&env=&date=",
              "videoUrl4Security": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056879/1.live&themeId=security&date=",
              "videoUrl4Simple": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056879/1.live&themeId=simple&date=",
              "videoUrl4Standard": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056879/1.live&themeId=standard&date="
            },
            {
              "id": "2025070715040300009",
              "name": "民勤03",
              "videoUrl4PcLive": "https://open.ys7.com/console/jssdk/pc.html?url=ezopen://open.ys7.com/FY4056880/1.live&accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&themeId=pcLive&env=&date=",
              "videoUrl4Security": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056880/1.live&themeId=security&date=",
              "videoUrl4Simple": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056880/1.live&themeId=simple&date=",
              "videoUrl4Standard": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056880/1.live&themeId=standard&date="
            },
            {
              "id": "2025070715040300010",
              "name": "民勤04",
              "videoUrl4PcLive": "https://open.ys7.com/console/jssdk/pc.html?url=ezopen://open.ys7.com/FY4056881/1.live&accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&themeId=pcLive&env=&date=",
              "videoUrl4Security": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056881/1.live&themeId=security&date=",
              "videoUrl4Simple": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056881/1.live&themeId=simple&date=",
              "videoUrl4Standard": "https://open.ys7.com/console/jssdk/pc.html?accessToken=at.87a8u4z04s3gom0o6i0cpgz35kuhu8xh-67xrfkiy90-0nnbl6z-r0v9mckp3&url=ezopen://open.ys7.com/FY4056881/1.live&themeId=standard&date="
            }
          ],
          "pageCurr": 1,
          "pageSize": 4,
          "pageTotal": 1
        },
        "msg": "请求成功",
        "success": true
      };
    // 调用真实接口获取摄像头列表
    this.getVideoListFromApi();
  },
      console.log('模拟接口返回数据:', mockResponse);
      if (mockResponse.success && mockResponse.code === '0001') {
        // 处理返回的摄像头数据
        const cameraList = mockResponse.content.obj.map(item => {
          // 从萤石云URL中提取设备信息并生成RTMP地址
          let rtmpUrl = '';
          if (item.videoUrl4PcLive) {
            // 提取设备序列号和通道号
            const ezopenMatch = item.videoUrl4PcLive.match(/ezopen:\/\/open\.ys7\.com\/([^\/]+)\/(\d+)\.live/);
            const tokenMatch = item.videoUrl4PcLive.match(/accessToken=([^&]+)/);
  /**
   * 从接口获取视频列表
   */
  getVideoListFromApi() {
    console.log('开始调用 /wx/video/all 接口获取视频列表');
    get({url:'/wx/video/all'} )
      .then(response => {
        console.log('接口返回数据:', response);
        if (response.success && response.code === '0001') {
          // 处理返回的摄像头数据
          const cameraList = response.content.map(item => {
            // 根据devNo生成RTMP URL
            const channelNo = 1; // 默认通道号
            const rtmpUrl = `rtmp://open.ys7.com/${item.devNo}/${channelNo}/live`;
            
            if (ezopenMatch && tokenMatch) {
              const deviceSerial = ezopenMatch[1]; // 设备序列号
              const channelNo = ezopenMatch[2];    // 通道号
              const accessToken = tokenMatch[1];   // 访问令牌
              // 生成RTMP地址
              rtmpUrl = `rtmp://open.ys7.com:1935/live/${deviceSerial}/${channelNo}?accessToken=${accessToken}`;
              // 备用HLS地址
              const hlsUrl = `https://open.ys7.com:443/live/${deviceSerial}/${channelNo}.m3u8?accessToken=${accessToken}`;
              console.log('生成的RTMP地址:', rtmpUrl);
              console.log('生成的HLS地址:', hlsUrl);
            }
          }
            console.log(`摄像头 ${item.name} 生成RTMP URL:`, rtmpUrl);
            return {
              id: item.id,
              name: item.name,
              online: true, // 默认在线,实际项目中可能需要额外的状态检查
              lastUpdate: new Date().toLocaleString(), // 当前时间作为最后更新时间
              isPlaying: false, // 视频播放状态
              hslUrl: rtmpUrl, // 使用生成的RTMP URL
              deviceSerial: item.devNo, // 使用接口返回的devNo
              isLoadingUrl: false, // URL加载状态
              urlError: false, // URL获取错误状态
              autoPlay: false, // 自动播放控制
              // 新增字段
              lng: item.lng, // 经度
              lat: item.lat, // 纬度
              accessToken: item.accessToken // 设备专用accessToken
            };
          });
          this.setData({
            cameraList: cameraList,
            isLoading: false
          });
          console.log('处理后的摄像头列表:', cameraList);
          
          return {
            id: item.id,
            name: item.name,
            online: true, // 默认在线,实际项目中可能需要额外的状态检查
            thumbnail: '/images/camera-thumb1.jpg', // 默认缩略图
            lastUpdate: new Date().toLocaleString(), // 当前时间作为最后更新时间
            isPlaying: false, // 视频播放状态
            rtmpUrl: rtmpUrl, // RTMP流地址
            videoUrl4PcLive: item.videoUrl4PcLive, // 原始PC播放地址
            videoUrl4Security: item.videoUrl4Security,
            videoUrl4Simple: item.videoUrl4Simple,
            videoUrl4Standard: item.videoUrl4Standard
          };
        });
        this.setData({
          cameraList: cameraList,
          isLoading: false
        });
        console.log('处理后的摄像头列表:', cameraList);
      } else {
        console.error('获取摄像头列表失败:', mockResponse.msg);
          // 由于现在直接使用RTMP URL,不需要再调用萤石云API获取播放地址
          // this.batchGetHlsUrls(cameraList);
        } else {
          console.error('获取摄像头列表失败:', response.msg);
          this.setData({
            isLoading: false
          });
          wx.showToast({
            title: response.msg || '获取摄像头列表失败',
            icon: 'none'
          });
        }
      })
      .catch(error => {
        console.error('调用接口失败:', error);
        this.setData({
          isLoading: false
        });
        wx.showToast({
          title: mockResponse.msg || '获取摄像头列表失败',
          icon: 'none'
        });
      }
    }, 1000); // 模拟网络延迟1秒
      });
  },
  /**
   * 批量获取所有摄像头的HLS播放地址
   */
  batchGetHlsUrls(cameraList) {
    if (!cameraList || cameraList.length === 0) {
      console.log('摄像头列表为空,无需获取播放地址');
      return;
    }
    console.log('开始批量获取播放地址,摄像头数量:', cameraList.length);
    // 为每个摄像头获取播放地址
    cameraList.forEach((camera, index) => {
      // 延迟获取,避免同时发起太多请求
      setTimeout(() => {
        this.getHlsUrlForCamera(camera);
      }, index * 500); // 每个请求间隔500ms
    });
  },
  /**
@@ -224,31 +457,56 @@
   */
  playVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('播放摄像头:', camera.name);
    console.log('=== 播放视频开始 ===');
    console.log('摄像头信息:', camera);
    console.log('设备信息:', this.data.deviceInfo);
    console.log('设备特定配置:', this.data.deviceSpecificConfig);
    if (!camera.online) {
      console.log('摄像头离线,无法播放');
      wx.showToast({
        title: '摄像头离线',
        title: '设备离线,无法播放',
        icon: 'error'
      });
      return;
    }
    // 检查视频URL是否有效
    if (!camera.videoUrl4PcLive) {
    if (!camera.hslUrl) {
      console.log('无播放地址,无法播放');
      wx.showToast({
        title: '视频地址无效',
        title: '暂无播放地址,请稍后重试',
        icon: 'error'
      });
      return;
    }
    console.log('视频URL:', camera.videoUrl4PcLive);
    if (camera.isLoadingUrl) {
      console.log('正在加载URL,无法播放');
      wx.showToast({
        title: '正在获取播放地址,请稍候',
        icon: 'none'
      });
      return;
    }
    // 更新视频播放状态
    console.log('开始播放视频,播放地址:', camera.hslUrl);
    console.log('当前页面数据状态:', {
      cameraList: this.data.cameraList,
      activeTab: this.data.activeTab,
      isLoading: this.data.isLoading
    });
    // 检查URL格式
    if (camera.hslUrl.startsWith('rtmp://')) {
      console.log('检测到RTMP URL格式,开始播放');
      // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return { ...item, isPlaying: true };
        return {
          ...item,
          isPlaying: true
        };
      }
      return item;
    });
@@ -257,10 +515,22 @@
      cameraList: cameraList
    });
    // 延迟一下让live-player组件更新
    setTimeout(() => {
      console.log('开始播放直播:', camera.videoUrl4PcLive);
    }, 100);
      // 显示播放成功提示
      wx.showToast({
        title: `开始播放 ${camera.name}`,
        icon: 'success'
      });
      console.log(`播放状态已更新,摄像头 ${camera.name} 开始播放RTMP流`);
    } else {
      console.log('URL格式不是RTMP,无法播放');
      wx.showToast({
        title: '播放地址格式不正确',
        icon: 'error'
      });
    }
    console.log('=== 播放视频结束 ===');
  },
  /**
@@ -269,11 +539,14 @@
  pauseVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('暂停摄像头:', camera.name);
    // 更新视频播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return { ...item, isPlaying: false };
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
@@ -289,11 +562,14 @@
  stopVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('停止摄像头:', camera.name);
    // 更新视频播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return { ...item, isPlaying: false };
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
@@ -303,23 +579,7 @@
    });
  },
  /**
   * 测试视频URL
   */
  testVideoUrl(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('测试视频URL:', camera.name);
    console.log('原始URL:', camera.videoUrl4PcLive);
    console.log('RTMP URL:', camera.rtmpUrl);
    // 显示URL信息
    wx.showModal({
      title: '视频URL信息',
      content: `摄像头: ${camera.name}\n原始URL: ${camera.videoUrl4PcLive}\nRTMP URL: ${camera.rtmpUrl}`,
      showCancel: false,
      confirmText: '确定'
    });
  },
  /**
   * 直播播放器状态变化
@@ -327,13 +587,15 @@
  onLivePlayerStateChange(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('直播播放器状态变化:', camera.name, e.detail);
    const { code } = e.detail;
    const {
      code
    } = e.detail;
    // 显示状态信息给用户
    let statusText = '';
    let isPlaying = false;
    switch (code) {
      case 2001:
        statusText = '已经连接服务器';
@@ -398,13 +660,16 @@
        statusText = `未知状态码: ${code}`;
        break;
    }
    console.log(`摄像头 ${camera.name} 状态: ${statusText}`);
    // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return { ...item, isPlaying: isPlaying };
        return {
          ...item,
          isPlaying: isPlaying
        };
      }
      return item;
    });
@@ -428,16 +693,19 @@
  onLivePlayerError(e) {
    const camera = e.currentTarget.dataset.camera;
    console.error('直播播放器错误:', camera.name, e.detail);
    wx.showToast({
      title: '直播播放失败',
      icon: 'error'
    });
    // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return { ...item, isPlaying: false };
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
@@ -453,7 +721,7 @@
  fullscreenVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('全屏播放:', camera.name);
    if (!camera.online) {
      wx.showToast({
        title: '摄像头离线',
@@ -462,10 +730,10 @@
      return;
    }
    // 使用PC直播URL进行全屏播放
    if (camera.videoUrl4PcLive) {
      console.log('全屏视频URL:', camera.videoUrl4PcLive);
    // 使用RTMP URL进行全屏播放
    if (camera.hslUrl) {
      console.log('全屏视频URL:', camera.hslUrl);
      wx.showModal({
        title: '全屏播放',
        content: `即将全屏播放 ${camera.name} 的视频流`,
@@ -477,7 +745,7 @@
              title: '正在加载全屏视频...',
              icon: 'loading'
            });
            // 模拟全屏视频加载
            setTimeout(() => {
              wx.showToast({
@@ -502,7 +770,7 @@
  cameraSettings(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('摄像头设置:', camera.name);
    wx.showActionSheet({
      itemList: ['云台控制', '录像设置', '画质调节', '报警设置'],
      success: (res) => {
@@ -513,5 +781,762 @@
        });
      }
    });
  }
})
  },
  /**
   * 获取气象站列表(兼容性方法,现在调用统一接口)
   */
  getWeatherStationList() {
    console.log('获取气象站列表(调用统一接口)');
    this.getAllDeviceInfo();
  },
  /**
   * 选择气象站
   */
  selectWeatherStation(index) {
    const weatherStation = this.data.weatherStationList[index];
    if (!weatherStation) return;
    console.log('选择气象站:', weatherStation.name);
    // 获取该气象站的详细数据
    this.getWeatherStationData(weatherStation.id);
    this.setData({
      selectedWeatherStationIndex: index
    });
  },
  /**
   * 获取气象站详细数据
   */
  getWeatherStationData(stationId) {
    console.log('获取气象站数据:', stationId);
    // 调用真实接口获取气象站详细信息
    this.getWeatherLastData(stationId);
  },
  /**
   * 调用 /wx/mqttLast/oneWeatherLast 接口获取气象站详细信息
   */
  getWeatherLastData(weatherId) {
    console.log('开始调用 /wx/mqttLast/oneWeatherLast 接口获取气象站详细信息');
    console.log('气象站ID:', weatherId);
    get({url: `/wx/mqttLast/oneWeatherLast?weatherId=${weatherId}`})
      .then(response => {
        console.log('气象站详细信息接口返回数据:', response);
        if (response.success && response.code === '0001') {
          const content = response.content;
          // 处理接口返回的气象站数据
          const weatherData = {
            id: content.id,
            weatherId: content.weatherId,
            weatherName: content.weatherName || '气象站',
            dt: content.dt,
            // 气象数据
            temperature: content.airTemperature, // 空气温度
            humidity: content.airHumidity, // 空气湿度
            uv: content.ultraviolet, // 紫外线
            light: content.lightIntensity, // 光照强度
            rainfall: content.rainfall, // 雨量
            windSpeed: content.windSpeed, // 风速
            windDirection: content.windDirectionStr, // 风向描述
            windDirectionAngle: content.windDirection, // 风向角度
            // 在线状态
            onLine: content.onLine,
            // 计算在线状态
            online: content.onLine === 1,
            // 格式化显示数据
            lastUpdate: content.dt || new Date().toLocaleString()
          };
          this.setData({
            currentWeatherStation: weatherData
          });
          console.log('处理后的气象站数据:', weatherData);
        } else {
          console.error('获取气象站详细信息失败:', response.msg);
          wx.showToast({
            title: response.msg || '获取气象站详细信息失败',
            icon: 'none'
          });
          // 如果接口调用失败,使用模拟数据作为备选
          this.setMockWeatherData(stationId);
        }
      })
      .catch(error => {
        console.error('调用气象站详细信息接口失败:', error);
        wx.showToast({
          title: '获取气象站详细信息失败',
          icon: 'error'
        });
        // 如果接口调用失败,使用模拟数据作为备选
        this.setMockWeatherData(stationId);
      });
  },
  /**
   * 设置模拟气象站数据(作为接口调用失败的备选方案)
   */
  setMockWeatherData(stationId) {
    console.log('使用模拟气象站数据:', stationId);
    const mockWeatherData = {
      id: stationId,
      weatherId: stationId,
      weatherName: '气象站',
      dt: new Date().toLocaleString(),
      temperature: 0.0,
      humidity: 0.0,
      uv: 0,
      light: 0,
      rainfall: 0.00,
      windSpeed: 0.00,
      windDirection: '北',
      windDirectionAngle: 0,
      onLine: 1,
      online: true,
      lastUpdate: new Date().toLocaleString()
    };
    this.setData({
      currentWeatherStation: mockWeatherData
    });
  },
  /**
   * 气象站选择改变
   */
  onWeatherStationChange(e) {
    const index = e.detail.value;
    this.selectWeatherStation(index);
  },
  /**
   * 刷新气象数据
   */
  refreshWeatherData() {
    if (!this.data.currentWeatherStation) {
      wx.showToast({
        title: '请先选择气象站',
        icon: 'none'
      });
      return;
    }
    console.log('刷新气象数据');
    wx.showLoading({
      title: '刷新中...'
    });
    // 重新调用接口获取最新数据
    this.getWeatherLastData(this.data.currentWeatherStation.weatherId || this.data.currentWeatherStation.id);
    wx.hideLoading();
    wx.showToast({
      title: '刷新成功',
      icon: 'success'
    });
  },
  /**
   * 选择土壤墒情站
   */
  selectSoilStation(index) {
    const soilStation = this.data.soilStationList[index];
    if (!soilStation) return;
    console.log('选择土壤墒情站:', soilStation.name);
    // 获取该土壤墒情站的详细数据
    this.getSoilStationData(soilStation.id);
    this.setData({
      selectedSoilStationIndex: index
    });
  },
  /**
   * 获取土壤墒情站详细数据
   */
  getSoilStationData(stationId) {
    console.log('获取土壤墒情站数据:', stationId);
    // 调用真实接口获取土壤墒情站详细信息
    this.getSoilLastData(stationId);
  },
  /**
   * 调用 /wx/mqttLast/oneSoilLast 接口获取土壤墒情站详细信息
   */
  getSoilLastData(soilId) {
    console.log('开始调用 /wx/mqttLast/oneSoilLast 接口获取土壤墒情站详细信息');
    console.log('土壤墒情站ID:', soilId);
    get({url: `/wx/mqttLast/oneSoilLast?soilId=${soilId}`})
      .then(response => {
        console.log('土壤墒情站详细信息接口返回数据:', response);
        if (response.success && response.code === '0001') {
          const content = response.content;
          // 处理接口返回的土壤墒情站数据
          const soilData = {
            id: content.id,
            soilId: content.soilId,
            soilName: content.soilName || '土壤墒情站',
            dt: content.dt,
            // 5层土壤湿度数据
            soilHumidity1: content.soilHumidity1,
            soilHumidity2: content.soilHumidity2,
            soilHumidity3: content.soilHumidity3,
            soilHumidity4: content.soilHumidity4,
            soilHumidity5: content.soilHumidity5,
            // 5层土壤温度数据
            soilTemperature1: content.soilTemperature1,
            soilTemperature2: content.soilTemperature2,
            soilTemperature3: content.soilTemperature3,
            soilTemperature4: content.soilTemperature4,
            soilTemperature5: content.soilTemperature5,
            // 在线状态
            onLine: content.onLine,
            // 计算在线状态
            online: content.onLine === 1,
            // 格式化显示数据
            lastUpdate: content.dt || new Date().toLocaleString()
          };
          this.setData({
            currentSoilStation: soilData
          });
          console.log('处理后的土壤墒情站数据:', soilData);
        } else {
          console.error('获取土壤墒情站详细信息失败:', response.msg);
          wx.showToast({
            title: response.msg || '获取土壤墒情站详细信息失败',
            icon: 'none'
          });
          // 如果接口调用失败,使用模拟数据作为备选
          this.setMockSoilData(stationId);
        }
      })
      .catch(error => {
        console.error('调用土壤墒情站详细信息接口失败:', error);
        wx.showToast({
          title: '获取土壤墒情站详细信息失败',
          icon: 'error'
        });
        // 如果接口调用失败,使用模拟数据作为备选
        this.setMockSoilData(stationId);
      });
  },
  /**
   * 设置模拟土壤墒情站数据(作为接口调用失败的备选方案)
   */
  setMockSoilData(stationId) {
    console.log('使用模拟土壤墒情站数据:', stationId);
    const mockSoilData = {
      id: stationId,
      soilId: stationId,
      soilName: '土壤墒情站',
      dt: new Date().toLocaleString(),
      // 5层土壤湿度数据
      soilHumidity1: 0.00,
      soilHumidity2: 0.00,
      soilHumidity3: 0.00,
      soilHumidity4: 0.00,
      soilHumidity5: 0.00,
      // 5层土壤温度数据
      soilTemperature1: 0.00,
      soilTemperature2: 0.00,
      soilTemperature3: 0.00,
      soilTemperature4: 0.00,
      soilTemperature5: 0.00,
      // 在线状态
      onLine: 1,
      online: true,
      lastUpdate: new Date().toLocaleString()
    };
    this.setData({
      currentSoilStation: mockSoilData
    });
  },
  /**
   * 土壤墒情站选择改变
   */
  onSoilStationChange(e) {
    const index = e.detail.value;
    this.selectSoilStation(index);
  },
  /**
   * 刷新土壤墒情数据
   */
  refreshSoilData() {
    if (!this.data.currentSoilStation) {
      wx.showToast({
        title: '请先选择土壤墒情站',
        icon: 'none'
      });
      return;
    }
    console.log('刷新土壤墒情数据');
    wx.showLoading({
      title: '刷新中...'
    });
    // 重新调用接口获取最新数据
    this.getSoilLastData(this.data.currentSoilStation.soilId || this.data.currentSoilStation.id);
    wx.hideLoading();
    wx.showToast({
      title: '刷新成功',
      icon: 'success'
    });
  },
  /**
   * 获取水肥机列表(兼容性方法,现在调用统一接口)
   */
  getFertilizerStationList() {
    console.log('获取水肥机列表(调用统一接口)');
    this.getAllDeviceInfo();
  },
  /**
   * 选择水肥机
   */
  selectFertilizerStation(index) {
    const fertilizerStation = this.data.fertilizerStationList[index];
    if (!fertilizerStation) return;
    console.log('选择水肥机:', fertilizerStation.name);
    // 获取该水肥机的详细数据
    this.getFertilizerStationData(fertilizerStation.id);
    this.setData({
      selectedFertilizerStationIndex: index
    });
  },
  /**
   * 获取水肥机详细数据
   */
  getFertilizerStationData(stationId) {
    console.log('获取水肥机数据:', stationId);
    // 调用真实接口获取水肥机详细信息
    this.getManureLastData(stationId);
  },
  /**
   * 调用 /wx/mqttLast/oneManureLast 接口获取水肥机详细信息
   */
  getManureLastData(manureId) {
    console.log('开始调用 /wx/mqttLast/oneManureLast 接口获取水肥机详细信息');
    console.log('水肥机ID:', manureId);
    get({url: `/wx/mqttLast/oneManureLast?manureId=${manureId}`})
      .then(response => {
        console.log('水肥机详细信息接口返回数据:', response);
        if (response.success && response.code === '0001') {
          const content = response.content;
          // 处理接口返回的水肥机数据
          const fertilizerData = {
            id: content.id,
            manureId: content.manureId,
            manureName: content.manureName || '水肥机',
            dt: content.dt,
            alarm: content.alarm,
            // 搅拌运行状态
            stirRunning1: content.stirRunning1,
            // 注肥运行状态
            injectRunning: content.injectRunning,
            // 流量和时间数据
            manureFlow: content.manureFlow,
            manureTime: content.manureTime,
            stirTime: content.stirTime,
            stirDuration: content.stirDuration,
            injectDuration: content.injectDuration,
            // 在线状态
            onLine: content.onLine,
            // 计算运行状态
            mixingEnabled: content.stirRunning1 === 1,
            fertilizingEnabled: content.injectRunning === 1,
            // 格式化显示数据
            lastUpdate: content.dt || new Date().toLocaleString()
          };
          this.setData({
            currentFertilizerStation: fertilizerData
          });
          console.log('处理后的水肥机数据:', fertilizerData);
        } else {
          console.error('获取水肥机详细信息失败:', response.msg);
          wx.showToast({
            title: response.msg || '获取水肥机详细信息失败',
            icon: 'none'
          });
          // 如果接口调用失败,使用模拟数据作为备选
          this.setMockFertilizerData(stationId);
        }
      })
      .catch(error => {
        console.error('调用水肥机详细信息接口失败:', error);
        wx.showToast({
          title: '获取水肥机详细信息失败',
          icon: 'error'
        });
        // 如果接口调用失败,使用模拟数据作为备选
        this.setMockFertilizerData(stationId);
      });
  },
  /**
   * 设置模拟水肥机数据(作为接口调用失败的备选方案)
   */
  setMockFertilizerData(stationId) {
    console.log('使用模拟水肥机数据:', stationId);
    const mockFertilizerData = {
      id: stationId,
      manureId: stationId,
      manureName: '水肥机',
      dt: new Date().toLocaleString(),
      alarm: 0,
      stirRunning1: 0,
      injectRunning: 0,
      manureFlow: 0.00,
      manureTime: 0,
      stirTime: 0,
      stirDuration: 300,
      injectDuration: 300,
      onLine: 1,
      mixingEnabled: false,
      fertilizingEnabled: false,
      lastUpdate: new Date().toLocaleString()
    };
    this.setData({
      currentFertilizerStation: mockFertilizerData
    });
  },
  /**
   * 水肥机选择改变
   */
  onFertilizerStationChange(e) {
    const index = e.detail.value;
    this.selectFertilizerStation(index);
  },
  /**
   * 刷新水肥机数据
   */
  refreshFertilizerData() {
    if (!this.data.currentFertilizerStation) {
      wx.showToast({
        title: '请先选择水肥机',
        icon: 'none'
      });
      return;
    }
    console.log('刷新水肥机数据');
    wx.showLoading({
      title: '刷新中...'
    });
    // 重新调用接口获取最新数据
    this.getManureLastData(this.data.currentFertilizerStation.manureId || this.data.currentFertilizerStation.id);
    wx.hideLoading();
    wx.showToast({
      title: '刷新成功',
      icon: 'success'
    });
  },
  /**
   * 切换搅拌开关
   */
  toggleMixing(e) {
    const enabled = e.detail.value;
    console.log('搅拌开关:', enabled ? '开启' : '关闭');
    if (!this.data.currentFertilizerStation) return;
    // 更新搅拌状态
    const currentStation = {
      ...this.data.currentFertilizerStation
    };
    currentStation.mixingEnabled = enabled;
    // 更新具体的搅拌运行状态(这里假设只控制第一个搅拌器)
    currentStation.stirRunning1 = enabled ? 1 : 0;
    this.setData({
      currentFertilizerStation: currentStation
    });
    // 显示操作结果
    wx.showToast({
      title: enabled ? '搅拌已开启' : '搅拌已关闭',
      icon: 'success'
    });
  },
  /**
   * 切换注肥开关
   */
  toggleFertilizing(e) {
    const enabled = e.detail.value;
    console.log('注肥开关:', enabled ? '开启' : '关闭');
    if (!this.data.currentFertilizerStation) return;
    // 更新注肥状态
    const currentStation = {
      ...this.data.currentFertilizerStation
    };
    currentStation.fertilizingEnabled = enabled;
    // 更新注肥运行状态
    currentStation.injectRunning = enabled ? 1 : 0;
    this.setData({
      currentFertilizerStation: currentStation
    });
    // 显示操作结果
    wx.showToast({
      title: enabled ? '注肥已开启' : '注肥已关闭',
      icon: 'success'
    });
  },
  /**
   * 手动重试获取播放地址
   */
  retryGetHlsUrl(e) {
    const camera = e.currentTarget.dataset.camera;
    if (!camera) {
      console.error('重试失败:摄像头信息不完整');
      wx.showToast({
        title: '摄像头信息不完整',
        icon: 'error'
      });
      return;
    }
    console.log('=== 手动重试获取播放地址 ===');
    console.log(`摄像头: ${camera.name}, ID: ${camera.id}`);
    console.log('当前状态:', {
      online: camera.online,
      hslUrl: camera.hslUrl,
      isLoadingUrl: camera.isLoadingUrl,
      urlError: camera.urlError
    });
    // 重置错误状态并重新获取
    this.updateCameraUrlLoadingState(camera.id, false, false);
    this.getHlsUrlForCamera(camera);
  },
  /**
   * 更新摄像头URL加载状态
   */
  updateCameraUrlLoadingState(cameraId, isLoading, hasError) {
    console.log('=== 更新摄像头URL加载状态 ===');
    console.log('参数:', { cameraId, isLoading, hasError });
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === cameraId) {
        const updatedItem = {
          ...item,
          isLoadingUrl: isLoading,
          urlError: hasError
        };
        console.log(`摄像头 ${cameraId} 状态更新:`, {
          name: updatedItem.name,
          isLoadingUrl: updatedItem.isLoadingUrl,
          urlError: updatedItem.urlError
        });
        return updatedItem;
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
    console.log('状态更新完成,当前摄像头列表:', cameraList);
  },
  /**
   * 为单个摄像头获取HLS播放地址
   */
  getHlsUrlForCamera(camera) {
    if (!camera || !camera.deviceSerial) {
      console.error('摄像头信息不完整:', camera);
      return;
    }
    console.log('=== 获取播放地址开始 ===');
    console.log(`摄像头: ${camera.name}, ID: ${camera.id}, 设备序列号: ${camera.deviceSerial}`);
    console.log('当前accessToken:', this.data.accessToken);
    // 更新加载状态
    this.updateCameraUrlLoadingState(camera.id, true, false);
    // 调用萤石云API获取播放地址
    this.getHlsUrl(this.data.accessToken, camera.deviceSerial, camera.id);
  },
  /**
   * ezplayer错误处理
   */
  handleError(e) {
    console.log('=== ezplayer 错误处理 ===');
    console.log('错误事件详情:', e);
    console.log('错误详情:', e.detail);
    // 获取摄像头信息
    const cameraId = e.currentTarget.id;
    console.log('出错的摄像头ID:', cameraId);
    // 查找对应的摄像头
    const camera = this.data.cameraList.find(item => `ezplayer-${item.id}` === cameraId);
    if (camera) {
      console.log('出错的摄像头信息:', camera);
      // 更新错误状态
      this.updateCameraUrlLoadingState(camera.id, false, true);
      // 显示错误提示
      wx.showToast({
        title: '视频播放出错',
        icon: 'error',
        duration: 2000
      });
    } else {
      console.error('未找到对应的摄像头:', cameraId);
    }
  },
  /**
   * ezplayer控制事件
   */
  onControlEvent(e) {
    console.log('=== ezplayer 控制事件 ===');
    console.log('控制事件详情:', e);
    console.log('事件类型:', e.type);
    console.log('事件数据:', e.detail);
    // 获取摄像头信息
    const cameraId = e.currentTarget.id;
    console.log('事件来源摄像头ID:', cameraId);
    // 查找对应的摄像头
    const camera = this.data.cameraList.find(item => `ezplayer-${item.id}` === cameraId);
    if (camera) {
      console.log('事件来源摄像头信息:', camera);
      // 根据事件类型处理
      switch (e.type) {
        case 'play':
          console.log('视频开始播放');
          break;
        case 'pause':
          console.log('视频暂停播放');
          break;
        case 'ended':
          console.log('视频播放结束');
          break;
        case 'error':
          console.log('视频播放错误');
          this.updateCameraUrlLoadingState(camera.id, false, true);
          break;
      default:
          console.log('未知事件类型:', e.type);
      }
    } else {
      console.error('未找到对应的摄像头:', cameraId);
    }
  },
  /**
   * 更新摄像头播放状态
   */
  updateCameraPlayState(cameraId, isPlaying) {
    console.log('=== 更新摄像头播放状态 ===');
    console.log('参数:', { cameraId, isPlaying });
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === cameraId) {
        const updatedItem = {
          ...item,
          isPlaying: isPlaying
        };
        console.log(`摄像头 ${cameraId} 播放状态更新:`, {
          name: updatedItem.name,
          isPlaying: updatedItem.isPlaying
        });
        return updatedItem;
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
    console.log('播放状态更新完成');
  },
})
pages/stationMonitor/stationMonitor.wxml
@@ -1,23 +1,23 @@
<!--pages/stationMonitor/stationMonitor.wxml-->
<view class="container">
  <!-- 顶部选项卡 -->
  <view class="tab-container">
    <view class="tab-item {{activeTab === 'weather' ? 'active' : ''}}" bind:tap="switchTab" data-tab="weather">
  <view class="tabs">
    <view class="tab {{activeTab === 'weather' ? 'active' : ''}}" bind:tap="switchTab" data-tab="weather">
      <image class="tab-icon" src="/images/weather.svg" />
      <text class="tab-name">气象站</text>
    </view>
    <view class="tab-item {{activeTab === 'soil' ? 'active' : ''}}" bind:tap="switchTab" data-tab="soil">
    <view class="tab {{activeTab === 'soil' ? 'active' : ''}}" bind:tap="switchTab" data-tab="soil">
      <image class="tab-icon" src="/images/soil.svg" />
      <text class="tab-name">土壤墒情站</text>
    </view>
    <view class="tab-item {{activeTab === 'fertilizer' ? 'active' : ''}}" bind:tap="switchTab" data-tab="fertilizer">
    <view class="tab {{activeTab === 'fertilizer' ? 'active' : ''}}" bind:tap="switchTab" data-tab="fertilizer">
      <image class="tab-icon" src="/images/fertilizer.svg" />
      <text class="tab-name">水肥机</text>
    </view>
    <view class="tab-item {{activeTab === 'camera' ? 'active' : ''}}" bind:tap="switchTab" data-tab="camera">
    <view class="tab {{activeTab === 'camera' ? 'active' : ''}}" bind:tap="switchTab" data-tab="camera">
      <image class="tab-icon" src="/images/camera.svg" />
      <text class="tab-name">摄像头</text>
    </view>
@@ -27,25 +27,407 @@
  <view class="content-area">
    <!-- 气象站内容 -->
    <view wx:if="{{activeTab === 'weather'}}" class="tab-content">
      <text class="content-title">气象站监测</text>
      <!-- 在这里添加气象站相关内容 -->
      <!-- <text class="content-title">气象站监测</text> -->
      <!-- 气象站选择下拉框 -->
      <view class="weather-station-selector">
        <picker bindchange="onWeatherStationChange" value="{{selectedWeatherStationIndex}}" range="{{weatherStationList}}" range-key="name">
          <view class="picker-container">
            <text class="picker-label">选择气象站:</text>
            <view class="picker-value">
              <text>{{weatherStationList[selectedWeatherStationIndex].name || '请选择气象站'}}</text>
              <image class="picker-arrow" src="/images/arrow-down.svg" />
            </view>
          </view>
        </picker>
      </view>
      <!-- 气象站信息卡片 -->
      <view wx:if="{{currentWeatherStation}}" class="weather-info-card">
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentWeatherStation.online ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentWeatherStation.online ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshWeatherData">
            <image class="refresh-icon" src="/images/refresh.svg" />
            <text class="refresh-text">刷新</text>
          </view>
        </view>
        <!-- 气象数据网格 -->
        <view class="weather-data-grid">
          <!-- 空气湿度 -->
          <view class="weather-data-item humidity">
            <view class="data-icon">
              <image src="/images/humidity.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">空气湿度(%)</text>
              <text class="data-value">{{currentWeatherStation.humidity || '--'}}%</text>
            </view>
          </view>
          <!-- 空气温度 -->
          <view class="weather-data-item temperature">
            <view class="data-icon">
              <image src="/images/temperature.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">空气温度(℃)</text>
              <text class="data-value">{{currentWeatherStation.temperature || '--'}}°C</text>
            </view>
          </view>
          <!-- 紫外线 -->
          <view class="weather-data-item uv">
            <view class="data-icon">
              <image src="/images/uv.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">紫外线(mW/m²)</text>
              <text class="data-value">{{currentWeatherStation.uv || '--'}}</text>
            </view>
          </view>
          <!-- 光照强度 -->
          <view class="weather-data-item light">
            <view class="data-icon">
              <image src="/images/light.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">光照强度(lm/㎡)</text>
              <text class="data-value">{{currentWeatherStation.light || '--'}} lux</text>
            </view>
          </view>
          <!-- 雨量 -->
          <view class="weather-data-item rainfall">
            <view class="data-icon">
              <image src="/images/rainfall.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">雨量(mm)</text>
              <text class="data-value">{{currentWeatherStation.rainfall || '--'}} mm</text>
            </view>
          </view>
          <!-- 风速 -->
          <view class="weather-data-item wind-speed">
            <view class="data-icon">
              <image src="/images/wind-speed.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">风速(m/s)</text>
              <text class="data-value">{{currentWeatherStation.windSpeed || '--'}} m/s</text>
            </view>
          </view>
          <!-- 风向 -->
          <view class="weather-data-item wind-direction">
            <view class="data-icon">
              <image src="/images/wind-direction.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">风向</text>
              <view class="wind-direction-display">
                <!-- <image class="wind-arrow" src="/images/wind-arrow.svg" style="transform: rotate({{currentWeatherStation.windDirectionAngle || 0}}deg)" /> -->
                <text class="data-value">{{currentWeatherStation.windDirection || '--'}}</text>
              </view>
            </view>
          </view>
        </view>
        <!-- 最后更新时间 -->
        <view class="last-update">
          <text class="update-text">最后更新:{{currentWeatherStation.lastUpdate || '--'}}</text>
        </view>
      </view>
      <!-- 无数据提示 -->
      <view wx:if="{{!currentWeatherStation}}" class="no-data">
        <image class="no-data-icon" src="/images/no-data.svg" />
        <text class="no-data-text">请选择气象站查看数据</text>
      </view>
    </view>
    <!-- 土壤墒情站内容 -->
    <view wx:elif="{{activeTab === 'soil'}}" class="tab-content">
      <text class="content-title">土壤墒情站监测</text>
      <!-- 在这里添加土壤墒情站相关内容 -->
      <!-- 土壤墒情站选择下拉框 -->
      <view class="weather-station-selector">
        <picker bindchange="onSoilStationChange" value="{{selectedSoilStationIndex}}" range="{{soilStationList}}" range-key="name">
          <view class="picker-container">
            <text class="picker-label">选择土壤墒情站:</text>
            <view class="picker-value">
              <text>{{soilStationList[selectedSoilStationIndex].name || '请选择土壤墒情站'}}</text>
              <image class="picker-arrow" src="/images/arrow-down.svg" />
            </view>
          </view>
        </picker>
      </view>
      <!-- 土壤墒情信息卡片 -->
      <view wx:if="{{currentSoilStation}}" class="weather-info-card">
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentSoilStation.online ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentSoilStation.online ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshSoilData">
            <image class="refresh-icon" src="/images/refresh.svg" />
            <text class="refresh-text">刷新</text>
          </view>
        </view>
        <!-- 土壤墒情数据网格 -->
        <view class="weather-data-grid">
          <!-- 土壤层1 -->
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/one.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度1(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity1 || '--'}}%</text>
            </view>
          </view>
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/one.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度1(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature1 || '--'}}°C</text>
            </view>
          </view>
          <!-- 土壤层2 -->
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/two.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度2(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity2 || '--'}}%</text>
            </view>
          </view>
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/two.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度2(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature2 || '--'}}°C</text>
            </view>
          </view>
          <!-- 土壤层3 -->
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/three.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度3(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity3 || '--'}}%</text>
            </view>
          </view>
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/three.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度3(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature3 || '--'}}°C</text>
            </view>
          </view>
          <!-- 土壤层4 -->
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/four.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度4(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity4 || '--'}}%</text>
            </view>
          </view>
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/four.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度4(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature4 || '--'}}°C</text>
            </view>
          </view>
          <!-- 土壤层5 -->
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/five.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度5(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity5 || '--'}}%</text>
            </view>
          </view>
          <view class="weather-data-item soil-item">
            <view class="data-icon">
              <image src="/images/five.svg" />
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度5(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature5 || '--'}}°C</text>
            </view>
          </view>
        </view>
        <!-- 最后更新时间 -->
        <view class="last-update">
          <text class="update-text">最后更新:{{currentSoilStation.lastUpdate || '--'}}</text>
        </view>
      </view>
      <!-- 无数据提示 -->
      <view wx:if="{{!currentSoilStation}}" class="no-data">
        <image class="no-data-icon" src="/images/no-data.svg" />
        <text class="no-data-text">请选择土壤墒情站查看数据</text>
      </view>
    </view>
    <!-- 水肥机内容 -->
    <view wx:elif="{{activeTab === 'fertilizer'}}" class="tab-content">
      <text class="content-title">水肥机监测</text>
      <!-- 在这里添加水肥机相关内容 -->
      <!-- <text class="content-title">水肥机监测</text> -->
      <!-- 水肥机选择下拉框 -->
      <view class="fertilizer-station-selector">
        <picker bindchange="onFertilizerStationChange" value="{{selectedFertilizerStationIndex}}" range="{{fertilizerStationList}}" range-key="name">
          <view class="picker-container">
            <text class="picker-label">选择水肥机:</text>
            <view class="picker-value">
              <text>{{fertilizerStationList[selectedFertilizerStationIndex].name || '请选择水肥机'}}</text>
              <image class="picker-arrow" src="/images/arrow-down.svg" />
            </view>
          </view>
        </picker>
      </view>
      <!-- 水肥机信息卡片 -->
      <view wx:if="{{currentFertilizerStation}}" class="fertilizer-info-card">
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentFertilizerStation.onLine === 1 ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentFertilizerStation.onLine === 1 ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshFertilizerData">
            <image class="refresh-icon" src="/images/refresh.svg" />
            <text class="refresh-text">刷新</text>
          </view>
        </view>
        <!-- 控制开关区域 -->
        <view class="control-switches">
          <text class="section-title">控制开关</text>
          <view class="switch-container">
            <!-- 搅拌开关 -->
            <view class="switch-item">
              <text class="switch-label">搅拌</text>
              <switch class="custom-switch" checked="{{currentFertilizerStation.mixingEnabled}}" bindchange="toggleMixing" disabled="{{currentFertilizerStation.onLine !== 1}}" color="#07c160" />
            </view>
            <!-- 注肥开关 -->
            <view class="switch-item">
              <text class="switch-label">注肥</text>
              <switch class="custom-switch" checked="{{currentFertilizerStation.fertilizingEnabled}}" bindchange="toggleFertilizing" disabled="{{currentFertilizerStation.onLine !== 1}}" color="#07c160" />
            </view>
          </view>
        </view>
        <!-- 监测数据区域 -->
        <view class="monitoring-data">
          <text class="section-title">监测数据</text>
          <view class="data-grid">
            <!-- 肥料流量 -->
            <view class="data-item waste-flow">
              <view class="data-icon">
                <image src="/images/flow.svg" />
              </view>
              <view class="data-content">
                <text class="data-label">肥料流量(升)</text>
                <text class="data-value">{{currentFertilizerStation.manureFlow || '--'}} L</text>
              </view>
            </view>
            <!-- 注肥时长 -->
            <view class="data-item fertilizing-duration">
              <view class="data-icon">
                <image src="/images/timer.svg" />
              </view>
              <view class="data-content">
                <text class="data-label">注肥时长(秒)</text>
                <text class="data-value">{{currentFertilizerStation.manureTime || '--'}} s</text>
              </view>
            </view>
            <!-- 搅拌时长 -->
            <view class="data-item mixing-duration">
              <view class="data-icon">
                <image src="/images/mixing.svg" />
              </view>
              <view class="data-content">
                <text class="data-label">搅拌时长(秒)</text>
                <text class="data-value">{{currentFertilizerStation.stirTime || '--'}} s</text>
              </view>
            </view>
            <!-- 搅拌设定时间 -->
            <view class="data-item mixing-set-time">
              <view class="data-icon">
                <image src="/images/settings.svg" />
              </view>
              <view class="data-content">
                <text class="data-label">搅拌设定时间(秒)</text>
                <text class="data-value">{{currentFertilizerStation.stirDuration || '--'}} s</text>
              </view>
            </view>
            <!-- 注肥设定时间 -->
            <view class="data-item fertilizing-set-time">
              <view class="data-icon">
                <image src="/images/settings-time.svg" />
              </view>
              <view class="data-content">
                <text class="data-label">注肥设定时间(秒)</text>
                <text class="data-value">{{currentFertilizerStation.injectDuration || '--'}} s</text>
              </view>
            </view>
          </view>
        </view>
        <!-- 最后更新时间 -->
        <view class="last-update">
          <text class="update-text">最后更新:{{currentFertilizerStation.dt || currentFertilizerStation.lastUpdate || '--'}}</text>
        </view>
      </view>
      <!-- 无数据提示 -->
      <view wx:if="{{!currentFertilizerStation}}" class="no-data">
        <image class="no-data-icon" src="/images/no-data.svg" />
        <text class="no-data-text">请选择水肥机查看数据</text>
      </view>
    </view>
    <!-- 摄像头内容 -->
    <view wx:elif="{{activeTab === 'camera'}}" class="tab-content">
      <!-- <text class="content-title">摄像头监控</text> -->
      <!-- 摄像头列表 -->
      <view class="camera-list">
@@ -59,63 +441,66 @@
          </view>
          <!-- 摄像头视频 -->
          <view class="camera-video-container">
            <view wx:if="{{item.online}}" class="video-wrapper">
          <view class="camera-video-container" style="height: {{deviceSpecificConfig.videoHeight}}rpx;">
            <!-- 加载状态 -->
            <view wx:if="{{item.isLoadingUrl}}" class="video-loading">
              <view class="loading-spinner"></view>
              <text class="loading-text">正在获取播放地址...</text>
            </view>
            <!-- 错误状态 -->
            <view wx:elif="{{item.urlError}}" class="video-error">
              <image class="error-icon" src="/images/error.svg" />
              <text class="error-text">获取播放地址失败</text>
              <button class="retry-btn" bind:tap="retryGetHlsUrl" data-camera="{{item}}">
                <image class="retry-icon" src="/images/refresh.svg" />
                <text>重试</text>
              </button>
            </view>
            <!-- 正常播放状态 -->
            <view wx:elif="{{item.online && item.hslUrl}}" class="video-wrapper">
              <!-- 直播播放器组件 -->
              <ezplayer id="ezplayer" accessToken="at.2o04glgs0q36cjugbvddqujz7tqrghx1-1ovr6lmf3k-03pij3c-304ziif7e" url="rtmp://open.ys7.com/BA7248908/1/live" plugins="talk,voice,capture" recPlayTime="" width="360" height="300" watermark="shuiyin" theme="{{ { showFullScreenBtn: true, showHdBtn: true, showTimeLine: true } }}" bind:handleError="handleError" bind:onControlEvent="onControlEvent" />
              <!-- 备用HLS播放器 -->
              <video wx:if="{{item.isPlaying && !item.rtmpUrl}}" class="live-player" src="{{item.hlsUrl}}" autoplay="{{true}}" muted="{{true}}" controls="{{false}}" object-fit="contain" bind:load="onVideoLoad" bind:play="onVideoPlay" bind:pause="onVideoPause" bind:ended="onVideoEnded" bind:error="onVideoError" data-camera="{{item}}" />
              <!-- 视频控制覆盖层 -->
              <view class="video-overlay" wx:if="{{!item.isPlaying}}">
                <view class="play-overlay" bind:tap="playVideo" data-camera="{{item}}">
                  <image class="play-icon" src="/images/play.svg" />
                </view>
              </view>
              <!-- 视频信息 -->
              <view class="video-info">
                <text class="video-time">{{item.lastUpdate}}</text>
                <text class="video-status">{{item.isPlaying ? '直播中' : '已停止'}}</text>
              </view>
              <!-- 播放控制按钮 -->
              <view class="video-controls" wx:if="{{item.isPlaying}}">
                <view class="control-btn" bind:tap="pauseVideo" data-camera="{{item}}">
                  <image class="control-icon" src="/images/pause.svg" />
                </view>
                <view class="control-btn" bind:tap="stopVideo" data-camera="{{item}}">
                  <image class="control-icon" src="/images/stop.svg" />
                </view>
              </view>
              <!-- 调试按钮 -->
              <view class="debug-controls">
                <view class="debug-btn" bind:tap="testVideoUrl" data-camera="{{item}}">
                  <text>测试URL</text>
                </view>
              </view>
              <ezplayer
                id="ezplayer-{{item.id}}"
                accessToken="{{item.accessToken}}"
                url="{{item.hslUrl}}"
                deviceSerial="{{item.deviceSerial}}"
                channelNo="1"
                width="300rpx"
                height="300rpx"
                plugins="talk,voice,capture,ptz,privacy,mirror"
                watermark="大禹"
                autoPlay="{{true}}"
                theme="{{ { showFullScreenBtn: true, showHdBtn: true, showTimeLine: true } }}"
                bind:handleError="handleError"
                bind:onControlEvent="onControlEvent"
                style="width: 100vw; height: 100%; max-width: 100vw; min-width: 100vw; position: absolute; left: 0; right: 0; top: 0; bottom: 0; overflow: hidden; margin: 0; padding: 0; transform: none; border: none; border-radius: 0; box-shadow: none; background: transparent;"
              />
            </view>
            <!-- 离线状态 -->
            <view wx:else class="video-offline">
              <image class="offline-icon" src="/images/offline.svg" />
              <text class="offline-text">摄像头离线</text>
            <!-- 离线状态显示 -->
            <view wx:elif="{{!item.online}}" class="video-offline">
              <image class="offline-icon" src="/images/camera.svg" />
              <text class="offline-text">设备离线</text>
            </view>
            <!-- 无播放地址状态 -->
            <view wx:else class="video-no-url">
              <image class="no-url-icon" src="/images/camera.svg" />
              <text class="no-url-text">暂无播放地址</text>
            </view>
          </view>
          <!-- 摄像头操作按钮 -->
          <view class="camera-actions">
            <button class="action-btn {{item.online ? 'primary' : 'disabled'}}" disabled="{{!item.online}}" bind:tap="fullscreenVideo" data-camera="{{item}}">
              全屏播放
            </button>
            <button class="action-btn secondary" bind:tap="cameraSettings" data-camera="{{item}}">
              设置
            </button>
          </view>
        </view>
      </view>
      <!-- 无数据提示 -->
      <view wx:if="{{cameraList.length === 0}}" class="no-data">
        <image class="no-data-icon" src="/images/no-data.svg" />
        <text class="no-data-text">暂无摄像头设备</text>
      </view>
    </view>
  </view>
</view>
pages/stationMonitor/stationMonitor.wxss
@@ -6,79 +6,126 @@
  padding: 0;
  width: 100%;
  box-sizing: border-box;
  /* 防止水平滚动 */
  overflow-x: hidden !important;
  /* 确保页面宽度约束 */
  max-width: 100vw;
  /* 新增:强制移除所有可能的边距 */
  min-width: 0;
}
.container {
  padding: 0;
  margin: 0;
  background-color: #f5f5f5;
  min-height: 100vh;
  height: 100vh; /* 固定高度为视口高度 */
  width: 100%;
  box-sizing: border-box;
}
/* 选项卡容器 */
.tab-container {
  /* 防止任何滚动 */
  overflow: hidden !important;
  /* 使用flexbox布局 */
  display: flex;
  flex-direction: column;
  /* 确保容器宽度约束 */
  max-width: 100vw;
  min-width: 0;
  /* 新增:强制移除所有可能的边距 */
  left: 0 !important;
  right: 0 !important;
}
/* 标签页样式 - 线性布局 */
.tabs {
  display: flex;
  background-color: #fff;
  padding: 4rpx 0;
  width: 100%;
  background: white;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  position: sticky;
  flex-shrink: 0; /* 防止被压缩 */
  box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.05);
  border-bottom: 1rpx solid #eaeaea;
  position: sticky; /* 使用sticky定位 */
  top: 0;
  z-index: 100;
  margin: 0;
  padding: 0;
  z-index: 9999;
  background-color: #fff; /* 确保背景色 */
  /* 减小tabs高度 */
  height: 100rpx;
  box-sizing: border-box;
}
/* 选项卡项 */
.tab-item {
/* 移除旧的tab-container样式 */
/* 移除过度的CSS规则,保持简洁的tabs样式 */
/* 标签页项样式 - 优化布局 */
.tab {
  flex: 1;
  width: 25%; /* 明确设置每个选项卡占25%宽度 */
  text-align: center;
  font-size: 29rpx;
  color: #666;
  position: relative;
  padding: 12rpx 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20rpx 5rpx;
  position: relative;
  transition: all 0.3s ease;
  box-sizing: border-box;
  border-radius: 16rpx;
  margin: 0 4rpx;
}
.tab-item.active {
  background-color: #f0f8ff;
.tab.active {
  color: #0052d9;
  font-weight: 500;
  /* 添加渐变背景色 */
  background: linear-gradient(135deg, #e6f3ff 0%, #f0f8ff 100%);
  box-shadow: 0 2rpx 8rpx rgba(0, 82, 217, 0.15);
}
.tab-item.active::after {
.tab.active::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 60rpx;
  width: 50rpx;
  height: 4rpx;
  background-color: #1890FF;
  background: linear-gradient(90deg, #0052d9 0%, #1890ff 100%);
  border-radius: 2rpx;
}
/* 选项卡图标 */
/* 添加悬停效果 */
.tab:hover {
  background: linear-gradient(135deg, #f5f5f5 0%, #fafafa 100%);
  transform: translateY(-1rpx);
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.tab.active:hover {
  background: linear-gradient(135deg, #d9ecff 0%, #e6f3ff 100%);
  transform: translateY(-1rpx);
  box-shadow: 0 4rpx 12rpx rgba(0, 82, 217, 0.2);
}
/* 标签页图标 */
.tab-icon {
  width: 48rpx;
  height: 48rpx;
  margin-bottom: 8rpx;
  width: 36rpx;
  height: 36rpx;
  margin-bottom: 6rpx;
  transition: all 0.3s ease;
}
.tab-item.active .tab-icon {
.tab.active .tab-icon {
  transform: scale(1.1);
  filter: brightness(0) saturate(100%) invert(41%) sepia(96%) saturate(1408%) hue-rotate(200deg) brightness(96%) contrast(103%);
}
.tab-item:not(.active) .tab-icon {
.tab:not(.active) .tab-icon {
  filter: brightness(0) saturate(100%) invert(60%) sepia(0%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(85%);
}
/* 选项卡文字 */
/* 标签页文字 */
.tab-name {
  font-size: 22rpx;
  color: #666;
@@ -89,11 +136,12 @@
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  margin-bottom: 2rpx;
}
.tab-item.active .tab-name {
  color: #1890FF;
  font-weight: 600;
.tab.active .tab-name {
  color: #0052d9;
  font-weight: 500;
}
/* 内容区域 */
@@ -101,8 +149,22 @@
  padding: 0;
  margin: 0;
  width: 100%;
  min-height: calc(100vh - 140rpx);
  box-sizing: border-box;
  /* 使用flex: 1填充剩余空间 */
  flex: 1;
  min-height: 0; /* 允许flex项目收缩 */
  overflow-y: auto; /* 垂直滚动 */
  overflow-x: hidden; /* 隐藏水平滚动 */
  /* 隐藏滚动条 */
  -ms-overflow-style: none;  /* IE and Edge */
  scrollbar-width: none;  /* Firefox */
  /* 为tabs留出空间 */
  margin-top: 0;
}
/* 隐藏Webkit浏览器的滚动条 */
.content-area::-webkit-scrollbar {
  display: none;
}
/* 选项卡内容 */
@@ -110,6 +172,7 @@
  width: 100%;
  background: white;
  border-radius: 0;
  /* 还原内边距 */
  padding: 20rpx 0;
  box-shadow: none;
  animation: fadeIn 0.3s ease-in-out;
@@ -134,10 +197,268 @@
  font-size: 32rpx;
  font-weight: 600;
  color: #333;
  /* 还原左右边距 */
  margin: 0 20rpx 20rpx 20rpx;
  display: block;
  width: calc(100% - 40rpx);
  box-sizing: border-box;
}
/* 气象站选择器 */
.weather-station-selector {
  /* 还原左右边距 */
  margin: 10rpx 20rpx;
  background: white;
  border-radius: 12rpx;
  padding: 20rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.picker-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.picker-label {
  font-size: 28rpx;
  color: #666;
  font-weight: 500;
}
.picker-value {
  display: flex;
  align-items: center;
  gap: 12rpx;
  font-size: 30rpx;
  color: #333;
  font-weight: 600;
}
.picker-arrow {
  width: 24rpx;
  height: 24rpx;
  opacity: 0.6;
}
/* 气象站信息卡片 */
.weather-info-card {
  /* 还原左右边距 */
  margin: 20rpx;
  background: white;
  border-radius: 16rpx;
  padding: 24rpx;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
/* 状态栏 */
.status-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24rpx;
  padding-bottom: 16rpx;
  border-bottom: 1rpx solid #f0f0f0;
}
.status-item {
  display: flex;
  align-items: center;
  gap: 8rpx;
}
.status-indicator {
  width: 12rpx;
  height: 12rpx;
  border-radius: 50%;
}
.status-indicator.online {
  background: #52c41a;
  box-shadow: 0 0 8rpx rgba(82, 196, 26, 0.4);
}
.status-indicator.offline {
  background: #ff4d4f;
  box-shadow: 0 0 8rpx rgba(255, 77, 79, 0.4);
}
.status-text {
  font-size: 26rpx;
  color: #666;
  font-weight: 500;
}
.refresh-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  padding: 12rpx 20rpx;
  min-width: 100rpx;
  background: #1890ff;
  color: white;
  border-radius: 24rpx;
  font-size: 24rpx;
  transition: all 0.3s ease;
  position: relative;
}
.refresh-btn:active {
  transform: scale(0.95);
  background: #096dd9;
}
.refresh-icon {
  width: 28rpx;
  height: 28rpx;
  filter: brightness(0) invert(1);
  left: 16rpx;
}
.refresh-text {
  text-align: center;
}
/* 气象数据网格 */
.weather-data-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20rpx;
  margin-bottom: 24rpx;
}
.weather-data-item {
  display: flex;
  align-items: center;
  gap: 16rpx;
  padding: 24rpx;
  background: #f8f9fa;
  border-radius: 16rpx;
  border-left: 4rpx solid;
  transition: all 0.3s ease;
  min-height: 120rpx;
  box-sizing: border-box;
}
.weather-data-item:active {
  transform: scale(0.98);
}
.weather-data-item.humidity {
  border-left-color: #1890ff;
}
.weather-data-item.temperature {
  border-left-color: #ff4d4f;
}
.weather-data-item.uv {
  border-left-color: #faad14;
}
.weather-data-item.light {
  border-left-color: #52c41a;
}
.weather-data-item.rainfall {
  border-left-color: #722ed1;
}
.weather-data-item.wind-speed {
  border-left-color: #13c2c2;
}
.weather-data-item.wind-direction {
  border-left-color: #eb2f96;
}
.data-icon {
  width: 56rpx;
  height: 56rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  background: white;
  border-radius: 12rpx;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
  flex-shrink: 0;
}
.data-icon image {
  width: 36rpx;
  height: 36rpx;
}
.data-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
  min-width: 0;
  overflow: hidden;
}
.data-label {
  font-size: 26rpx;
  color: #333;
  font-weight: 500;
  line-height: 1.4;
}
.data-value {
  font-size: 36rpx;
  color: #1890ff;
  font-weight: 700;
  line-height: 1.2;
}
/* 风向显示 */
.wind-direction-display {
  display: flex;
  align-items: center;
  gap: 8rpx;
}
.wind-arrow {
  width: 24rpx;
  height: 24rpx;
  transition: transform 0.3s ease;
}
/* 最后更新时间 */
.last-update {
  text-align: center;
  padding-top: 16rpx;
  border-top: 1rpx solid #f0f0f0;
}
.update-text {
  font-size: 24rpx;
  color: #999;
}
/* 无数据提示 */
.no-data {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80rpx 20rpx;
  color: #999;
}
.no-data-icon {
  width: 120rpx;
  height: 120rpx;
  margin-bottom: 20rpx;
  opacity: 0.5;
}
.no-data-text {
  font-size: 28rpx;
  color: #999;
}
/* 响应式适配 */
@@ -155,6 +476,25 @@
    padding: 16rpx 2rpx;
    width: 25%; /* 确保小屏幕下也均分 */
  }
  /* 气象站数据项响应式字体 */
  .weather-data-item .data-label {
    font-size: 22rpx;
  }
  .weather-data-item .data-value {
    font-size: 28rpx;
  }
  .weather-data-item .data-icon {
    width: 50rpx;
    height: 50rpx;
  }
  .weather-data-item .data-icon image {
    width: 32rpx;
    height: 32rpx;
  }
}
/* 超小屏幕适配 */
@@ -171,50 +511,106 @@
  .tab-item {
    padding: 12rpx 1rpx;
  }
  /* 气象站数据项超小屏幕响应式字体 */
  .weather-data-item .data-label {
    font-size: 20rpx;
  }
  .weather-data-item .data-value {
    font-size: 24rpx;
  }
  .weather-data-item .data-icon {
    width: 46rpx;
    height: 46rpx;
  }
  .weather-data-item .data-icon image {
    width: 30rpx;
    height: 30rpx;
  }
}
/* 摄像头列表样式 */
.camera-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  /* gap: 20rpx; */
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  /* 确保在不同设备上的一致性 */
  max-width: 100vw;
  overflow-x: hidden;
  /* 新增:移除左右内边距,确保完全填充 */
  /* padding: 0; */
  /* 新增:强制约束,防止ezplayer超出 */
  /* contain: layout style paint; */
  /* 新增:强制左对齐,无任何边距 */
  /* left: 0 !important;
  right: 0 !important; */
}
.camera-item {
  width: 100vw;
  background: #f8f9fa;
  border-radius: 0;
  padding: 20rpx;
  box-shadow: none;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  background: white;
  border-radius: 16rpx;
  /* 移除左右内边距,确保完全填充 */
  padding: 24rpx 0;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
  box-sizing: border-box;
  margin: 0 0 2rpx 0;
  margin: 0;
  position: relative;
  left: 0;
  right: 0;
  overflow: hidden;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  flex-grow: 0;
  /* 新增:强制约束,防止ezplayer超出 */
  contain: layout style paint;
  /* 新增:强制左对齐,无任何边距 */
  left: 0 !important;
  right: 0 !important;
}
/* 摄像头头部 */
.camera-header {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16rpx;
  margin-bottom: 20rpx;
  box-sizing: border-box;
  /* 防止文字溢出 */
  overflow: hidden;
  margin: 20rpx 10rpx;
}
.camera-name {
  font-size: 28rpx;
  font-size: 32rpx;
  font-weight: 600;
  color: #333;
  flex: 1;
  min-width: 0;
  /* 文字溢出处理 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.camera-status {
  padding: 8rpx 16rpx;
  border-radius: 20rpx;
  font-size: 22rpx;
  font-size: 24rpx;
  font-weight: 500;
  white-space: nowrap;
  flex-shrink: 0;
  /* 确保状态标签不被压缩 */
  min-width: fit-content;
}
.camera-status.online {
@@ -233,24 +629,402 @@
.camera-video-container {
  position: relative;
  width: 100%;
  height: 400rpx;
  max-width: 100%;
  min-width: 0;
  /* height: 400rpx; */
  /* 移除所有装饰性样式,确保完全填充 */
  border-radius: 0;
  overflow: hidden;
  margin-bottom: 16rpx;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  background-color: transparent;
  border: none;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止ezplayer超出容器 - 强化约束 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
  /* 新增:强制宽度约束,防止ezplayer超出 */
  max-width: 100vw !important;
  /* 新增:确保容器不会超出父元素 */
  contain: layout style paint !important;
  /* 新增:强制左对齐,防止右移 */
  left: 0 !important;
  right: 0 !important;
  /* 新增:强制填充整个屏幕 */
  /* width: 100vw !important;
  min-width: 100vw !important; */
}
/* 移除调试边框,避免影响ezplayer显示 */
/* 加载状态 */
.video-loading {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f8f9fa;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.loading-spinner {
  width: 60rpx;
  height: 60rpx;
  border: 4rpx solid #e3e3e3;
  border-top: 4rpx solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16rpx;
  /* 确保动画在不同设备上的一致性 */
  flex-shrink: 0;
}
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.loading-text {
  font-size: 26rpx;
  color: #666;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 错误状态 */
.video-error {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #fff2f0;
  border: 1rpx solid #ffccc7;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.error-icon {
  width: 80rpx;
  height: 80rpx;
  opacity: 0.6;
  margin-bottom: 16rpx;
  filter: grayscale(100%) brightness(0) saturate(100%) invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
.error-text {
  font-size: 26rpx;
  color: #ff4d4f;
  font-weight: 500;
  margin-bottom: 20rpx;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.retry-btn {
  display: flex;
  align-items: center;
  gap: 8rpx;
  padding: 12rpx 24rpx;
  background-color: #ff4d4f;
  color: white;
  border: none;
  border-radius: 20rpx;
  font-size: 24rpx;
  transition: all 0.3s ease;
  /* 确保按钮在不同设备上的一致性 */
  flex-shrink: 0;
  min-width: fit-content;
}
.retry-btn:active {
  background-color: #cf1322;
  transform: scale(0.98);
}
.retry-icon {
  width: 24rpx;
  height: 24rpx;
  filter: brightness(0) invert(1);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
/* 无播放地址状态 */
.video-no-url {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.no-url-icon {
  width: 80rpx;
  height: 80rpx;
  opacity: 0.4;
  margin-bottom: 16rpx;
  filter: grayscale(100%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
.no-url-text {
  font-size: 26rpx;
  color: #999;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.video-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止内容溢出 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
  /* 新增:移除所有边距和内边距 */
  margin: 0 !important;
  padding: 0 !important;
  /* 新增:强制左对齐 */
  left: 0 !important;
  right: 0 !important;
}
/* ezplayer组件样式优化 - 修复超出屏幕问题 */
.video-wrapper ezplayer {
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  border-radius: 12rpx;
  overflow: hidden !important;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止超出屏幕的关键设置 */
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  /* 强制约束尺寸 - 修复最小宽度问题 */
  max-width: 100% !important;
  max-height: 100% !important;
  /* 新增:强制约束到父容器 */
  transform: none !important;
  transform-origin: center center !important;
  /* 新增:确保不超出边界 */
  clip-path: inset(0 0 0 0) !important;
  /* 新增:防止任何形式的溢出 */
  contain: layout style paint !important;
  /* 新增:强制宽度约束,覆盖ezplayer的最小宽度限制 */
  min-width: 0 !important;
  min-height: 0 !important;
  /* 新增:确保组件完全约束在容器内 */
  box-sizing: border-box !important;
  /* 新增:移除所有边距和内边距 */
  margin: 0 !important;
  padding: 0 !important;
  /* 新增:强制完全填充容器 */
  inset: 0 !important;
}
/* 针对ezplayer组件的特殊约束 */
.video-wrapper ezplayer {
  /* 确保组件不会超出父容器 */
  box-sizing: border-box !important;
  /* 防止水平滚动 */
  overflow-x: hidden !important;
  overflow-y: hidden !important;
  /* 确保在flex容器中的行为 */
  flex: 0 0 auto !important;
  /* 防止缩放问题 */
  transform-origin: top left !important;
  /* 确保边框圆角生效 */
  border-radius: 12rpx !important;
  /* 新增:强制尺寸约束 */
  min-width: 0 !important;
  min-height: 0 !important;
  /* 新增:防止任何形式的拉伸 */
  flex-basis: auto !important;
  flex-grow: 0 !important;
  flex-shrink: 0 !important;
  /* 新增:确保定位正确 */
  position: absolute !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  /* 新增:强制宽度和高度 */
  width: 100% !important;
  height: 100% !important;
}
/* 新增:专门处理ezplayer暂停状态的样式 */
.video-wrapper ezplayer[data-paused="true"],
.video-wrapper ezplayer.paused {
  /* 强制约束宽度,防止超出屏幕 */
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  /* 确保组件完全在容器内 */
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  /* 防止任何形式的溢出 */
  overflow: hidden !important;
  /* 强制约束到父容器 */
  contain: layout style paint !important;
}
/* 新增:使用CSS Grid强制约束ezplayer */
.video-wrapper {
  display: grid !important;
  grid-template-columns: 1fr !important;
  grid-template-rows: 1fr !important;
  place-items: stretch !important;
}
/* 新增:只针对摄像头相关元素强制约束 */
.camera-list,
.camera-item,
.camera-video-container,
.video-wrapper,
.camera-header,
.camera-name,
.camera-status,
.camera-video-container > ezplayer,
.video-wrapper > ezplayer {
  max-width: 100% !important;
  min-width: 0 !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}
/* 新增:强制移除所有可能的边距和装饰 */
.camera-list,
.camera-item,
.camera-video-container,
.video-wrapper {
  margin: 0 !important;
  padding: 0 !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
}
/* 新增:特别针对ezplayer的强制约束 */
ezplayer {
  width: 100vw !important;
  height: 100% !important;
  max-width: 100vw !important;
  max-height: 100% !important;
  min-width: 100vw !important;
  min-height: 0 !important;
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
  contain: layout style paint !important;
  /* 新增:强制填充整个屏幕宽度 */
  margin: 0 !important;
  padding: 0 !important;
  transform: none !important;
  transform-origin: center center !important;
  /* 新增:强制移除所有装饰 */
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
  /* 新增:强制约束到屏幕边缘 */
  inset: 0 !important;
}
.video-wrapper ezplayer {
  grid-column: 1 !important;
  grid-row: 1 !important;
  place-self: stretch !important;
  /* 强制完全填充网格单元格 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
}
/* 视频包装器的绝对定位约束 */
.video-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止内容溢出 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
}
.live-player {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  background-color: #000;
  border-radius: 0;
  border-radius: 12rpx;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.video-overlay {
@@ -363,44 +1137,67 @@
.video-offline {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  background-color: #f5f5f5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12rpx;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.offline-icon {
  width: 60rpx;
  height: 60rpx;
  opacity: 0.5;
  width: 80rpx;
  height: 80rpx;
  opacity: 0.4;
  margin-bottom: 16rpx;
  filter: grayscale(100%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
.offline-text {
  font-size: 24rpx;
  font-size: 28rpx;
  color: #999;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 操作按钮 */
.camera-actions {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  gap: 16rpx;
  box-sizing: border-box;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.action-btn {
  flex: 1;
  height: 64rpx;
  border-radius: 32rpx;
  height: 72rpx;
  border-radius: 36rpx;
  font-size: 26rpx;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  transition: all 0.3s ease;
  box-sizing: border-box;
  /* 确保按钮在不同设备上的一致性 */
  min-width: 0;
  overflow: hidden;
}
.action-btn.primary {
@@ -409,21 +1206,639 @@
}
.action-btn.primary:active {
  background-color: #0050b3;
  background-color: #096dd9;
  transform: scale(0.98);
}
.action-btn.secondary {
  background-color: white;
  color: #1890FF;
  border: 1rpx solid #1890FF;
  background-color: #f5f5f5;
  color: #666;
  border: 1rpx solid #d9d9d9;
}
.action-btn.secondary:active {
  background-color: #f0f8ff;
  background-color: #e8e8e8;
  transform: scale(0.98);
}
.action-btn.disabled {
  background-color: #f5f5f5;
  color: #bfbfbf;
/* 禁用状态 */
.action-btn[disabled] {
  background-color: #f5f5f5 !important;
  color: #bfbfbf !important;
  border-color: #d9d9d9 !important;
  cursor: not-allowed;
  opacity: 0.6;
  /* 确保禁用状态在不同设备上的一致性 */
  transform: none !important;
}
.action-btn[disabled]:active {
  transform: none !important;
  background-color: #f5f5f5 !important;
}
.action-btn.primary[disabled] {
  background-color: #d9d9d9 !important;
  color: #bfbfbf !important;
}
.action-btn.secondary[disabled] {
  background-color: #f5f5f5 !important;
  color: #bfbfbf !important;
  border-color: #d9d9d9 !important;
}
.action-icon {
  width: 32rpx;
  height: 32rpx;
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
/* 响应式优化 - 确保在不同设备上的一致性 */
@media (max-width: 400px) {
  .camera-item {
    padding: 20rpx;
    margin-bottom: 16rpx;
  }
  .camera-header {
    margin-bottom: 16rpx;
  }
  .camera-name {
    font-size: 28rpx;
  }
  .camera-status {
    font-size: 22rpx;
    padding: 6rpx 12rpx;
  }
  .camera-video-container {
    height: 320rpx;
    margin-bottom: 16rpx;
  }
  .action-btn {
    height: 64rpx;
    font-size: 24rpx;
  }
  .action-icon {
    width: 28rpx;
    height: 28rpx;
  }
}
/* 确保在不同设备上的一致性 - 额外的兼容性处理 */
.camera-item {
  /* 防止在不同设备上的布局差异 */
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
}
.camera-video-container {
  /* 防止在不同设备上的显示差异 */
  transform: translateZ(0);
  backface-visibility: hidden;
}
/* 修复可能的溢出问题 */
.camera-list {
  max-width: 100%;
  overflow: hidden;
  /* 确保在不同设备上的一致性 */
  transform: translateZ(0);
}
.camera-item {
  overflow: hidden;
  /* 确保在不同设备上的一致性 */
  transform: translateZ(0);
}
/* 针对真机的特殊优化 */
@media screen and (max-device-width: 750px) {
  .camera-item {
    /* 真机上可能需要稍微调整间距 */
    margin-bottom: 16rpx;
  }
  .camera-video-container {
    /* 真机上可能需要稍微调整高度 */
    height: 380rpx;
  }
  .action-btn {
    /* 真机上可能需要稍微调整高度 */
    height: 68rpx;
  }
}
/* 土壤墒情站专用样式 */
.weather-data-item.soil-item {
  border-left: 4rpx solid;
  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
  border-radius: 16rpx;
  padding: 24rpx;
  margin-bottom: 16rpx;
  transition: all 0.3s ease;
}
.weather-data-item.soil-item:active {
  transform: scale(0.98);
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
}
/* 土壤层1 - 蓝色系 */
.weather-data-item.soil-item:nth-child(1),
.weather-data-item.soil-item:nth-child(2) {
  border-left-color: #1890ff;
  background: linear-gradient(135deg, #f0f8ff 0%, #ffffff 100%);
}
/* 土壤层2 - 绿色系 */
.weather-data-item.soil-item:nth-child(3),
.weather-data-item.soil-item:nth-child(4) {
  border-left-color: #52c41a;
  background: linear-gradient(135deg, #f6ffed 0%, #ffffff 100%);
}
/* 土壤层3 - 橙色系 */
.weather-data-item.soil-item:nth-child(5),
.weather-data-item.soil-item:nth-child(6) {
  border-left-color: #fa8c16;
  background: linear-gradient(135deg, #fff7e6 0%, #ffffff 100%);
}
/* 土壤层4 - 紫色系 */
.weather-data-item.soil-item:nth-child(7),
.weather-data-item.soil-item:nth-child(8) {
  border-left-color: #722ed1;
  background: linear-gradient(135deg, #f9f0ff 0%, #ffffff 100%);
}
/* 土壤层5 - 红色系 */
.weather-data-item.soil-item:nth-child(9),
.weather-data-item.soil-item:nth-child(10) {
  border-left-color: #f5222d;
  background: linear-gradient(135deg, #fff1f0 0%, #ffffff 100%);
}
/* 土壤墒情站数据网格优化 */
.weather-data-grid:has(.soil-item) {
  grid-template-columns: 1fr 1fr;
  gap: 16rpx;
}
/* 土壤墒情站数据项内容优化 */
.weather-data-item.soil-item .data-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
  min-width: 0; /* 防止内容溢出 */
  overflow: hidden; /* 隐藏溢出内容 */
}
.weather-data-item.soil-item .data-label {
  font-size: 26rpx;
  color: #333;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap; /* 防止标签换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
}
.weather-data-item.soil-item .data-value {
  font-size: 36rpx;
  color: #1890ff;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap; /* 防止数值换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
}
/* 土壤墒情站图标优化 */
.weather-data-item.soil-item .data-icon {
  width: 56rpx;
  height: 56rpx;
  background: white;
  border-radius: 12rpx;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
  border: 2rpx solid rgba(255, 255, 255, 0.8);
}
.weather-data-item.soil-item .data-icon image {
  width: 36rpx;
  height: 36rpx;
}
/* 土壤墒情站悬停效果 */
.weather-data-item.soil-item:hover {
  transform: translateY(-2rpx);
  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
}
/* 土壤墒情站响应式优化 */
@media (max-width: 400px) {
  .weather-data-grid:has(.soil-item) {
    grid-template-columns: 1fr 1fr;
    gap: 12rpx;
  }
  .weather-data-item.soil-item {
    padding: 16rpx;
    margin-bottom: 8rpx;
  }
  .weather-data-item.soil-item .data-label {
    font-size: 22rpx;
  }
  .weather-data-item.soil-item .data-value {
    font-size: 28rpx;
  }
  .weather-data-item.soil-item .data-icon {
    width: 50rpx;
    height: 50rpx;
  }
  .weather-data-item.soil-item .data-icon image {
    width: 32rpx;
    height: 32rpx;
  }
}
/* 超小屏幕响应式优化 */
@media (max-width: 320px) {
  .weather-data-grid:has(.soil-item) {
    grid-template-columns: 1fr 1fr;
    gap: 8rpx;
  }
  .weather-data-item.soil-item {
    padding: 12rpx;
    margin-bottom: 6rpx;
  }
  .weather-data-item.soil-item .data-label {
    font-size: 20rpx;
  }
  .weather-data-item.soil-item .data-value {
    font-size: 24rpx;
  }
  .weather-data-item.soil-item .data-icon {
    width: 46rpx;
    height: 46rpx;
  }
  .weather-data-item.soil-item .data-icon image {
    width: 30rpx;
    height: 30rpx;
  }
}
/* ==================== 水肥机样式 ==================== */
/* 水肥机选择器 */
.fertilizer-station-selector {
  /* 还原左右边距 */
  margin: 10rpx 20rpx;
  background: white;
  border-radius: 12rpx;
  padding: 20rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
/* 水肥机信息卡片 */
.fertilizer-info-card {
  /* 还原左右边距 */
  margin: 20rpx;
  background: white;
  border-radius: 16rpx;
  padding: 24rpx;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
/* 控制开关区域 */
.control-switches {
  margin-bottom: 20rpx;
  padding: 16rpx 20rpx;
  background: #f8f9fa;
  border-radius: 12rpx;
  border: 1rpx solid #e9ecef;
}
.section-title {
  font-size: 26rpx;
  font-weight: 600;
  color: #333;
  margin-bottom: 16rpx;
  display: block;
}
.switch-container {
  display: flex;
  gap: 60rpx;
  justify-content: center;
  align-items: center;
}
.switch-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 16rpx;
}
.switch-label {
  font-size: 24rpx;
  color: #666;
  font-weight: 500;
  white-space: nowrap;
}
.custom-switch {
  transform: scale(1.1);
}
/* 监测数据区域 */
.monitoring-data {
  margin-bottom: 24rpx;
}
.monitoring-data .section-title {
  margin: 0 0 20rpx 0;
  padding: 0 20rpx;
}
/* 水肥机数据网格 */
.monitoring-data .data-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20rpx;
  margin-bottom: 24rpx;
}
.monitoring-data .data-item {
  display: flex;
  align-items: center;
  gap: 16rpx;
  padding: 20rpx;
  background: #f8f9fa;
  border-radius: 16rpx;
  border-left: 4rpx solid;
  transition: all 0.3s ease;
  min-height: 100rpx;
  box-sizing: border-box;
}
.monitoring-data .data-item:active {
  transform: scale(0.98);
}
/* 水肥机数据项样式 */
.monitoring-data .data-item.pump-status {
  border-left-color: #1890ff;
  background: linear-gradient(135deg, #e6f7ff 0%, #ffffff 100%);
}
.monitoring-data .data-item.waste-flow {
  border-left-color: #52c41a;
  background: linear-gradient(135deg, #f6ffed 0%, #ffffff 100%);
}
.monitoring-data .data-item.fertilizing-duration {
  border-left-color: #fa8c16;
  background: linear-gradient(135deg, #fff7e6 0%, #ffffff 100%);
}
.monitoring-data .data-item.mixing-duration {
  border-left-color: #722ed1;
  background: linear-gradient(135deg, #f9f0ff 0%, #ffffff 100%);
}
.monitoring-data .data-item.mixing-set-time {
  border-left-color: #13c2c2;
  background: linear-gradient(135deg, #e6fffb 0%, #ffffff 100%);
}
.monitoring-data .data-item.fertilizing-set-time {
  border-left-color: #eb2f96;
  background: linear-gradient(135deg, #fff0f6 0%, #ffffff 100%);
}
/* 状态徽章 */
.status-badge {
  padding: 8rpx 16rpx;
  border-radius: 20rpx;
  font-size: 24rpx;
  font-weight: 600;
  text-align: center;
  min-width: 80rpx;
}
.status-badge.normal {
  background: #f6ffed;
  color: #52c41a;
  border: 1rpx solid #b7eb8f;
}
.status-badge.abnormal {
  background: #fff2f0;
  color: #ff4d4f;
  border: 1rpx solid #ffccc7;
}
/* 水肥机数据项图标 */
.monitoring-data .data-item .data-icon {
  width: 56rpx;
  height: 56rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  background: white;
  border-radius: 12rpx;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
  flex-shrink: 0;
}
.monitoring-data .data-item .data-icon image {
  width: 36rpx;
  height: 36rpx;
}
/* 水肥机数据项内容 */
.monitoring-data .data-item .data-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
  min-width: 0;
  overflow: hidden;
}
.monitoring-data .data-item .data-label {
  font-size: 26rpx;
  color: #333;
  font-weight: 500;
  line-height: 1.4;
}
.monitoring-data .data-item .data-value {
  font-size: 36rpx;
  color: #1890ff;
  font-weight: 700;
  line-height: 1.2;
}
/* 水肥机响应式优化 */
@media (max-width: 400px) {
  .control-switches {
    padding: 12rpx 16rpx;
    margin-bottom: 16rpx;
  }
  .section-title {
    font-size: 24rpx;
    margin-bottom: 12rpx;
  }
  .switch-container {
    gap: 40rpx;
  }
  .switch-item {
    gap: 12rpx;
  }
  .switch-label {
    font-size: 22rpx;
  }
  .custom-switch {
    transform: scale(1.0);
  }
  .monitoring-data .data-grid {
    grid-template-columns: 1fr;
    gap: 16rpx;
  }
  .monitoring-data .data-item {
    padding: 20rpx;
  }
  .monitoring-data .data-item .data-label {
    font-size: 24rpx;
  }
  .monitoring-data .data-item .data-value {
    font-size: 32rpx;
  }
  .monitoring-data .data-item .data-icon {
    width: 50rpx;
    height: 50rpx;
  }
  .monitoring-data .data-item .data-icon image {
    width: 32rpx;
    height: 32rpx;
  }
}
/* ezplayer组件样式 - 防止变形和超出屏幕 */
.video-wrapper ezplayer {
  /* 基础尺寸约束 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  /* 位置约束 */
  position: relative !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  /* 溢出控制 */
  overflow: hidden !important;
  clip-path: inset(0 0 0 0) !important;
  /* 变换约束 */
  transform: none !important;
  transform-origin: center center !important;
  /* 布局约束 */
  contain: layout style paint !important;
  flex-basis: auto !important;
  flex-grow: 0 !important;
  flex-shrink: 0 !important;
  /* 盒模型约束 */
  box-sizing: border-box !important;
  margin: 0 !important;
  padding: 0 !important;
  /* 渲染优化 */
  backface-visibility: hidden !important;
  perspective: 1000px !important;
  will-change: auto !important;
  /* 真机特殊处理 */
  -webkit-transform: none !important;
  -webkit-transform-origin: center center !important;
  -webkit-backface-visibility: hidden !important;
  -webkit-perspective: 1000px !important;
}
/* 真机上的特殊约束 */
@media screen and (max-device-width: 750px) {
  .video-wrapper ezplayer {
    /* 真机上更严格的约束 */
    max-width: 100vw !important;
    max-height: 100vh !important;
    left: 0 !important;
    right: 0 !important;
    top: 0 !important;
    bottom: 0 !important;
    /* 防止真机上的缩放问题 */
    -webkit-transform: scale(1) !important;
    transform: scale(1) !important;
    /* 真机上的溢出控制 */
    overflow: hidden !important;
    clip: rect(0, auto, auto, 0) !important;
  }
}
/* 暂停状态的特殊处理 */
.video-wrapper ezplayer[data-paused="true"] {
  /* 暂停时保持尺寸 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  /* 暂停时防止变形 */
  transform: none !important;
  -webkit-transform: none !important;
  /* 暂停时的溢出控制 */
  overflow: hidden !important;
  clip-path: inset(0 0 0 0) !important;
project.config.json
@@ -17,7 +17,8 @@
      "ignore": [],
      "disablePlugins": [],
      "outputPath": ""
    }
    },
    "condition": true
  },
  "condition": {},
  "editorSetting": {
project.private.config.json
@@ -5,5 +5,5 @@
    "compileHotReLoad": true,
    "urlCheck": false
  },
  "libVersion": "trial"
  "libVersion": "3.9.1"
}
utils/projectConfig.js
@@ -1,10 +1,11 @@
// 项目配置,包含各项目的专有设置
// 服务器地址配置
const SERVER_INFO = {
  URL_233: 'https://sp.dayuyanjiuyuan.top/',
  URL_233: 'https://wanzheng.dayuyanjiuyuan.top/',
  URL_55: 'https://irrigate.dayuyanjiuyuan.top/',
  URL_166: 'https://no253541tf71.vicp.fun/',
  URL_121: 'https://shifanqu1.dayuyanjiuyuan.top/',
  URL_166: 'https://wanzheng.dayuyanjiuyuan.top/frp/',
  // URL_121: 'https://shifanqu1.dayuyanjiuyuan.top/',
  URL_121: 'https://wanzheng.dayuyanjiuyuan.top/frp/',
  URL_87: 'http://192.168.10.87:54321/'
};
@@ -15,6 +16,7 @@
    operatorId: '2025040415305200007', // 统一ID用于operator和clientId
    needLogin: false, // 不需要登录
    loginType: 'code', // 验证码登录
    monitor:false,//是否可以进入综合站监测
    serverId: '55',
    get serverUrl() {
      return SERVER_INFO.URL_55;
@@ -26,6 +28,7 @@
    operatorId: '2025033115305200006', // 统一ID用于operator和clientId
    needLogin: false, // 不需要登录
    loginType: 'code', // 验证码登录
    monitor:true,//是否可以进入综合站监测
    serverId: '121',
    get serverUrl() {
      return SERVER_INFO.URL_121;
@@ -37,6 +40,7 @@
    operatorId: '', // 统一ID用于operator和clientId
    needLogin: true, // 需要登录
    loginType: 'code', // 账号密码登录  account
    monitor:true,//是否可以进入综合站监测
    serverId: '166',
    get serverUrl() {
      return SERVER_INFO.URL_166;
@@ -48,6 +52,7 @@
    operatorId: '', // 统一ID用于operator和clientId 2025041710412400006
    needLogin: true, // 需要登录
    loginType: 'code', // 账号密码登录
    monitor:false,//是否可以进入综合站监测
    serverId: '121',
    get serverUrl() {
      return SERVER_INFO.URL_121;
@@ -59,6 +64,7 @@
    operatorId: '', // 统一ID用于operator和clientId
    needLogin: true, // 不需要登录
    loginType: 'code', // 验证码登录
    monitor:false,//是否可以进入综合站监测
    serverId: '121',
    get serverUrl() {
      return SERVER_INFO.URL_121;
@@ -70,6 +76,7 @@
    operatorId: '', // 统一ID用于operator和clientId
    needLogin: true, // 不需要登录
    loginType: 'code', // 账号密码登录
    monitor:false,//是否可以进入综合站监测
    serverId: '233',
    get serverUrl() {
      return SERVER_INFO.URL_233;
@@ -81,6 +88,7 @@
    operatorId: '2025051317031200006', // 统一ID用于operator和clientId
    needLogin: false, // 不需要登录
    loginType: 'code', // 账号密码登录
    monitor:false,//是否可以进入综合站监测
    serverId: '233',
    get serverUrl() {
      return SERVER_INFO.URL_233;