更新分享
@@ -33,13 +33,15 @@
|
|||||||
<!-- <!–读取外部存储权限–>-->
|
<!-- <!–读取外部存储权限–>-->
|
||||||
<!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
|
<!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />-->
|
||||||
<!--相机权限-->
|
<!--相机权限-->
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="太和e护">
|
android:label="太和e护"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
|
>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
|||||||
BIN
assets/img/avatar.png
Normal file
|
After Width: | Height: | Size: 862 B |
BIN
assets/img/body_black.gif
Normal file
|
After Width: | Height: | Size: 814 KiB |
BIN
assets/img/body_white.gif
Normal file
|
After Width: | Height: | Size: 505 KiB |
1
assets/img/icon/arrow_down.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13.63 7.32"><defs><style>.cls-1{fill:#fff;}</style></defs><title>资源 249 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M6.82,7.32a.51.51,0,0,1-.36-.15L.15.85a.48.48,0,0,1,0-.7.48.48,0,0,1,.7,0l6,6,6-6a.48.48,0,0,1,.7,0,.48.48,0,0,1,0,.7L7.17,7.17A.5.5,0,0,1,6.82,7.32Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 404 B |
21
assets/img/icon/bed_status.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34.46 29.97">
|
||||||
|
<title>资源 239</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<line x1="3.59" y1="28.97" x2="32.17" y2="28.97"
|
||||||
|
stroke="#85f5ff"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none" />
|
||||||
|
<path d="M14.41,8.67a1,1,0,0,1-.71-.29l-6-6-6,6a1,1,0,0,1-1.42,0A1,1,0,0,1,.29,7L7,.29a1,1,0,0,1,1.41,0L15.11,7a1,1,0,0,1-.7,1.71Z"
|
||||||
|
fill="#85f5ff" />
|
||||||
|
<path d="M7.7,19.3a1,1,0,0,1-1-1V1a1,1,0,1,1,2,0V18.3A1,1,0,0,1,7.7,19.3Z"
|
||||||
|
fill="#85f5ff" />
|
||||||
|
<path d="M26.75,19.3a1,1,0,0,1-.7-.29l-6.71-6.67a1,1,0,0,1,0-1.42,1,1,0,0,1,1.41,0l6,6,6-6a1,1,0,1,1,1.41,1.42L27.46,19A1,1,0,0,1,26.75,19.3Z"
|
||||||
|
fill="#85f5ff" />
|
||||||
|
<path d="M26.75,19.3a1,1,0,0,1-1-1V1a1,1,0,0,1,2,0V18.3A1,1,0,0,1,26.75,19.3Z"
|
||||||
|
fill="#85f5ff" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 988 B |
11
assets/img/icon/bodymotion.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27.29 33.07">
|
||||||
|
<title>资源 238</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path d="M1,33.07a1,1,0,0,1-.71-1.71l7-7.06-7-7.06a1,1,0,0,1,0-1.41l7-7.06-7-7.06A1,1,0,0,1,.3.29,1,1,0,0,1,1.71.3L9.43,8.06a1,1,0,0,1,0,1.41l-7,7.06,7,7.07a1,1,0,0,1,0,1.41L1.71,32.77A1,1,0,0,1,1,33.07Z"
|
||||||
|
fill="#64c961"/>
|
||||||
|
<path d="M26.29,33.07a1,1,0,0,1-.71-.3L17.85,25a1,1,0,0,1,0-1.41l7-7.07-7-7.06a1,1,0,0,1,0-1.41L25.58.3A1,1,0,0,1,27,.29a1,1,0,0,1,0,1.42L20,8.77l7,7.06a1,1,0,0,1,0,1.41L20,24.3l7,7.06a1,1,0,0,1-.71,1.71Z"
|
||||||
|
fill="#64c961"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 685 B |
13
assets/img/icon/breathe.svg
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 27.98">
|
||||||
|
<title>资源 241</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path d="M23.9,8.63a11.1,11.1,0,0,1-8-3.61C9.17-1.69,2,4.77,1.68,5.05A1,1,0,1,1,.32,3.58c.09-.08,8.92-8,17,0,6.71,6.71,13.9.25,14.2,0a1,1,0,1,1,1.36,1.47C32.8,5.1,28.88,8.63,23.9,8.63Z"
|
||||||
|
fill="#85f5ff"/>
|
||||||
|
<path d="M23.9,18.3a11.13,11.13,0,0,1-8-3.6C9.17,8,2,14.45,1.68,14.72a1,1,0,0,1-1.42-.05,1,1,0,0,1,.06-1.42c.09-.08,8.92-8,17,0,6.71,6.72,13.9.25,14.2,0a1,1,0,1,1,1.36,1.47C32.8,14.78,28.88,18.3,23.9,18.3Z"
|
||||||
|
fill="#85f5ff"/>
|
||||||
|
<path d="M23.9,28a11.1,11.1,0,0,1-8-3.61h0c-6.69-6.69-13.9-.25-14.2,0a1,1,0,0,1-1.42-.06,1,1,0,0,1,.06-1.41c.09-.08,8.92-8,17,0h0c6.71,6.71,13.9.25,14.2,0a1,1,0,1,1,1.36,1.47C32.8,24.45,28.88,28,23.9,28Z"
|
||||||
|
fill="#85f5ff"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 907 B |
15
assets/img/icon/breathe_pause.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.11">
|
||||||
|
<title>资源 237</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path d="M23.9,11.19a11.13,11.13,0,0,1-8-3.6C9.17.87,2,7.34,1.68,7.62A1,1,0,0,1,.26,7.56,1,1,0,0,1,.32,6.14c.09-.08,8.92-8,17,0,6.71,6.72,13.9.25,14.2,0a1,1,0,0,1,1.36,1.48C32.8,7.67,28.88,11.19,23.9,11.19Z"
|
||||||
|
fill="#ff7159"/>
|
||||||
|
<path d="M23.9,20.87a11.1,11.1,0,0,1-8-3.61C9.17,10.55,2,17,1.68,17.29A1,1,0,1,1,.32,15.82c.09-.08,8.92-8,17,0,6.71,6.71,13.9.25,14.2,0a1,1,0,1,1,1.36,1.47C32.8,17.34,28.88,20.87,23.9,20.87Z"
|
||||||
|
fill="#ff7159"/>
|
||||||
|
<path d="M23.9,30.54a11.13,11.13,0,0,1-8-3.6h0C9.19,20.25,2,26.69,1.68,27a1,1,0,0,1-1.42-.06,1,1,0,0,1,.06-1.42c.09-.08,8.92-8,17,0h0c6.71,6.72,13.9.25,14.2,0A1,1,0,0,1,32.86,27C32.8,27,28.88,30.54,23.9,30.54Z"
|
||||||
|
fill="#ff7159"/>
|
||||||
|
<path d="M7.2,33.11A1.07,1.07,0,0,1,6.68,33a1,1,0,0,1-.34-1.38L25.13.48A1,1,0,0,1,26.5.14a1,1,0,0,1,.34,1.38L8.05,32.63A1,1,0,0,1,7.2,33.11Z"
|
||||||
|
fill="#ff7159"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
8
assets/img/icon/device_issue.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26">
|
||||||
|
<title>资源 251</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path fill="#ff7159" d="M13,0A13,13,0,1,0,26,13,13,13,0,0,0,13,0Zm0,20.8a1.33,1.33,0,1,1,1.33-1.33A1.33,1.33,0,0,1,13,20.8ZM14.44,6l-.27,9.46a1,1,0,0,1-1.12.88h-.21a1,1,0,0,1-1.11-.88L11.44,6a1.35,1.35,0,0,1,1.37-1.39h.27A1.34,1.34,0,0,1,14.44,6Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 454 B |
1
assets/img/icon/group.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27.01 23.24"><defs><style>.cls-1{fill:#fff;}</style></defs><title>资源 248 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M199.81,18.84a6.5,6.5,0,1,0-9.13-9,6.78,6.78,0,0,0-.94,1.86v0a4.07,4.07,0,0,1,1.87,1,4.54,4.54,0,0,1,.91-1.9A4.45,4.45,0,1,1,196,18.06a4.34,4.34,0,0,1-1.09-.14h0a4.27,4.27,0,0,1-1.88-1,4.52,4.52,0,0,1-.9,1.9s0,0,0,0l0,0a4.51,4.51,0,0,1-2.38,1.45l-.19.17a9.47,9.47,0,0,0-1.74,1.94l-.09.14a8,8,0,0,1,1-.07,7.15,7.15,0,0,1,1.55.16,3.24,3.24,0,0,1,.49-.49,7,7,0,0,1,1.47-1.07,6.75,6.75,0,0,1,1.06-.48,7.79,7.79,0,0,1,2.74-.5,7.87,7.87,0,0,1,7.81,7,1,1,0,0,0,1,.87,1,1,0,0,0,1-1.16,10,10,0,0,0-6-8Z" transform="translate(-178.79 -7.12)"/><path class="cls-1" d="M192.51,21.22a5.09,5.09,0,0,0,.71-.61,7.06,7.06,0,0,0,.71-.83,6.71,6.71,0,0,0,.85-1.64c0-.07.05-.14.08-.22h0a6.37,6.37,0,0,0,.29-1.92,6.48,6.48,0,0,0-6.06-6.48,6.56,6.56,0,0,0-6.81,5.19,6.5,6.5,0,0,0,2.51,6.52,9.93,9.93,0,0,0-6,8,1,1,0,0,0,1,1.15,1,1,0,0,0,1-.86,7.87,7.87,0,0,1,6.82-6.93,8.26,8.26,0,0,1,1-.07,7.06,7.06,0,0,1,1.54.16,7.87,7.87,0,0,1,6.27,6.84,1,1,0,0,0,1,.87h0a1,1,0,0,0,1-1.16,10,10,0,0,0-6-8Zm-8-6.79a4.36,4.36,0,0,1,4.41-2.87,3.51,3.51,0,0,1,.86.13h0a4.16,4.16,0,0,1,1.87,1A4.44,4.44,0,0,1,193.09,16a4.08,4.08,0,0,1-.11.93,4.5,4.5,0,0,1-.9,1.91s0,0,0,0a4.57,4.57,0,0,1-2.38,1.45,4.31,4.31,0,0,1-1,.12,4.46,4.46,0,0,1-4.18-6Z" transform="translate(-178.79 -7.12)"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
15
assets/img/icon/heart.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37.32 32.47">
|
||||||
|
<title>资源 242</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path
|
||||||
|
d="M18.49,4.76l.15.15.15-.15C23.61.2,29.14.09,33,3.83L33.1,4a10.08,10.08,0,0,1,.11,14.37L19.63,30.93a1.45,1.45,0,0,1-2,0L4.07,18.32l-.05,0a10.16,10.16,0,0,1,.2-14.35C8,.06,13.63.14,18.49,4.76Z"
|
||||||
|
fill="none"
|
||||||
|
stroke="#ff7159"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2.3"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 562 B |
8
assets/img/icon/in_bed.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.48 35.04">
|
||||||
|
<title>资源 253</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path fill="#00c1aa" d="M7.19,6.57a3.33,3.33,0,0,0,3.39-3.28A3.33,3.33,0,0,0,7.19,0,3.26,3.26,0,0,0,3.9,3.29,3.25,3.25,0,0,0,7.19,6.57Zm5,1.09H2A1.86,1.86,0,0,0,0,8.76v9.91a1,1,0,0,0,1.07,1s1.15,0,1.15-1.07v-6s.64-1.37,1.12.07V33.94A1,1,0,0,0,4.42,35H5.57a1.08,1.08,0,0,0,1.09-1.1V24.07a.62.62,0,0,1,.63-.56s.51.2.51.58V34a1,1,0,0,0,1.11,1H10s1.12-.07,1.12-1V12.59s.4-1.26,1.11,0l0,6.07S12,19.7,13.45,19.7a1,1,0,0,0,1-1V8.75a2.46,2.46,0,0,0-2.31-1.09Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 665 B |
1
assets/img/icon/loading.json
Normal file
1
assets/img/icon/not_bed.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.48 35.04"><defs><style>.cls-1{fill:#fff;opacity:0.2;}</style></defs><title>资源 247 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M7.19,6.57a3.33,3.33,0,0,0,3.39-3.28A3.33,3.33,0,0,0,7.19,0,3.26,3.26,0,0,0,3.9,3.29,3.25,3.25,0,0,0,7.19,6.57Zm5,1.09H2A1.86,1.86,0,0,0,0,8.76v9.91a1,1,0,0,0,1.07,1s1.15,0,1.15-1.07v-6s.64-1.37,1.12.07V33.94A1,1,0,0,0,4.42,35H5.57a1.08,1.08,0,0,0,1.09-1.1V24.07a.62.62,0,0,1,.63-.56s.51.2.51.58V34a1,1,0,0,0,1.11,1H10s1.12-.07,1.12-1V12.59s.4-1.26,1.11,0l0,6.07S12,19.7,13.45,19.7a1,1,0,0,0,1-1V8.75a2.46,2.46,0,0,0-2.31-1.09Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 695 B |
1
assets/img/icon/nulldata.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54.49 68.11"><defs><style>.cls-1{opacity:0.4;}.cls-2{fill:#fff;opacity:0.6;}</style></defs><title>资源 292 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><g class="cls-1"><path class="cls-2" d="M34.05,0H6.81A6.81,6.81,0,0,0,0,6.81H0V61.3a6.81,6.81,0,0,0,6.81,6.81H47.67a6.81,6.81,0,0,0,6.82-6.81V20.43Zm-3.4,5.11L49.38,23.84H30.65V5.11Z"/></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 451 B |
1
assets/img/icon/refresh.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.95 28.97"><defs><style>.cls-1{fill:#fff;}</style></defs><title>资源 232 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M24.32,3.81V2a1.21,1.21,0,0,1,.33-.87,1.22,1.22,0,0,1,1.7,0,1.28,1.28,0,0,1,.37.87V7.54a1.31,1.31,0,0,1-1.2,1.2H19.91A1.28,1.28,0,0,1,19,8.37a1.22,1.22,0,0,1,0-1.7,1.12,1.12,0,0,1,.87-.33h3.52A12.05,12.05,0,0,0,8.76,3.9,11.85,11.85,0,0,0,3.44,9.63a12.14,12.14,0,0,0-.64,7.86A11.93,11.93,0,0,0,7.08,24a12.19,12.19,0,0,0,7.42,2.55A12,12,0,0,0,23,23.06a12.27,12.27,0,0,0,3.5-7.56,1.2,1.2,0,0,1,1.2-1.1h0A1.22,1.22,0,0,1,29,15.71,14.5,14.5,0,1,1,2.34,6.57,14.2,14.2,0,0,1,8.56,1.24a14.43,14.43,0,0,1,8.28-1,14.7,14.7,0,0,1,7.46,3.6Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 784 B |
1
assets/img/icon/share.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.06 28.06"><defs><style>.cls-1{fill:#fff;}</style></defs><title>资源 285 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M5.36,28.06A5.36,5.36,0,0,1,0,22.7V5.36A5.36,5.36,0,0,1,5.36,0H14a.81.81,0,1,1,0,1.62H5.36A3.75,3.75,0,0,0,1.62,5.36V22.7a3.75,3.75,0,0,0,3.74,3.75H22.7a3.75,3.75,0,0,0,3.75-3.75V13.88a.81.81,0,0,1,1.61,0V22.7a5.36,5.36,0,0,1-5.36,5.36Z"/><path class="cls-1" d="M13.19,15.71a.83.83,0,0,1-.58-.24.82.82,0,0,1,0-1.15L25.5,1.62H19.24a.81.81,0,1,1,0-1.62h7.88a.94.94,0,0,1,.94,1V8.82a.81.81,0,1,1-1.61,0V3L13.76,15.48A.83.83,0,0,1,13.19,15.71Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 695 B |
1
assets/img/icon/signal0.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.57 22.17"><defs><style>.cls-1{fill:#fff;opacity:0.2;}</style></defs><title>资源 246 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><rect class="cls-1" y="16.63" width="6.01" height="5.54"/><rect class="cls-1" x="7.85" y="11.09" width="6.01" height="11.09"/><rect class="cls-1" x="15.71" y="4.62" width="6.01" height="17.55"/><rect class="cls-1" x="23.56" width="6.01" height="22.17"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 495 B |
1
assets/img/icon/signal1.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.57 22.17"><defs><style>.cls-1{fill:#00c1aa;}.cls-2{fill:#fff;opacity:0.2;}</style></defs><title>资源 245 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><rect class="cls-1" y="16.63" width="6.01" height="5.54"/><rect class="cls-2" x="7.85" y="11.09" width="6.01" height="11.09"/><rect class="cls-2" x="15.71" y="4.62" width="6.01" height="17.55"/><rect class="cls-2" x="23.56" width="6.01" height="22.17"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 516 B |
1
assets/img/icon/signal2.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.57 22.17"><defs><style>.cls-1{fill:#00c1aa;}.cls-2{fill:#fff;opacity:0.2;}</style></defs><title>资源 244 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><rect class="cls-1" y="16.63" width="6.01" height="5.54"/><rect class="cls-1" x="7.85" y="11.09" width="6.01" height="11.09"/><rect class="cls-2" x="15.71" y="4.62" width="6.01" height="17.55"/><rect class="cls-2" x="23.56" width="6.01" height="22.17"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 516 B |
1
assets/img/icon/signal3.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.57 22.17"><defs><style>.cls-1{fill:#00c1aa;}.cls-2{fill:#fff;opacity:0.2;}</style></defs><title>资源 243 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><rect class="cls-1" y="16.63" width="6.01" height="5.54"/><rect class="cls-1" x="7.85" y="11.09" width="6.01" height="11.09"/><rect class="cls-1" x="15.71" y="4.62" width="6.01" height="17.55"/><rect class="cls-2" x="23.56" width="6.01" height="22.17"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 516 B |
1
assets/img/icon/singal4.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?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="1745314396634" class="icon" viewBox="0 0 1365 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3510" xmlns:xlink="http://www.w3.org/1999/xlink" width="266.6015625" height="200"><path d="M0 767.769161h277.467989v255.769162H0zM362.416592 512h277.467989v512H362.416592zM725.29486 213.29486h277.467989v810.243463h-277.467989zM1087.711452 0h277.467989v1023.538323h-277.467989z" fill="#00C1AA" p-id="3511"></path></svg>
|
||||||
|
After Width: | Height: | Size: 568 B |
19
assets/img/icon/snore.svg
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34.71 31.32">
|
||||||
|
<title>资源 240</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path
|
||||||
|
d="M15.38,31.32H7.29a1,1,0,0,1-.65-1.77l7.58-6.32H5.78a1,1,0,0,1,0-2H17A1,1,0,0,1,17.62,23L10,29.32h5.34a1,1,0,0,1,0,2Z"
|
||||||
|
fill="#8e7def"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M31.91,20.47H22.78a1,1,0,0,1-.94-.66,1,1,0,0,1,.3-1.11L31,11.35H21.08a1,1,0,0,1,0-2H33.71a1,1,0,0,1,.94.65,1,1,0,0,1-.3,1.11l-8.81,7.36h6.37a1,1,0,0,1,0,2Z"
|
||||||
|
fill="#8e7def"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M16.86,15.37H3.49a1,1,0,0,1-.94-.66,1,1,0,0,1,.3-1.11L16.75,2H1A1,1,0,0,1,1,0H19.5a1,1,0,0,1,.94.66,1,1,0,0,1-.29,1.11L6.25,13.37H16.86a1,1,0,0,1,0,2Z"
|
||||||
|
fill="#8e7def"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 796 B |
1
assets/img/icon/tips.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.73 21.73"><defs><style>.cls-1{opacity:0.6;}.cls-2{fill:#fff;}</style></defs><title>资源 236 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><g class="cls-1"><path class="cls-2" d="M10.86,14.93a.91.91,0,1,0,.91.91A.91.91,0,0,0,10.86,14.93Z"/><path class="cls-2" d="M10.86,5a.91.91,0,0,0-.91.91v7a.91.91,0,1,0,1.82,0v-7A.9.9,0,0,0,10.86,5Z"/><path class="cls-2" d="M10.86,0A10.87,10.87,0,1,0,21.73,10.86,10.87,10.87,0,0,0,10.86,0Zm9,10.86a9,9,0,1,1-9-9A9,9,0,0,1,19.9,10.86Z"/></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 589 B |
8
assets/img/icon/upgrade.svg
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.38 23.89">
|
||||||
|
<title>资源 250</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<path fill="#10cff1" d="M25.06,6.83a10.33,10.33,0,0,0-19.94,2A7.81,7.81,0,0,0,0,16.22a7.62,7.62,0,0,0,7.67,7.67h6.51V16.77H9.94a.25.25,0,0,1-.19-.39l6.08-6.76a.42.42,0,0,1,.68,0l6.09,6.76a.23.23,0,0,1-.19.39H18.2v7.12h6.5a8.66,8.66,0,0,0,7.68-8.54A8.5,8.5,0,0,0,25.06,6.83Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 487 B |
1
assets/img/icon/wifi1.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38.14 28.69"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#f3f5f6;opacity:0.06;}</style></defs><title>资源 226 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M19.07,28.69a2.16,2.16,0,0,1,0-4.32,2.16,2.16,0,0,1,0,4.32Z"/><path class="cls-2" d="M25.11,21.61a1.65,1.65,0,0,1-1-.41A7.53,7.53,0,0,0,14,21.2a1.52,1.52,0,0,1-2.11-.1A1.51,1.51,0,0,1,12,19a10.53,10.53,0,0,1,14.1-.06,1.57,1.57,0,0,1-1,2.68Z"/><path class="cls-2" d="M7.57,16.16a1.41,1.41,0,0,1-1.05-.45,1.68,1.68,0,0,1-.46-1.21,1.36,1.36,0,0,1,.44-1A18.07,18.07,0,0,1,19,8.58h.12a18.4,18.4,0,0,1,12.57,4.95,1.44,1.44,0,0,1,.05,2.1,1.63,1.63,0,0,1-1.09.52h0a1.79,1.79,0,0,1-1.1-.42,15.21,15.21,0,0,0-20.86,0A1.6,1.6,0,0,1,7.57,16.16Z"/><path class="cls-2" d="M36.62,10.1a1.84,1.84,0,0,1-1.09-.41A23.44,23.44,0,0,0,19.08,3,23.75,23.75,0,0,0,2.58,9.64a1.53,1.53,0,0,1-2.18,0A1.55,1.55,0,0,1,0,8.58a1.44,1.44,0,0,1,.45-1,26.81,26.81,0,0,1,37.23-.07,1.51,1.51,0,0,1,0,2.12,1.43,1.43,0,0,1-1.08.5Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
1
assets/img/icon/wifi2.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38.14 28.69"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#f3f5f6;opacity:0.06;}</style></defs><title>资源 227 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M19.07,28.69a2.16,2.16,0,0,1,0-4.32,2.16,2.16,0,0,1,0,4.32Zm6-7.08a1.65,1.65,0,0,1-1-.41A7.53,7.53,0,0,0,14,21.2a1.52,1.52,0,0,1-2.11-.1A1.51,1.51,0,0,1,12,19a10.53,10.53,0,0,1,14.1-.06,1.57,1.57,0,0,1-1,2.68Z"/><path class="cls-2" d="M7.57,16.16a1.41,1.41,0,0,1-1.05-.45,1.68,1.68,0,0,1-.46-1.21,1.36,1.36,0,0,1,.44-1A18.07,18.07,0,0,1,19,8.58h.12a18.4,18.4,0,0,1,12.57,4.95,1.44,1.44,0,0,1,.05,2.1,1.63,1.63,0,0,1-1.09.52h0a1.79,1.79,0,0,1-1.1-.42,15.21,15.21,0,0,0-20.86,0A1.6,1.6,0,0,1,7.57,16.16Z"/><path class="cls-2" d="M36.62,10.1a1.84,1.84,0,0,1-1.09-.41A23.44,23.44,0,0,0,19.08,3,23.75,23.75,0,0,0,2.58,9.64a1.53,1.53,0,0,1-2.18,0A1.55,1.55,0,0,1,0,8.58a1.44,1.44,0,0,1,.45-1,26.81,26.81,0,0,1,37.23-.07,1.51,1.51,0,0,1,0,2.12,1.43,1.43,0,0,1-1.08.5Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
assets/img/icon/wifi3.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38.14 28.69"><defs><style>.cls-1{fill:#fff;}.cls-2,.cls-3{fill:#f3f5f6;}.cls-3{opacity:0.06;}</style></defs><title>资源 228 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M19.07,28.69a2.16,2.16,0,0,1,0-4.32,2.16,2.16,0,0,1,0,4.32Zm6-7.08a1.65,1.65,0,0,1-1-.41A7.53,7.53,0,0,0,14,21.2a1.52,1.52,0,0,1-2.11-.1A1.51,1.51,0,0,1,12,19a10.53,10.53,0,0,1,14.1-.06,1.57,1.57,0,0,1-1,2.68Z"/><path class="cls-2" d="M7.57,16.16a1.41,1.41,0,0,1-1.05-.45,1.68,1.68,0,0,1-.46-1.21,1.36,1.36,0,0,1,.44-1A18.07,18.07,0,0,1,19,8.58h.12a18.4,18.4,0,0,1,12.57,4.95,1.44,1.44,0,0,1,.05,2.1,1.63,1.63,0,0,1-1.09.52h0a1.79,1.79,0,0,1-1.1-.42,15.21,15.21,0,0,0-20.86,0A1.6,1.6,0,0,1,7.57,16.16Z"/><path class="cls-3" d="M36.62,10.1a1.84,1.84,0,0,1-1.09-.41A23.44,23.44,0,0,0,19.08,3,23.75,23.75,0,0,0,2.58,9.64a1.53,1.53,0,0,1-2.18,0A1.55,1.55,0,0,1,0,8.58a1.44,1.44,0,0,1,.45-1,26.81,26.81,0,0,1,37.23-.07,1.51,1.51,0,0,1,0,2.12,1.43,1.43,0,0,1-1.08.5Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
assets/img/icon/wifi4.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38.14 28.69"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#f3f5f6;}</style></defs><title>资源 229 </title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M19.07,28.69a2.16,2.16,0,0,1,0-4.32,2.16,2.16,0,0,1,0,4.32Zm6-7.08a1.65,1.65,0,0,1-1-.41A7.53,7.53,0,0,0,14,21.2a1.52,1.52,0,0,1-2.11-.1A1.51,1.51,0,0,1,12,19a10.53,10.53,0,0,1,14.1-.06,1.57,1.57,0,0,1-1,2.68Z"/><path class="cls-2" d="M7.57,16.16a1.41,1.41,0,0,1-1.05-.45,1.68,1.68,0,0,1-.46-1.21,1.36,1.36,0,0,1,.44-1A18.07,18.07,0,0,1,19,8.58h.12a18.4,18.4,0,0,1,12.57,4.95,1.44,1.44,0,0,1,.05,2.1,1.63,1.63,0,0,1-1.09.52h0a1.79,1.79,0,0,1-1.1-.42,15.21,15.21,0,0,0-20.86,0A1.6,1.6,0,0,1,7.57,16.16Z"/><path class="cls-2" d="M36.62,10.1a1.84,1.84,0,0,1-1.09-.41A23.44,23.44,0,0,0,19.08,3,23.75,23.75,0,0,0,2.58,9.64a1.53,1.53,0,0,1-2.18,0A1.55,1.55,0,0,1,0,8.58a1.44,1.44,0,0,1,.45-1,26.81,26.81,0,0,1,37.23-.07,1.51,1.51,0,0,1,0,2.12,1.43,1.43,0,0,1-1.08.5Z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/img/signal0.png
Normal file
|
After Width: | Height: | Size: 222 B |
BIN
assets/img/signal1.png
Normal file
|
After Width: | Height: | Size: 214 B |
BIN
assets/img/signal2.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
assets/img/signal3.png
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
assets/img/signal4.png
Normal file
|
After Width: | Height: | Size: 223 B |
BIN
assets/img/wifi1.png
Normal file
|
After Width: | Height: | Size: 910 B |
BIN
assets/img/wifi2.png
Normal file
|
After Width: | Height: | Size: 899 B |
BIN
assets/img/wifi3.png
Normal file
|
After Width: | Height: | Size: 996 B |
BIN
assets/img/wifi4.png
Normal file
|
After Width: | Height: | Size: 898 B |
@@ -27,7 +27,17 @@
|
|||||||
"设备报修": "设备报修",
|
"设备报修": "设备报修",
|
||||||
"操作说明": "操作说明",
|
"操作说明": "操作说明",
|
||||||
"关注我们": "关注我们",
|
"关注我们": "关注我们",
|
||||||
"当前版本": "当前版本"
|
"当前版本": "当前版本",
|
||||||
|
"未命名": "未命名",
|
||||||
|
"去登录": "去登录",
|
||||||
|
"头像限制": "头像图片不能超过1MB",
|
||||||
|
"头像上传失败":"头像上传失败",
|
||||||
|
"未选择图片":"未选择图片",
|
||||||
|
"上传成功":"上传成功",
|
||||||
|
"保存失败":"保存失败",
|
||||||
|
"保存成功":"保存成功",
|
||||||
|
"昵称为空":"昵称不能为空",
|
||||||
|
"查询失败":"查询用户资料失败"
|
||||||
},
|
},
|
||||||
"设备类型": {
|
"设备类型": {
|
||||||
"我的设备": "我的设备",
|
"我的设备": "我的设备",
|
||||||
@@ -75,7 +85,12 @@
|
|||||||
"是":"是",
|
"是":"是",
|
||||||
"否":"否",
|
"否":"否",
|
||||||
"确定绑定提示":"确定绑定该设备吗?",
|
"确定绑定提示":"确定绑定该设备吗?",
|
||||||
"连接成功":"连接成功"
|
"连接成功":"连接成功",
|
||||||
|
"连接异常":"连接异常",
|
||||||
|
"连接":"连接",
|
||||||
|
"输入wifi密码":"请输入wifi密码",
|
||||||
|
"显示密码":"显示",
|
||||||
|
"不显示密码":"不显示"
|
||||||
},
|
},
|
||||||
"登录页":{
|
"登录页":{
|
||||||
"欢迎使用太和e护":"欢迎使用太和e护",
|
"欢迎使用太和e护":"欢迎使用太和e护",
|
||||||
@@ -122,7 +137,13 @@
|
|||||||
"未连接":"未连接",
|
"未连接":"未连接",
|
||||||
"已连接":"已连接",
|
"已连接":"已连接",
|
||||||
"可用WLAN":"可用WLAN",
|
"可用WLAN":"可用WLAN",
|
||||||
"刷新":"刷新"
|
"刷新":"刷新",
|
||||||
|
"密码为空":"密码不能为空",
|
||||||
|
"配网成功":"配网成功",
|
||||||
|
"配网失败":"配网失败",
|
||||||
|
"配网中":"配网中",
|
||||||
|
"需配网":"请给设备配置网络!"
|
||||||
|
|
||||||
},
|
},
|
||||||
"其他手机登录页":{
|
"其他手机登录页":{
|
||||||
"输入内容":"输入手机号码/邮箱",
|
"输入内容":"输入手机号码/邮箱",
|
||||||
@@ -153,13 +174,118 @@
|
|||||||
"用户协议":"用户协议",
|
"用户协议":"用户协议",
|
||||||
"隐私协议":"隐私协议",
|
"隐私协议":"隐私协议",
|
||||||
"退出登录":"退出登录",
|
"退出登录":"退出登录",
|
||||||
"注销账号":"注销账号"
|
"注销账号":"注销账号",
|
||||||
|
"退出成功":"退出成功",
|
||||||
|
"退出失败":"退出失败"
|
||||||
|
|
||||||
},
|
},
|
||||||
"关于我们":{
|
"关于我们":{
|
||||||
"标题":"关于我们"
|
"标题":"关于我们"
|
||||||
},
|
},
|
||||||
"服务器":{
|
"服务器":{
|
||||||
"失败":"服务器内部错误,请联系管理员"
|
"失败":"服务器内部错误,请联系管理员"
|
||||||
}
|
},
|
||||||
|
"体征检测设备":{
|
||||||
|
"标题":"体征监测设备",
|
||||||
|
"输入关键词":"输入关键词",
|
||||||
|
"搜索":"搜索",
|
||||||
|
"我的e护":"我的e护",
|
||||||
|
"云关爱":"云关爱",
|
||||||
|
"设备ID":"设备ID",
|
||||||
|
"更新时间":"更新时间",
|
||||||
|
"设备来源":"设备来源",
|
||||||
|
"设备状态":"设备状态",
|
||||||
|
"人员资料":"人员资料",
|
||||||
|
"实时体征":"实时体征",
|
||||||
|
"消息回看":"消息回看",
|
||||||
|
"健康报告":"健康报告",
|
||||||
|
"首页展示":"首页展示",
|
||||||
|
"设备详情":"设备详情",
|
||||||
|
"重命名":"重命名",
|
||||||
|
"删除":"删除"
|
||||||
|
|
||||||
|
},
|
||||||
|
"设备详情":{
|
||||||
|
"标题":"设备详情",
|
||||||
|
"MAC":"MAC",
|
||||||
|
"设备来源":"设备来源",
|
||||||
|
"型号":"型号",
|
||||||
|
"设备名称":"设备名称",
|
||||||
|
"网络状态":"网络状态",
|
||||||
|
"版本":"版本",
|
||||||
|
"更新状态":"更新状态",
|
||||||
|
"更新时间":"更新时间",
|
||||||
|
"故障状态":"故障状态"
|
||||||
|
},
|
||||||
|
"实时体征":{
|
||||||
|
"标题":"实时体征",
|
||||||
|
"姓名":"姓名",
|
||||||
|
"年龄":"年龄",
|
||||||
|
"设备ID":"设备ID",
|
||||||
|
"体重":"体重",
|
||||||
|
"提示":"提示:实时体征分析时,人员应躺在指定床位上且设备正常运行,保持身体静止不动状态下10~30秒左右,即可显示实时体征数据。"
|
||||||
|
},
|
||||||
|
"待开发":{
|
||||||
|
"提示":"功能开发中..."
|
||||||
|
},
|
||||||
|
"扫一扫":{
|
||||||
|
"标题":"扫一扫",
|
||||||
|
"提示":"请扫描设备二维码",
|
||||||
|
"相册":"相册",
|
||||||
|
"手电筒":"手电筒"
|
||||||
|
},
|
||||||
|
"设备":{
|
||||||
|
"设备列表请求失败":"设备列表请求失败",
|
||||||
|
"设备列表请求成功":"设备列表请求成功"
|
||||||
|
},
|
||||||
|
"未命名":"未命名",
|
||||||
|
"未知时间":"-",
|
||||||
|
"设备ID":"设备ID",
|
||||||
|
"更新时间":"更新时间",
|
||||||
|
"已分享":"已分享",
|
||||||
|
"设备来源":"设备来源",
|
||||||
|
"云关爱":"云关爱",
|
||||||
|
"是否确认解绑":"是否确认解绑?",
|
||||||
|
"请求失败":"请求失败!",
|
||||||
|
"操作成功":"操作成功!",
|
||||||
|
"操作失败":"操作失败!",
|
||||||
|
"暂无数据":"暂无数据",
|
||||||
|
"请输入姓名":"请输入姓名",
|
||||||
|
"请选择生日":"请选择生日",
|
||||||
|
"请输入体重":"请输入体重",
|
||||||
|
"必须登录提示":"请先登录!",
|
||||||
|
"待开发功能":"功能开发中...",
|
||||||
|
"未知数据":"-",
|
||||||
|
"在离床":"在离床",
|
||||||
|
"体动":"体动",
|
||||||
|
"心率":"心率",
|
||||||
|
"打鼾":"打鼾",
|
||||||
|
"呼吸":"呼吸",
|
||||||
|
"呼吸暂停":"呼吸暂停",
|
||||||
|
"请保持静止":"请保持身体静止",
|
||||||
|
"健康报告":"健康报告",
|
||||||
|
"修改人员名称":"修改人员名称",
|
||||||
|
"在线":"在线",
|
||||||
|
"离线":"离线",
|
||||||
|
"有更新":"有更新",
|
||||||
|
"无更新":"无更新",
|
||||||
|
"有故障":"有故障",
|
||||||
|
"无故障":"无故障",
|
||||||
|
"人":"人",
|
||||||
|
"WIFI配置":"WIFI配置",
|
||||||
|
"分享设备":"分享设备",
|
||||||
|
"消息设置":"消息设置",
|
||||||
|
"设备分享":"设备分享",
|
||||||
|
"请输入对方手机号或邮箱":"请输入对方手机号或邮箱",
|
||||||
|
"微信好友一键分享":"微信好友一键分享",
|
||||||
|
"发送邀请":"发送邀请",
|
||||||
|
"要分享的设备":"要分享的设备",
|
||||||
|
"主设备":"主设备:",
|
||||||
|
"从设备":"从设备:",
|
||||||
|
"邀请成功":"邀请成功!",
|
||||||
|
"邀请失败":"邀请失败!",
|
||||||
|
"请输入手机号或者邮箱":"请输入手机号或者邮箱",
|
||||||
|
"请输入正确的手机号或者邮箱":"请输入正确的手机号或者邮箱",
|
||||||
|
"体征消息":"体征消息",
|
||||||
|
"系统消息":"系统消息"
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>需要使用相机扫码</string>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
|||||||
29
lib/common/color/ServiceConstant.dart
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
class ServiceConstant {
|
||||||
|
static const String baseHost = "vsbs-test.he-info.cn";//服务地址
|
||||||
|
static const String service_address = "http://$baseHost";
|
||||||
|
|
||||||
|
static String server_service = "/vsbs_app_server";//服务名称
|
||||||
|
|
||||||
|
static String send_code = "/api/verifycode/send";//发送验证码
|
||||||
|
static String login = "/api/user/login";//登录
|
||||||
|
static String get_bluetooth_device_status = "/api/device/status/info";//设备绑定状态
|
||||||
|
static String device_bind = "/api/device/bind";//设备绑定
|
||||||
|
static String device_type = "/api/device/type/list";//设备类型
|
||||||
|
static String upload_file = "/api/file/info";//上传文件
|
||||||
|
static String user_info = "/api/user/info";//更新用户资料,查询用户信息
|
||||||
|
static String device_list = "/api/device/list";//绑定设备列表
|
||||||
|
static String person_info = "/api/personnel/info";//用户资料
|
||||||
|
static String sleep_report = "/api/device/sleep/data";//睡眠报告
|
||||||
|
static String device_share = "/api/device/share";//分享设备
|
||||||
|
static String message_list = "/api/mesasge/list";//消息列表
|
||||||
|
static String device_show = "/api/device/bind";//更新设备绑定
|
||||||
|
static String disease_list = "/api/personnel/disease/list";//获取疾病类型
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static String logService = "$service_address/vsbs_log";
|
||||||
|
static const String webSocketService = "wss://$baseHost/vsbs_ws_gateway/ws";
|
||||||
|
static const String sleep_token = "HdAMjzqiYQKsmHRyEFKhfRGQ";
|
||||||
|
static const String sleep_report_url = "https://alltoone.he-info.cn/h5/#/mattress/sleep/sleep";
|
||||||
|
|
||||||
|
}
|
||||||
87
lib/common/util/DailyLogUtils.dart
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
class DailyLogUtils {
|
||||||
|
// 获取日志文件路径(按日期命名)
|
||||||
|
static Future<File> _getLogFile() async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
final date = DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||||||
|
final filePath = '${dir.path}/$date.log';
|
||||||
|
final file = File(filePath);
|
||||||
|
if (!await file.exists()) {
|
||||||
|
await file.create(recursive: true);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入日志核心方法,带日志等级
|
||||||
|
static Future<void> _writeLogWithLevel(String level, String content) async {
|
||||||
|
final file = await _getLogFile();
|
||||||
|
final now = DateTime.now();
|
||||||
|
final time = DateFormat('HH:mm:ss').format(now);
|
||||||
|
final logLine = '[$time][$level] $content\n';
|
||||||
|
await file.writeAsString(logLine, mode: FileMode.append);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入 info 日志(原 writeLog 保留)
|
||||||
|
static Future<void> writeLog(String content) async {
|
||||||
|
await _writeLogWithLevel('INFO', content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入 warning 日志
|
||||||
|
static Future<void> writeWarning(String content) async {
|
||||||
|
await _writeLogWithLevel('WARNING', content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入 error 日志
|
||||||
|
static Future<void> writeError(String content) async {
|
||||||
|
await _writeLogWithLevel('ERROR', content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入 debug 日志
|
||||||
|
static Future<void> writeDebug(String content) async {
|
||||||
|
await _writeLogWithLevel('DEBUG', content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取当天日志
|
||||||
|
static Future<String> readTodayLog() async {
|
||||||
|
final file = await _getLogFile();
|
||||||
|
return await file.readAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有日志文件(返回 File 列表)
|
||||||
|
static Future<List<FileSystemEntity>> listLogFiles() async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
final files = dir.listSync();
|
||||||
|
return files.where((f) => f.path.endsWith('.log')).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除所有日志
|
||||||
|
static Future<void> clearAllLogs() async {
|
||||||
|
final files = await listLogFiles();
|
||||||
|
for (final f in files) {
|
||||||
|
await File(f.path).delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取指定日期范围内的日志文件(包含起止日期)
|
||||||
|
static Future<List<File>> getLogsBetween(
|
||||||
|
DateTime fromDate, DateTime toDate) async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
final logFiles = <File>[];
|
||||||
|
final dateFormat = DateFormat('yyyy-MM-dd');
|
||||||
|
|
||||||
|
for (DateTime date = fromDate;
|
||||||
|
!date.isAfter(toDate);
|
||||||
|
date = date.add(Duration(days: 1))) {
|
||||||
|
final fileName = '${dateFormat.format(date)}.log';
|
||||||
|
final file = File('${dir.path}/$fileName');
|
||||||
|
if (await file.exists()) {
|
||||||
|
logFiles.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -118,6 +118,57 @@ class MyUtils {
|
|||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String formatBindTime(DateTime d) {
|
||||||
|
final DateFormat formatter = DateFormat('yyyy/MM/dd');
|
||||||
|
return formatter.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DateTime? formatBirthdayTime(String? device) {
|
||||||
|
if (device == null || device.isEmpty) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return DateTime.parse(device.replaceAll('/', '-')); // 替换为标准格式
|
||||||
|
} catch (e) {
|
||||||
|
return null; // 解析失败时返回 null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getAgeByDate(DateTime? formatBirthdayTime) {
|
||||||
|
if (formatBirthdayTime == null) return 0;
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
int age = now.year - formatBirthdayTime.year;
|
||||||
|
|
||||||
|
// 如果还没到今年生日,减一岁
|
||||||
|
if (now.month < formatBirthdayTime.month ||
|
||||||
|
(now.month == formatBirthdayTime.month &&
|
||||||
|
now.day < formatBirthdayTime.day)) {
|
||||||
|
age--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatDateTimeWeek(DateTime date) {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
// 去除时间部分,仅比较年月日
|
||||||
|
DateTime today = DateTime(now.year, now.month, now.day);
|
||||||
|
DateTime target = DateTime(date.year, date.month, date.day);
|
||||||
|
|
||||||
|
if (target == today) {
|
||||||
|
return '今日';
|
||||||
|
}
|
||||||
|
|
||||||
|
const List<String> weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||||
|
return weekdays[date.weekday % 7]; // Dart中星期日是7,要映射到索引0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 返回 MM/dd 格式
|
||||||
|
static String formatDateTimeDay(DateTime date) {
|
||||||
|
String twoDigits(int n) => n.toString().padLeft(2, '0');
|
||||||
|
return '${twoDigits(date.month)}/${twoDigits(date.day)}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color stringToColor(String hexColor) {
|
Color stringToColor(String hexColor) {
|
||||||
|
|||||||
77
lib/component/NullDataComponentWidget.dart
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
class NullDataWidget extends StatefulWidget {
|
||||||
|
const NullDataWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NullDataWidget> createState() => _TestWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestWidgetState extends State<NullDataWidget> {
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
return GestureDetector(
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
key: scaffoldKey,
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 1,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 56.rpx,
|
||||||
|
height: 69.rpx,
|
||||||
|
// width: double.infinity,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/nulldata.svg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.04,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 40,
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Text(
|
||||||
|
'暂无数据'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
useGoogleFonts: false,
|
||||||
|
fontFamily: "PingFangSC",
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
172
lib/component/home_page/DynamicReportDetailWidget.dart
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/home_page/SleepDataModuleWidget.dart';
|
||||||
|
import 'package:vbvs_app/component/home_page/SleepDateWidget.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
class DynamicReportDetailWidget extends StatelessWidget {
|
||||||
|
final List<SleepDateWidget> sleepDateWidgets;
|
||||||
|
final List<SleepDataModuleWidget> sleepDataModuleWidgets;
|
||||||
|
final ThemeController themeController = Get.find();
|
||||||
|
final Map targetDevice;
|
||||||
|
|
||||||
|
DynamicReportDetailWidget({
|
||||||
|
required this.sleepDateWidgets,
|
||||||
|
required this.sleepDataModuleWidgets,
|
||||||
|
required this.targetDevice,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 25.rpx, 0, 25.rpx),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc5,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(AppConstants().normal_container_radius),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(30.rpx, 30.rpx, 30.rpx, 30.rpx),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
_buildHeader(context),
|
||||||
|
_buildSleepDateWidgets(),
|
||||||
|
SizedBox(height: 20.rpx),
|
||||||
|
_buildSleepDataModuleWidgets(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeader(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${targetDevice['person']?['name'] == null ? '未命名'.tr : targetDevice['person']['name']}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: themeController.currentColor.sc3,
|
||||||
|
borderRadius: 0,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () {
|
||||||
|
String mac = targetDevice['mac'];
|
||||||
|
List<SleepDateWidget> selectedWidgets = sleepDateWidgets
|
||||||
|
.where(
|
||||||
|
(widget) => widget.isSelected == true,
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
int.parse(selectedWidgets[0].time!));
|
||||||
|
String time = MyUtils.formatBindTime(dateTime);
|
||||||
|
String sleepReportUrl =
|
||||||
|
"${ServiceConstant.sleep_report_url}?mac=${mac}&token=${ServiceConstant.sleep_token}&date=${time}";
|
||||||
|
Get.toNamed("/sleepReportPage", arguments: sleepReportUrl);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'首页.报告详情'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 6.rpx, 0, 0.rpx),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/arrow_right.svg',
|
||||||
|
width: 14.rpx,
|
||||||
|
height: 14.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 22.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSleepDateWidgets() {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: sleepDateWidgets
|
||||||
|
.map((widget) => widget)
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(width: 20.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSleepDataModuleWidgets() {
|
||||||
|
// bool hasData = sleepDataModuleWidgets.any((w) {
|
||||||
|
// final data = w.data;
|
||||||
|
// return data['state'] != null &&
|
||||||
|
// data['state'].toString().trim().isNotEmpty;
|
||||||
|
// });
|
||||||
|
bool hasData = sleepDataModuleWidgets.length > 0;
|
||||||
|
|
||||||
|
if (!hasData) {
|
||||||
|
return Container(
|
||||||
|
height: 100.rpx,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
'暂无数据'.tr,
|
||||||
|
style: FlutterFlowTheme.of(Get.context!).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 28.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: sleepDataModuleWidgets
|
||||||
|
.map((widget) => widget)
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(width: 14.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
import 'package:ef/base/widget/flutterflow/FlutterFlowTheme.dart';
|
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
import 'package:vbvs_app/common/color/appConstants.dart';
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
class SleepDataModuleWidget extends StatefulWidget {
|
class SleepDataModuleWidget extends StatefulWidget {
|
||||||
const SleepDataModuleWidget({super.key});
|
final Map<String, dynamic> data;
|
||||||
|
|
||||||
|
const SleepDataModuleWidget({super.key, required this.data});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SleepDataModuleWidget> createState() => _SleepDataModuleWidgetState();
|
State<SleepDataModuleWidget> createState() => _SleepDataModuleWidgetState();
|
||||||
@@ -33,111 +35,137 @@ class _SleepDataModuleWidgetState extends State<SleepDataModuleWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
return Container(
|
return ClickableContainer(
|
||||||
width: MediaQuery.sizeOf(context).width * 0.27,
|
backgroundColor: themeController.currentColor.sc5,
|
||||||
constraints: BoxConstraints(
|
highlightColor: themeController.currentColor.sc3,
|
||||||
minWidth: 200.rpx,
|
borderRadius: 20.rpx,
|
||||||
),
|
padding: EdgeInsetsDirectional.fromSTEB(18.rpx, 18.rpx, 18.rpx, 22.rpx),
|
||||||
decoration: BoxDecoration(
|
onTap: () {
|
||||||
color: themeController.currentColor.sc5,
|
print('点击了离床次数卡片');
|
||||||
borderRadius: BorderRadius.circular(20.rpx),
|
},
|
||||||
),
|
child: Container(
|
||||||
child: Padding(
|
width: MediaQuery.sizeOf(context).width * 0.27,
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(18.rpx, 18.rpx, 18.rpx, 22.rpx),
|
constraints: BoxConstraints(
|
||||||
child: Container(
|
minWidth: 200.rpx,
|
||||||
decoration: BoxDecoration(),
|
minHeight: 161.rpx,
|
||||||
child: Column(
|
),
|
||||||
mainAxisSize: MainAxisSize.max,
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text(
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
'离床次数',
|
children: [
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
Text(
|
||||||
fontFamily: 'Inter',
|
'${widget.data['name']}',
|
||||||
fontSize: 26.rpx,
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
letterSpacing: 0.0,
|
fontFamily: 'Inter',
|
||||||
color: themeController.currentColor.sc3,
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${widget.data['value']}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 40.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
// SizedBox(
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 10.rpx),
|
||||||
// height: 21.rpx,
|
child: Text(
|
||||||
// ),
|
'${widget.data['unit'] ?? ''}',
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'4',
|
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
fontSize: 40.rpx,
|
fontSize: AppConstants().small_text_fontSize,
|
||||||
letterSpacing: 0.0,
|
letterSpacing: 0.0,
|
||||||
color: themeController.currentColor.sc3,
|
color: themeController.currentColor.sc3,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
),
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
],
|
||||||
0.rpx, 0, 0.rpx, 10.rpx),
|
),
|
||||||
child: Text(
|
// Container(
|
||||||
'次',
|
// width: MediaQuery.sizeOf(context).width * 0.07,
|
||||||
style: FlutterFlowTheme.of(context)
|
// height: MediaQuery.sizeOf(context).height * 0.014,
|
||||||
.bodyMedium
|
// constraints: BoxConstraints(
|
||||||
.override(
|
// minWidth: 43.rpx,
|
||||||
fontFamily: 'Inter',
|
// minHeight: 36.rpx,
|
||||||
fontSize: AppConstants().small_text_fontSize,
|
// ),
|
||||||
letterSpacing: 0.0,
|
// child: FFButtonWidget(
|
||||||
color: themeController.currentColor.sc3,
|
// onPressed: () {
|
||||||
),
|
// print('Button pressed ...');
|
||||||
),
|
// },
|
||||||
),
|
// // text: '${widget.data['level']}',
|
||||||
],
|
// text: '${widget.data['level']}',
|
||||||
|
// options: FFButtonOptions(
|
||||||
|
// height: 40.rpx,
|
||||||
|
// padding: EdgeInsets.zero,
|
||||||
|
// // color: themeController.currentColor.sc14,
|
||||||
|
// color: stringToColor('${widget.data['color']}'),
|
||||||
|
// textStyle:
|
||||||
|
// FlutterFlowTheme.of(context).titleSmall.override(
|
||||||
|
// fontFamily: 'Inter Tight',
|
||||||
|
// color: themeController.currentColor.sc3,
|
||||||
|
// // color: stringToColor('${widget.data['color']}'),
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// fontSize: 15.rpx,
|
||||||
|
// ),
|
||||||
|
// elevation: 0,
|
||||||
|
// borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: stringToColor('${widget.data['color']}'),
|
||||||
|
highlightColor: themeController.currentColor.sc3,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 0.rpx,
|
||||||
|
vertical: 0.rpx,
|
||||||
),
|
),
|
||||||
Container(
|
borderRadius: 8.rpx,
|
||||||
width: MediaQuery.sizeOf(context).width * 0.07,
|
onTap: () {
|
||||||
height: MediaQuery.sizeOf(context).height * 0.014,
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minWidth: 43.rpx,
|
minWidth: 43.rpx,
|
||||||
minHeight: 36.rpx,
|
minHeight: 36.rpx,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(),
|
child: Text(
|
||||||
child: FFButtonWidget(
|
'${widget.data['level']}',
|
||||||
onPressed: () {
|
style: FlutterFlowTheme.of(context).titleSmall.override(
|
||||||
print('Button pressed ...');
|
fontFamily: 'Inter Tight',
|
||||||
},
|
color: themeController.currentColor.sc3,
|
||||||
text: '异常',
|
letterSpacing: 0.0,
|
||||||
options: FFButtonOptions(
|
fontSize: 15.rpx,
|
||||||
height: 40.rpx,
|
),
|
||||||
padding:
|
|
||||||
EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0.rpx, 0),
|
|
||||||
color: themeController.currentColor.sc14,
|
|
||||||
textStyle:
|
|
||||||
FlutterFlowTheme.of(context).titleSmall.override(
|
|
||||||
fontFamily: 'Inter Tight',
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
fontSize: 15.rpx,
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
borderRadius: BorderRadius.circular(8.rpx),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
].divide(SizedBox(width: 0.rpx)),
|
||||||
Text(
|
),
|
||||||
'正常值:0~2',
|
Text(
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
'${widget.data['range']}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
fontSize: AppConstants().small_text_fontSize,
|
fontSize: AppConstants().small_text_fontSize,
|
||||||
letterSpacing: 0.0,
|
letterSpacing: 0.0,
|
||||||
color: themeController.currentColor.sc4),
|
color: themeController.currentColor.sc4,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,10 +6,28 @@ import 'package:vbvs_app/common/color/appConstants.dart';
|
|||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
class SleepDateWidget extends StatefulWidget {
|
class SleepDateWidget extends StatefulWidget {
|
||||||
const SleepDateWidget({super.key});
|
final String? mac;
|
||||||
|
final String? time; // 必传:日期,例如 "07/15"
|
||||||
|
final DateTime date; // 必传:日期,例如 "07/15"
|
||||||
|
final String? score; // 可选:分数,默认为 "--"
|
||||||
|
final String? comment; // 可选:评价,默认为 "暂无".tr
|
||||||
|
final Color? textColor; // 可选:文字颜色,默认为灰色
|
||||||
|
final bool? isSelected; // 是否选中
|
||||||
|
|
||||||
|
const SleepDateWidget({
|
||||||
|
super.key,
|
||||||
|
this.mac,
|
||||||
|
this.time,
|
||||||
|
required this.date,
|
||||||
|
this.score = '--',
|
||||||
|
this.comment = '暂无',
|
||||||
|
this.textColor,
|
||||||
|
this.isSelected = false, // 新增参数,默认不选中
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SleepDateWidget> createState() => _SleepDateWidgetState();
|
State<SleepDateWidget> createState() => _SleepDateWidgetState();
|
||||||
@@ -19,14 +37,35 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
|
BodyDeviceController bodyDeviceController = Get.find();
|
||||||
|
String week = MyUtils.formatDateTimeWeek(widget.date);
|
||||||
|
String day = MyUtils.formatDateTimeDay(widget.date);
|
||||||
|
|
||||||
|
// 选中时背景色为黑色,否则为透明
|
||||||
|
Color backgroundColor =
|
||||||
|
widget.isSelected == true ? Colors.black : Colors.transparent;
|
||||||
|
|
||||||
return ClickableContainer(
|
return ClickableContainer(
|
||||||
backgroundColor: Colors.transparent, // 原 BoxDecoration 为空
|
backgroundColor: backgroundColor,
|
||||||
highlightColor:
|
// highlightColor: themeController.currentColor.sc3.withOpacity(0.1),
|
||||||
themeController.currentColor.sc3.withOpacity(0.1), // 自定义点击波纹颜色
|
highlightColor: Colors.transparent,
|
||||||
borderRadius: AppConstants().normal_container_radius, // 原来没设置圆角
|
borderRadius: AppConstants().normal_container_radius,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("今日评分卡片点击");
|
final mac = widget.mac;
|
||||||
|
final time = widget.time;
|
||||||
|
|
||||||
|
if (bodyDeviceController.sleepReportData.value.containsKey(mac)) {
|
||||||
|
final list = bodyDeviceController.sleepReportData.value[mac];
|
||||||
|
|
||||||
|
for (var item in list!) {
|
||||||
|
item['selected'] = (item['time'] == time);
|
||||||
|
}
|
||||||
|
bodyDeviceController.sleepReportData.value = {
|
||||||
|
...bodyDeviceController.sleepReportData.value,
|
||||||
|
};
|
||||||
|
bodyDeviceController.updateAll();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: MediaQuery.sizeOf(context).width * 0.19,
|
width: MediaQuery.sizeOf(context).width * 0.19,
|
||||||
@@ -36,54 +75,55 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsetsDirectional.fromSTEB(10.rpx, 25.rpx, 10.rpx, 22.rpx),
|
EdgeInsetsDirectional.fromSTEB(10.rpx, 25.rpx, 10.rpx, 22.rpx),
|
||||||
child: Container(
|
child: Column(
|
||||||
child: Column(
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
children: [
|
||||||
children: [
|
Padding(
|
||||||
Padding(
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 14.rpx),
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 14.rpx),
|
child: Text(
|
||||||
child: Text(
|
'${week}',
|
||||||
'今日',
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
fontFamily: 'Inter',
|
||||||
fontFamily: 'Inter',
|
fontSize: AppConstants().title_text_fontSize,
|
||||||
fontSize: AppConstants().title_text_fontSize,
|
letterSpacing: 0.0,
|
||||||
letterSpacing: 0.0,
|
color: themeController.currentColor.sc3,
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 33.rpx),
|
|
||||||
child: Text(
|
|
||||||
'07/15',
|
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 20.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 16.rpx),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'70',
|
|
||||||
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 48.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: stringToColor("#00C1AA")),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 33.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${day}',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 20.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 16.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
(widget.score?.isEmpty ?? true) ? '--' : widget.score!,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 48.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: widget.textColor ??
|
||||||
|
themeController.currentColor.sc4),
|
||||||
|
),
|
||||||
|
if ((widget.score?.trim().isNotEmpty ?? false))
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsetsDirectional.fromSTEB(0, 16.rpx, 0, 0.rpx),
|
EdgeInsetsDirectional.fromSTEB(0, 16.rpx, 0, 0.rpx),
|
||||||
child: Text(
|
child: Text(
|
||||||
'分',
|
'分'.tr,
|
||||||
style: FlutterFlowTheme.of(context)
|
style: FlutterFlowTheme.of(context)
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
.override(
|
.override(
|
||||||
@@ -94,40 +134,40 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 0.2.rpx,
|
||||||
|
height: 2.4.rpx,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 123.rpx,
|
||||||
|
minHeight: 47.rpx,
|
||||||
|
),
|
||||||
|
child: FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('合格按钮点击');
|
||||||
|
},
|
||||||
|
text: (widget.comment?.trim().isEmpty ?? true)
|
||||||
|
? '暂无'.tr
|
||||||
|
: widget.comment!,
|
||||||
|
options: FFButtonOptions(
|
||||||
|
height: 40.rpx,
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(16.rpx, 0, 16.rpx, 0),
|
||||||
|
iconPadding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: widget.textColor ?? themeController.currentColor.sc4,
|
||||||
|
textStyle: FlutterFlowTheme.of(context).titleSmall.override(
|
||||||
|
fontFamily: 'Inter Tight',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
elevation: 0,
|
||||||
|
borderRadius: BorderRadius.circular(50.rpx),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
),
|
||||||
width: 0.2.rpx,
|
],
|
||||||
height: 2.4.rpx,
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minWidth: 123.rpx,
|
|
||||||
minHeight: 47.rpx,
|
|
||||||
),
|
|
||||||
child: FFButtonWidget(
|
|
||||||
onPressed: () {
|
|
||||||
print('合格按钮点击');
|
|
||||||
},
|
|
||||||
text: '合格',
|
|
||||||
options: FFButtonOptions(
|
|
||||||
height: 40.rpx,
|
|
||||||
padding:
|
|
||||||
EdgeInsetsDirectional.fromSTEB(16.rpx, 0, 16.rpx, 0),
|
|
||||||
iconPadding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
|
||||||
color: stringToColor("#00C1AA"),
|
|
||||||
textStyle:
|
|
||||||
FlutterFlowTheme.of(context).titleSmall.override(
|
|
||||||
fontFamily: 'Inter Tight',
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
),
|
|
||||||
elevation: 0,
|
|
||||||
borderRadius: BorderRadius.circular(50.rpx),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
|
||||||
class CustomCard extends StatefulWidget {
|
class CustomCard extends StatefulWidget {
|
||||||
final double borderRadius; // 圆角
|
final double borderRadius; // 圆角
|
||||||
@@ -15,7 +16,7 @@ class CustomCard extends StatefulWidget {
|
|||||||
required this.colors,
|
required this.colors,
|
||||||
required this.child,
|
required this.child,
|
||||||
this.enableAnimation = true, // 默认启用动画效果
|
this.enableAnimation = true, // 默认启用动画效果
|
||||||
this.enableGradient = true, // 默认启用渐变效果
|
this.enableGradient = true, // 默认启用渐变效果
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -25,36 +26,19 @@ class CustomCard extends StatefulWidget {
|
|||||||
class _CustomCardState extends State<CustomCard>
|
class _CustomCardState extends State<CustomCard>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
double _scale = 1.0;
|
double _scale = 1.0;
|
||||||
final Duration _animationDuration = Duration(milliseconds: 50);
|
final Duration _animationDuration = const Duration(milliseconds: 50);
|
||||||
final GlobalKey _inkKey = GlobalKey();
|
|
||||||
|
|
||||||
Future<void> _handleTap(TapDownDetails details) async {
|
Future<void> _handleTap() async {
|
||||||
setState(() {
|
if (widget.enableAnimation) {
|
||||||
_scale = 0.95;
|
setState(() {
|
||||||
});
|
_scale = 0.95;
|
||||||
|
});
|
||||||
|
|
||||||
await Future.delayed(_animationDuration);
|
await Future.delayed(_animationDuration);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_scale = 1.0;
|
_scale = 1.0;
|
||||||
});
|
});
|
||||||
|
|
||||||
await Future.delayed(_animationDuration);
|
|
||||||
|
|
||||||
// 手动触发水波纹
|
|
||||||
final RenderBox? box =
|
|
||||||
_inkKey.currentContext?.findRenderObject() as RenderBox?;
|
|
||||||
if (box != null) {
|
|
||||||
final Offset localPosition = box.globalToLocal(details.globalPosition);
|
|
||||||
InkRipple.splashFactory.create(
|
|
||||||
controller: Material.of(_inkKey.currentContext!)!,
|
|
||||||
referenceBox: box,
|
|
||||||
position: localPosition,
|
|
||||||
color: widget.colors.first.withOpacity(0.2),
|
|
||||||
containedInkWell: true,
|
|
||||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
||||||
textDirection: Directionality.of(context),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
widget.onTap();
|
widget.onTap();
|
||||||
@@ -62,51 +46,44 @@ class _CustomCardState extends State<CustomCard>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bool isGradient = widget.enableGradient && widget.colors.length > 1; // 只有启用渐变时,才使用渐变
|
final bool isGradient = widget.enableGradient && widget.colors.length > 1;
|
||||||
final Color baseColor = widget.colors.first;
|
final Color baseColor = widget.colors.first;
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||||
child: GestureDetector(
|
child: InkWell(
|
||||||
onTapDown: _handleTap,
|
onTap: _handleTap,
|
||||||
behavior: HitTestBehavior.translucent, // 关键:让空白区域也能点击
|
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||||
child: widget.enableAnimation // 判断是否启用动画
|
splashColor: widget.colors.first.withOpacity(0.2),
|
||||||
|
child: widget.enableAnimation
|
||||||
? AnimatedScale(
|
? AnimatedScale(
|
||||||
scale: _scale,
|
scale: _scale,
|
||||||
duration: _animationDuration,
|
duration: _animationDuration,
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: Ink(
|
child: _buildContent(isGradient, baseColor),
|
||||||
key: _inkKey,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: isGradient ? null : baseColor,
|
|
||||||
gradient: isGradient
|
|
||||||
? LinearGradient(
|
|
||||||
colors: widget.colors,
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
|
||||||
),
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: Ink(
|
: _buildContent(isGradient, baseColor),
|
||||||
key: _inkKey,
|
),
|
||||||
decoration: BoxDecoration(
|
);
|
||||||
color: isGradient ? null : baseColor,
|
}
|
||||||
gradient: isGradient
|
|
||||||
? LinearGradient(
|
Widget _buildContent(bool isGradient, Color baseColor) {
|
||||||
colors: widget.colors,
|
return Container(
|
||||||
begin: Alignment.topLeft,
|
decoration: BoxDecoration(
|
||||||
end: Alignment.bottomRight,
|
color: isGradient ? null : baseColor,
|
||||||
)
|
gradient: isGradient
|
||||||
: null,
|
? LinearGradient(
|
||||||
borderRadius: BorderRadius.circular(widget.borderRadius),
|
colors: widget.colors,
|
||||||
),
|
begin: Alignment.topLeft,
|
||||||
child: widget.child,
|
end: Alignment.bottomRight,
|
||||||
),
|
)
|
||||||
|
: null,
|
||||||
|
borderRadius: BorderRadius.circular(widget.borderRadius),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 5.rpx),
|
||||||
|
child: widget.child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
79
lib/component/tool/SelectableTagButton.dart
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
import 'CustomCard.dart';
|
||||||
|
|
||||||
|
class SelectableTagButton extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final bool selected;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final double minWidth; // 最小宽度,单位:dp(会转 rpx)
|
||||||
|
final double maxWidth; // 最大宽度,单位:dp(会转 rpx)
|
||||||
|
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
|
||||||
|
SelectableTagButton({
|
||||||
|
Key? key,
|
||||||
|
required this.label,
|
||||||
|
required this.selected,
|
||||||
|
required this.onTap,
|
||||||
|
this.minWidth = 132, // 默认最小宽度
|
||||||
|
this.maxWidth = 500, // 默认最大宽度
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double minWidthRpx = minWidth.rpx;
|
||||||
|
final double maxWidthRpx = maxWidth.rpx;
|
||||||
|
final double horizontalPadding = 28.rpx * 2; // 左右各 28,总 56
|
||||||
|
// 估算文本宽度:每个字符按 14.rpx 字号估一个宽度
|
||||||
|
final double estimatedTextWidth = label.length * 33.rpx;
|
||||||
|
|
||||||
|
// 总宽度 = 文本宽度 + padding
|
||||||
|
final double totalWidth = estimatedTextWidth + horizontalPadding;
|
||||||
|
|
||||||
|
// 限制在 min 和 max 之间
|
||||||
|
final double constrainedWidth = totalWidth.clamp(minWidthRpx, maxWidthRpx);
|
||||||
|
|
||||||
|
return CustomCard(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: AppConstants().normal_container_radius,
|
||||||
|
colors: selected
|
||||||
|
? [themeController.currentColor.sc1, themeController.currentColor.sc2]
|
||||||
|
: [Colors.transparent],
|
||||||
|
// colors: [Colors.transparent],
|
||||||
|
enableGradient: true,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: selected
|
||||||
|
? null
|
||||||
|
: Border.all(
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
width: 1.rpx,
|
||||||
|
), // 未选中时无边框
|
||||||
|
borderRadius: BorderRadius.circular(12.0), // 如果需要圆角
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 28.rpx),
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 61.rpx,
|
||||||
|
maxWidth: constrainedWidth,
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
style: TextStyle(
|
||||||
|
color: selected
|
||||||
|
? themeController.currentColor.sc3
|
||||||
|
: themeController.currentColor.sc4,
|
||||||
|
fontSize: AppConstants().normal_text_fontSize, // 字体也用 rpx 控制
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
130
lib/component/tool/TopSlideNotification.dart
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
class TopSlideNotification extends StatefulWidget {
|
||||||
|
final String text;
|
||||||
|
double? fontSize = 26.rpx;
|
||||||
|
Color? textColor;
|
||||||
|
double? slideOffset = 200;
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
TopSlideNotification({
|
||||||
|
super.key,
|
||||||
|
this.text = '操作成功!',
|
||||||
|
this.fontSize,
|
||||||
|
this.textColor,
|
||||||
|
this.slideOffset,
|
||||||
|
this.duration = const Duration(seconds: 2),
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TopSlideNotification> createState() => _TopSlideNotificationState();
|
||||||
|
|
||||||
|
/// 工具方法:调用时直接加进 Overlay 上
|
||||||
|
static void show(
|
||||||
|
BuildContext context, {
|
||||||
|
String text = '操作成功!',
|
||||||
|
double fontSize = 16,
|
||||||
|
Color? textColor,
|
||||||
|
double slideOffset = 300.0,
|
||||||
|
Duration duration = const Duration(seconds: 2),
|
||||||
|
}) {
|
||||||
|
final overlay = Overlay.of(context);
|
||||||
|
final entry = OverlayEntry(
|
||||||
|
builder: (_) => TopSlideNotification(
|
||||||
|
text: text,
|
||||||
|
fontSize: fontSize,
|
||||||
|
textColor: textColor,
|
||||||
|
slideOffset: slideOffset,
|
||||||
|
duration: duration,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
overlay.insert(entry);
|
||||||
|
|
||||||
|
Future.delayed(duration + const Duration(milliseconds: 500), () {
|
||||||
|
entry.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TopSlideNotificationState extends State<TopSlideNotification>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<Offset> _animation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_controller = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
SchedulerBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await _controller.forward();
|
||||||
|
await Future.delayed(widget.duration);
|
||||||
|
await _controller.reverse();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
final screenHeight = MediaQuery.of(context).size.height;
|
||||||
|
final offsetValue = widget.slideOffset! / screenHeight;
|
||||||
|
|
||||||
|
_animation = Tween<Offset>(
|
||||||
|
begin: const Offset(0, -1),
|
||||||
|
end: Offset(0, offsetValue),
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
reverseCurve: Curves.easeIn,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Color get _textColor {
|
||||||
|
return widget.textColor ?? Get.find<ThemeController>().currentColor.sc2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: SlideTransition(
|
||||||
|
position: _animation,
|
||||||
|
child: Material(
|
||||||
|
color: stringToColor("#000000").withOpacity(0.8),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 20.0),
|
||||||
|
child: Container(
|
||||||
|
// color: Colors.red,
|
||||||
|
child: Text(
|
||||||
|
widget.text,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: widget.fontSize,
|
||||||
|
color: _textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
lib/component/tool/WebViewWidget.dart
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
// import 'package:webview_flutter/webview_flutter.dart';
|
||||||
|
|
||||||
|
// class WebViewWidget extends StatefulWidget {
|
||||||
|
// final String url;
|
||||||
|
// const WebViewWidget({Key? key, required this.url}) : super(key: key);
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// _WebViewWidgetState createState() => _WebViewWidgetState();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class _WebViewWidgetState extends State<WebViewWidget> {
|
||||||
|
// late WebViewController _webViewController;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void initState() {
|
||||||
|
// super.initState();
|
||||||
|
// // 初始化 WebView 控件
|
||||||
|
// WebView.platform = SurfaceAndroidWebView();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return Scaffold(
|
||||||
|
// appBar: AppBar(
|
||||||
|
// title: Text('WebView'),
|
||||||
|
// ),
|
||||||
|
// body: WebView(
|
||||||
|
// initialUrl: widget.url, // 设置要打开的网页地址
|
||||||
|
// javascriptMode: JavascriptMode.unrestricted, // 启用 JavaScript
|
||||||
|
// onWebViewCreated: (WebViewController webViewController) {
|
||||||
|
// _webViewController = webViewController;
|
||||||
|
// },
|
||||||
|
// onPageStarted: (String url) {
|
||||||
|
// print("页面开始加载:$url");
|
||||||
|
// },
|
||||||
|
// onPageFinished: (String url) {
|
||||||
|
// print("页面加载完成:$url");
|
||||||
|
// },
|
||||||
|
// navigationDelegate: (NavigationRequest request) {
|
||||||
|
// if (request.url.startsWith('https://www.google.com/')) {
|
||||||
|
// print('拦截了URL请求: ${request.url}');
|
||||||
|
// return NavigationDecision.prevent; // 拦截特定的请求
|
||||||
|
// }
|
||||||
|
// return NavigationDecision.navigate;
|
||||||
|
// },
|
||||||
|
// gestureNavigationEnabled: true, // 启用手势返回
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
166
lib/component/tool/cmd.dart
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//蓝牙指令
|
||||||
|
|
||||||
|
// wifi列表指令
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
|
||||||
|
import 'package:easydevice/src/app/thapp.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
|
||||||
|
getWifiList(THapp tHapp) async {
|
||||||
|
try {
|
||||||
|
edm.EasyDartModule.logger.info("发送请求网络列表指令");
|
||||||
|
DailyLogUtils.writeLog("发送请求网络列表指令");
|
||||||
|
List data = [];
|
||||||
|
var wifilist = await tHapp.send("wscan scan", true, (log) {
|
||||||
|
print("[bles]${log.log}");
|
||||||
|
if (log.log.contains("SCAN RESULT OVER!")) {
|
||||||
|
final wifiList = <Map<String, dynamic>>[];
|
||||||
|
final items = log.log.split('[wifi]: SCAN RESULT ITEM:');
|
||||||
|
final reg =
|
||||||
|
RegExp(r'SSID=([^\t\r\n]+)\s+RSSI=(-?\d+)\s*,\s*auth\s*=\s*(\d+)');
|
||||||
|
|
||||||
|
for (var item in items) {
|
||||||
|
final match = reg.firstMatch(item);
|
||||||
|
if (match != null) {
|
||||||
|
wifiList.add({
|
||||||
|
'ssid': match.group(1),
|
||||||
|
'rssi': int.parse(match.group(2)!),
|
||||||
|
'auth': int.parse(match.group(3)!),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('解析得到 Wi-Fi 列表: $wifiList');
|
||||||
|
if (wifiList.length != 0) {
|
||||||
|
log.result = wifiList;
|
||||||
|
data = wifiList;
|
||||||
|
log.over = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
return wifilist;
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getWifiStatus(THapp tHapp) async {
|
||||||
|
edm.EasyDartModule.logger.info("发送请求设备网络状态指令");
|
||||||
|
DailyLogUtils.writeLog("发送请求设备网络状态指令");
|
||||||
|
var result = await tHapp.send(
|
||||||
|
"wl show",
|
||||||
|
true,
|
||||||
|
(ss) {
|
||||||
|
var log = ss.log;
|
||||||
|
final match = RegExp(r'status=([^\s]+)').firstMatch(log);
|
||||||
|
final status = match?.group(1);
|
||||||
|
if (status != null) {
|
||||||
|
print('提取到的 status: $status');
|
||||||
|
if (status == 'connect') {
|
||||||
|
ss.result = true;
|
||||||
|
ss.over = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
ss.result = false;
|
||||||
|
ss.over = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> sendWifiSetting(wifiItem, String password, THapp tHapp) async {
|
||||||
|
try {
|
||||||
|
edm.EasyDartModule.logger.info("发送wifi配置指令");
|
||||||
|
DailyLogUtils.writeLog("发送wifi配置指令->");
|
||||||
|
String cmd = "vtouch save update -a -i .wifi.sta.auth=${wifiItem['auth']} "
|
||||||
|
".wifi.sta.ssid=${wifiItem['ssid']} .wifi.sta.pwd=$password";
|
||||||
|
final success = await tHapp.send(cmd, true, (log) {
|
||||||
|
if (log.log.contains("update parm is successful")) {
|
||||||
|
print("[wifi456]:" + log.log);
|
||||||
|
edm.EasyDartModule.logger.info("WiFi配置成功-》log:$log");
|
||||||
|
DailyLogUtils.writeLog("WiFi配置成功->log:$log");
|
||||||
|
log.result = true;
|
||||||
|
log.over = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
edm.EasyDartModule.logger.error("WiFi配置超时或失败");
|
||||||
|
DailyLogUtils.writeLog("WiFi配置超时或失败");
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
} catch (e) {
|
||||||
|
edm.EasyDartModule.logger.error("发送wifi配置指令异常: ${e.toString()}");
|
||||||
|
DailyLogUtils.writeLog("发送wifi配置指令异常-> ${e.toString()}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeviceWifiStatus(THapp tHapp) async {
|
||||||
|
edm.EasyDartModule.logger.info("发送请求设备已配置网络状态指令");
|
||||||
|
DailyLogUtils.writeLog("发送请求设备已配置网络状态指令");
|
||||||
|
|
||||||
|
var result = await tHapp.send(
|
||||||
|
"at+system info",
|
||||||
|
true,
|
||||||
|
(ss) {
|
||||||
|
var log = ss.log;
|
||||||
|
|
||||||
|
// 匹配设备状态
|
||||||
|
final statusMatch = RegExp(r'status=([^\s]+)').firstMatch(log);
|
||||||
|
final status = statusMatch?.group(1);
|
||||||
|
if (status != null) {
|
||||||
|
print('提取到的 status: $status');
|
||||||
|
|
||||||
|
// 如果设备连接状态是 "connect",继续检测
|
||||||
|
if (status == 'connect') {
|
||||||
|
ss.result = true;
|
||||||
|
ss.over = true;
|
||||||
|
|
||||||
|
// 匹配 Wi-Fi 连接信息
|
||||||
|
final wifiInfoMatch = RegExp(
|
||||||
|
r'WIFI CONNECTED INFO:SSID=([^\s]+),RSSI=([-0-9]+),AUTH=([0-9]+),CH=([0-9]+),BSSID=([A-F0-9]+)')
|
||||||
|
.firstMatch(log);
|
||||||
|
if (wifiInfoMatch != null) {
|
||||||
|
final ssid = wifiInfoMatch.group(1);
|
||||||
|
final rssi = wifiInfoMatch.group(2);
|
||||||
|
final auth = wifiInfoMatch.group(3);
|
||||||
|
final ch = wifiInfoMatch.group(4);
|
||||||
|
final bssid = wifiInfoMatch.group(5);
|
||||||
|
|
||||||
|
// 打印并返回 Wi-Fi 信息
|
||||||
|
print(
|
||||||
|
'Wi-Fi 信息: SSID=$ssid, RSSI=$rssi, AUTH=$auth, CH=$ch, BSSID=$bssid');
|
||||||
|
|
||||||
|
// 停止监听并返回信息
|
||||||
|
ss.result = {
|
||||||
|
'ssid': ssid,
|
||||||
|
'rssi': rssi,
|
||||||
|
'auth': auth,
|
||||||
|
'ch': ch,
|
||||||
|
'bssid': bssid,
|
||||||
|
};
|
||||||
|
ss.over = true;
|
||||||
|
return ss.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未找到状态或Wi-Fi信息时,返回 false
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -2,54 +2,54 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:EasyDartModule/EasyDartModule.dart';
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
import 'package:easydevice/src/ble_device.dart';
|
import 'package:easydevice/easydevice.dart';
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/person/person_controller.dart';
|
||||||
import 'package:vbvs_app/model/BleDeviceData.dart';
|
import 'package:vbvs_app/model/BleDeviceData.dart';
|
||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
part 'blueteeth_bind_controller.g.dart'; // 由json_serializable自动生成的部分
|
part 'blueteeth_bind_controller.g.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class BlueteethBindModel {
|
class BlueteethBindModel {
|
||||||
int? read = 1; //是否不再提示教程 0 不再提示 1 需要提示
|
int? read = 1;
|
||||||
double? singal = -70; //扫描信号强度
|
double? singal = -70;
|
||||||
|
|
||||||
List<BleDeviceData>? devicelist = []; //蓝牙扫描到的设备数据列表
|
@JsonKey(ignore: true)
|
||||||
List<BleDeviceData>? betDevicelist = []; //请求的
|
List<BleDeviceData>? devicelist = [];//蓝牙扫描
|
||||||
List? blelist = []; //蓝牙扫描到的设备数据列表
|
@JsonKey(ignore: true)
|
||||||
List? wifiList = [];
|
List<BleDeviceData>? betDevicelist = [];//网络状态
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
List? blelist = [];
|
||||||
|
|
||||||
List bindArr = ["", "", ""];
|
List bindArr = ["", "", ""];
|
||||||
|
|
||||||
String connectedWifiName = "";
|
String connectedWifiName = "";
|
||||||
|
|
||||||
int connectedRssi = 0;
|
int connectedRssi = 0;
|
||||||
|
|
||||||
String deviceName = "";
|
String deviceName = "";
|
||||||
|
|
||||||
bool? deviceIndex0 = true;
|
bool? deviceIndex0 = true;
|
||||||
bool? deviceIndex1 = false;
|
bool? deviceIndex1 = false;
|
||||||
bool? deviceIndex2 = false;
|
bool? deviceIndex2 = false;
|
||||||
|
|
||||||
BlueteethBindModel();
|
bool wifiPassShow = false;
|
||||||
|
String? wifiPass;
|
||||||
|
|
||||||
// 从JSON反序列化时的异常处理
|
BlueteethBindModel();
|
||||||
|
|
||||||
factory BlueteethBindModel.fromJson(Map<String, dynamic> json) {
|
factory BlueteethBindModel.fromJson(Map<String, dynamic> json) {
|
||||||
try {
|
try {
|
||||||
return _$BlueteethBindModelFromJson(json);
|
return _$BlueteethBindModelFromJson(json);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
return BlueteethBindModel();
|
||||||
return BlueteethBindModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 序列化为JSON时的异常处理
|
|
||||||
Map<String, dynamic> toJson() => _$BlueteethBindModelToJson(this);
|
Map<String, dynamic> toJson() => _$BlueteethBindModelToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,30 +60,73 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
|
|
||||||
Timer? _statusTimer;
|
Timer? _statusTimer;
|
||||||
|
|
||||||
BLEDevice? currentDevice;
|
THapp? currentDevice;
|
||||||
|
RxInt wifiStatus = 0.obs;
|
||||||
|
RxList wifiList = [].obs;
|
||||||
|
RxMap connect_wifi = {}.obs;
|
||||||
|
RxString scanMac = "".obs;
|
||||||
|
|
||||||
|
// 安全展示 TopSlideNotification
|
||||||
|
void safeShowNotification(String msg) {
|
||||||
|
try {
|
||||||
|
final ctx = Get.context;
|
||||||
|
if (ctx != null && ctx.mounted) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
ctx,
|
||||||
|
text: msg,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print("TopSlideNotification 未显示:context 不可用或未挂载");
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
// print("TopSlideNotification 显示异常: $e\n$stack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 启动每10秒获取设备状态
|
// 启动每10秒获取设备状态
|
||||||
void startStatusPolling() {
|
void startStatusPolling() {
|
||||||
|
updateDeviceStatus().then((res) {
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
updateAll();
|
||||||
|
} else {
|
||||||
|
safeShowNotification(res.msg ?? "获取设备状态异常");
|
||||||
|
EasyDartModule.logger.info("获取设备状态异常: $res");
|
||||||
|
DailyLogUtils.writeLog("获取设备状态异常: $res");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (_statusTimer == null) {
|
if (_statusTimer == null) {
|
||||||
_statusTimer = Timer.periodic(Duration(seconds: 10), (timer) {
|
_statusTimer = Timer.periodic(Duration(seconds: 10), (timer) {
|
||||||
updateDeviceStatus();
|
updateDeviceStatus().then((res) {
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
updateAll();
|
||||||
|
} else {
|
||||||
|
safeShowNotification(res.msg ?? "获取设备状态异常");
|
||||||
|
EasyDartModule.logger.info("获取设备状态异常: $res");
|
||||||
|
DailyLogUtils.writeLog("获取设备状态异常: $res");
|
||||||
|
}
|
||||||
|
}).catchError((e, stack) {
|
||||||
|
print("updateDeviceStatus 执行异常: $e\n$stack");
|
||||||
|
safeShowNotification("设备状态请求失败");
|
||||||
|
EasyDartModule.logger.info("设备状态异常: $e");
|
||||||
|
DailyLogUtils.writeLog("设备状态异常: $e");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止轮询
|
|
||||||
void stopStatusPolling() {
|
void stopStatusPolling() {
|
||||||
_statusTimer?.cancel();
|
_statusTimer?.cancel();
|
||||||
_statusTimer = null;
|
_statusTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 你的已有方法
|
Future<ApiResponse> updateDeviceStatus() async {
|
||||||
Future<void> updateDeviceStatus() async {
|
|
||||||
try {
|
try {
|
||||||
String serviceAddress = ServiceConstant.service_address;
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
String serviceName = ServiceConstant.server_service;
|
String serviceName = ServiceConstant.server_service;
|
||||||
String serviceApi = ServiceConstant.get_bluetooth_device_status;
|
String serviceApi = ServiceConstant.get_bluetooth_device_status;
|
||||||
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
|
||||||
if (model.devicelist != null && model.devicelist!.isNotEmpty) {
|
if (model.devicelist != null && model.devicelist!.isNotEmpty) {
|
||||||
final macParams = model.devicelist!
|
final macParams = model.devicelist!
|
||||||
@@ -97,13 +140,16 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var response = await EasyDartModule.dio.get(queryUrl);
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) return res;
|
||||||
|
|
||||||
if (response.data['data'] != null && response.data['data'] is List) {
|
if (response.data['data'] != null && response.data['data'] is List) {
|
||||||
List<dynamic> responseList = response.data['data'];
|
List<dynamic> responseList = response.data['data'];
|
||||||
|
|
||||||
Map<String, BleDeviceData> deviceMap = {
|
Map<String, BleDeviceData> deviceMap = {
|
||||||
for (var d in model.devicelist!)
|
for (var d in model.devicelist!) if (d.mac != null) d.mac!: d
|
||||||
if (d.mac != null) d.mac!: d
|
|
||||||
};
|
};
|
||||||
|
|
||||||
List<String> slaveMacsToRemove = [];
|
List<String> slaveMacsToRemove = [];
|
||||||
@@ -123,17 +169,26 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model.devicelist!
|
model.devicelist!
|
||||||
.removeWhere((device) => slaveMacsToRemove.contains(device.mac));
|
.removeWhere((device) => slaveMacsToRemove.contains(device.mac));
|
||||||
|
model.betDevicelist = model.devicelist!;
|
||||||
|
} else {
|
||||||
|
model.betDevicelist = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
print("获取设备状态成功");
|
print("获取设备状态成功");
|
||||||
updateAll();
|
updateAll();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("获取设备状态异常: $e");
|
print("获取设备状态异常: $e");
|
||||||
EasyDartModule.logger.info("获取设备状态异常: $e");
|
EasyDartModule.logger.info("获取设备状态异常: $e");
|
||||||
DailyLogUtils.writeLog("获取设备状态异常: $e");
|
DailyLogUtils.writeLog("获取设备状态异常: $e");
|
||||||
|
return ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ApiResponse> bindDeviceAndMAC(BleDeviceData d) async {
|
Future<ApiResponse> bindDeviceAndMAC(BleDeviceData d) async {
|
||||||
@@ -142,7 +197,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
String serviceAddress = ServiceConstant.service_address;
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
String serviceName = ServiceConstant.server_service;
|
String serviceName = ServiceConstant.server_service;
|
||||||
String serviceApi = ServiceConstant.device_bind;
|
String serviceApi = ServiceConstant.device_bind;
|
||||||
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
var data = {
|
var data = {
|
||||||
"deviceType": 1,
|
"deviceType": 1,
|
||||||
"mac": d.mac,
|
"mac": d.mac,
|
||||||
@@ -154,10 +209,55 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
response.data is String ? jsonDecode(response.data) : response.data;
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
ApiResponse res =
|
ApiResponse res =
|
||||||
ApiResponse.fromJson(responseData, (object) => object);
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
MyUtils.formatResponse(apiResponse, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
|
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
PersonController personController = Get.find();
|
||||||
|
personController.currentPersonId.value = res.data['id'];
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("蓝牙绑定.绑定异常: $e");
|
||||||
|
DailyLogUtils.writeLog("蓝牙绑定.绑定异常: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose() {
|
||||||
|
stopStatusPolling();
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindDevice(Map<String, dynamic> map) {}
|
||||||
|
|
||||||
|
Future<ApiResponse> bindDeviceByScan(String mac) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "蓝牙绑定.绑定失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_bind;
|
||||||
|
String queryUrl = "$serviceAddress$serviceName$serviceApi";
|
||||||
|
var data = {
|
||||||
|
"deviceType": 1,
|
||||||
|
"mac": mac,
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
|
||||||
if (res.code == HttpStatusCodes.ok) {
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
apiResponse.msg = res.msg ?? apiResponse.msg;
|
||||||
} else {
|
} else {
|
||||||
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
}
|
}
|
||||||
@@ -166,14 +266,6 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
|
|||||||
EasyDartModule.logger.info("蓝牙绑定.绑定异常: $e");
|
EasyDartModule.logger.info("蓝牙绑定.绑定异常: $e");
|
||||||
DailyLogUtils.writeLog("蓝牙绑定.绑定异常: $e");
|
DailyLogUtils.writeLog("蓝牙绑定.绑定异常: $e");
|
||||||
}
|
}
|
||||||
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
return ApiResponse(code: -1, msg: "未知错误".tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void onClose() {
|
|
||||||
stopStatusPolling(); // 控制器销毁时停止轮询
|
|
||||||
super.onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
bindDevice(Map<String, dynamic> map) {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,30 @@ part of 'blueteeth_bind_controller.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
BlueteethBindModel _$BlueteethBindModelFromJson(Map<String, dynamic> json) =>
|
BlueteethBindModel _$BlueteethBindModelFromJson(Map<String, dynamic> json) =>
|
||||||
BlueteethBindModel()..read = (json['read'] as num).toInt();
|
BlueteethBindModel()
|
||||||
|
..read = (json['read'] as num?)?.toInt()
|
||||||
|
..singal = (json['singal'] as num?)?.toDouble()
|
||||||
|
..bindArr = json['bindArr'] as List<dynamic>
|
||||||
|
..connectedWifiName = json['connectedWifiName'] as String
|
||||||
|
..connectedRssi = (json['connectedRssi'] as num).toInt()
|
||||||
|
..deviceName = json['deviceName'] as String
|
||||||
|
..deviceIndex0 = json['deviceIndex0'] as bool?
|
||||||
|
..deviceIndex1 = json['deviceIndex1'] as bool?
|
||||||
|
..deviceIndex2 = json['deviceIndex2'] as bool?
|
||||||
|
..wifiPassShow = json['wifiPassShow'] as bool
|
||||||
|
..wifiPass = json['wifiPass'] as String?;
|
||||||
|
|
||||||
Map<String, dynamic> _$BlueteethBindModelToJson(BlueteethBindModel instance) =>
|
Map<String, dynamic> _$BlueteethBindModelToJson(BlueteethBindModel instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'read': instance.read,
|
'read': instance.read,
|
||||||
|
'singal': instance.singal,
|
||||||
|
'bindArr': instance.bindArr,
|
||||||
|
'connectedWifiName': instance.connectedWifiName,
|
||||||
|
'connectedRssi': instance.connectedRssi,
|
||||||
|
'deviceName': instance.deviceName,
|
||||||
|
'deviceIndex0': instance.deviceIndex0,
|
||||||
|
'deviceIndex1': instance.deviceIndex1,
|
||||||
|
'deviceIndex2': instance.deviceIndex2,
|
||||||
|
'wifiPassShow': instance.wifiPassShow,
|
||||||
|
'wifiPass': instance.wifiPass,
|
||||||
};
|
};
|
||||||
|
|||||||
256
lib/controller/device/body_device_controller.dart
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
|
part 'body_device_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class BodyDeviceModel {
|
||||||
|
int? type = 1; //设备类型 1:我的e护 2.云关爱
|
||||||
|
|
||||||
|
BodyDeviceModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory BodyDeviceModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$BodyDeviceModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return BodyDeviceModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$BodyDeviceModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
|
||||||
|
BodyDeviceController() {
|
||||||
|
attr = GetModel(BodyDeviceModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxInt bindDeviceNum = 0.obs;
|
||||||
|
RxList deviceList = [].obs;
|
||||||
|
RxMap<String, List<dynamic>> sleepReportData = <String, List<dynamic>>{}.obs;
|
||||||
|
|
||||||
|
RxString keyWord = "".obs;
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceNum() async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_list;
|
||||||
|
String queryUrl =
|
||||||
|
"${serviceAddress}${serviceName}${serviceApi}?bindNum=1";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
bindDeviceNum.value = res.total!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceList({String? key}) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_list;
|
||||||
|
String queryUrl =
|
||||||
|
"${serviceAddress}${serviceName}${serviceApi}?bindType=${model.type}${key != null ? '&key=$key' : ''}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
// bindDeviceNum.value = res.total!;
|
||||||
|
deviceList.value = res.data!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> deleteDevice(Map<String, dynamic> device) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_bind;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
final data = {
|
||||||
|
"mac": device['mac'],
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.delete(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("解绑设备: $e");
|
||||||
|
DailyLogUtils.writeLog("解绑设备: $e");
|
||||||
|
} finally {
|
||||||
|
EasyDartModule.logger.info("用户操作:解绑设备");
|
||||||
|
DailyLogUtils.writeLog("用户操作:解绑设备");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> getSleepReport() async {
|
||||||
|
try {
|
||||||
|
sleepReportData.value = {};
|
||||||
|
ApiResponse<Map<String, List<dynamic>>> apiResponse = ApiResponse(
|
||||||
|
code: -1,
|
||||||
|
msg: "请求失败".tr,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deviceList.value.isEmpty) {
|
||||||
|
return ApiResponse(
|
||||||
|
code: HttpStatusCodes.ok,
|
||||||
|
msg: "请求成功".tr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.sleep_report;
|
||||||
|
|
||||||
|
for (var device in deviceList.value) {
|
||||||
|
String mac = device['mac'] ?? "";
|
||||||
|
if (mac.isEmpty) continue;
|
||||||
|
|
||||||
|
sleepReportData[mac] = []; // 初始化当前设备的数据列表
|
||||||
|
|
||||||
|
String queryUrl =
|
||||||
|
"$serviceAddress$serviceName$serviceApi?mac=$mac&time=${DateTime.now().millisecondsSinceEpoch}";
|
||||||
|
|
||||||
|
try {
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData = response.data is String
|
||||||
|
? jsonDecode(response.data)
|
||||||
|
: response.data;
|
||||||
|
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
|
||||||
|
if (res.code == HttpStatusCodes.ok && res.data != null) {
|
||||||
|
// 确保数据是一个列表
|
||||||
|
if (res.data is List) {
|
||||||
|
sleepReportData[mac] = List.from(res.data);
|
||||||
|
} else {
|
||||||
|
sleepReportData[mac] = [res.data];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.warning("请求设备 $mac 的睡眠数据失败: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sleepReportData.value.isNotEmpty) {
|
||||||
|
// 遍历 Map 中的每一个键值对
|
||||||
|
sleepReportData.value.forEach((key, report) {
|
||||||
|
// 确保 report 列表不为空
|
||||||
|
if (report.isNotEmpty) {
|
||||||
|
// 获取该列表的最后一个元素
|
||||||
|
var lastElement = report.last;
|
||||||
|
|
||||||
|
// 给最后一个元素添加 selected 属性
|
||||||
|
lastElement['selected'] = true; // 假设每个元素是一个 Map 类型
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAll();
|
||||||
|
|
||||||
|
return ApiResponse(
|
||||||
|
code: HttpStatusCodes.ok,
|
||||||
|
msg: "请求成功".tr,
|
||||||
|
data: sleepReportData,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表异常: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表异常: $e");
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr, data: {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDeviceShow(device) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "操作失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_show;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var data = {
|
||||||
|
"id": device['_id'],
|
||||||
|
"show": !device['show'],
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("更新显示异常: $e");
|
||||||
|
DailyLogUtils.writeLog("更新显示异常: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lib/controller/device/body_device_controller.g.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'body_device_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
BodyDeviceModel _$BodyDeviceModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
BodyDeviceModel()..type = (json['type'] as num?)?.toInt();
|
||||||
|
|
||||||
|
Map<String, dynamic> _$BodyDeviceModelToJson(BodyDeviceModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'type': instance.type,
|
||||||
|
};
|
||||||
120
lib/controller/device/device_share_controller.dart
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
|
part 'device_share_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class DeviceShareModel {
|
||||||
|
String? _id; // 设备类型
|
||||||
|
String? name; // 设备类型
|
||||||
|
int? type; // 设备类型
|
||||||
|
String? image; // 设备类型
|
||||||
|
DeviceShareModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory DeviceShareModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$DeviceShareModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return DeviceShareModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$DeviceShareModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeviceShareController extends GetControllerEx<DeviceShareModel> {
|
||||||
|
DeviceShareController() {
|
||||||
|
attr = GetModel(DeviceShareModel()).obs;
|
||||||
|
}
|
||||||
|
RxList deviceTypeList = [].obs;
|
||||||
|
|
||||||
|
RxString account = "".obs;
|
||||||
|
RxString msg = "".obs;
|
||||||
|
RxInt code = 0.obs;
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceType() async {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_type;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = apiResponse.msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deviceTypeList.value = res.data;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> shareDevice(String mac) async {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
EasyDartModule.logger.info("分享设备");
|
||||||
|
DailyLogUtils.writeLog("分享设备");
|
||||||
|
try {
|
||||||
|
if (account.value == null || account.value.isEmpty) {
|
||||||
|
apiResponse.msg = "请输入手机号或者邮箱".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
if (!MyUtils.isValidPhoneNumber(account.value) &&
|
||||||
|
!MyUtils.isValidEmail(account.value)) {
|
||||||
|
apiResponse.msg = '请输入正确的手机号或者邮箱'.tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_share;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var data = {"type": 1, "userName": account.value, "mac": mac};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = apiResponse.msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = "操作成功".tr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg.value = res.msg!;
|
||||||
|
code.value = res.code!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("分享设备失败:${e.toString()}");
|
||||||
|
DailyLogUtils.writeLog("分享设备失败:${e.toString()}");
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/controller/device/device_share_controller.g.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'device_share_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
DeviceShareModel _$DeviceShareModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
DeviceShareModel()
|
||||||
|
..name = json['name'] as String?
|
||||||
|
..type = (json['type'] as num?)?.toInt()
|
||||||
|
..image = json['image'] as String?;
|
||||||
|
|
||||||
|
Map<String, dynamic> _$DeviceShareModelToJson(DeviceShareModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'type': instance.type,
|
||||||
|
'image': instance.image,
|
||||||
|
};
|
||||||
65
lib/controller/device/device_type_controller.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
|
part 'device_type_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class DeviceTypeModel {
|
||||||
|
String? _id; // 设备类型
|
||||||
|
String? name; // 设备类型
|
||||||
|
int? type; // 设备类型
|
||||||
|
String? image; // 设备类型
|
||||||
|
DeviceTypeModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory DeviceTypeModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$DeviceTypeModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return DeviceTypeModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$DeviceTypeModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeviceTypeController extends GetControllerEx<DeviceTypeModel> {
|
||||||
|
DeviceTypeController() {
|
||||||
|
attr = GetModel(DeviceTypeModel()).obs;
|
||||||
|
}
|
||||||
|
RxList deviceTypeList = [].obs;
|
||||||
|
|
||||||
|
Future<ApiResponse> getDeviceType() async {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.device_type;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = apiResponse.msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deviceTypeList.value = res.data;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/controller/device/device_type_controller.g.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'device_type_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
DeviceTypeModel _$DeviceTypeModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
DeviceTypeModel()
|
||||||
|
..name = json['name'] as String?
|
||||||
|
..type = (json['type'] as num?)?.toInt()
|
||||||
|
..image = json['image'] as String?;
|
||||||
|
|
||||||
|
Map<String, dynamic> _$DeviceTypeModelToJson(DeviceTypeModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'type': instance.type,
|
||||||
|
'image': instance.image,
|
||||||
|
};
|
||||||
50
lib/controller/home/home_controller.dart
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
|
||||||
|
part 'home_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class HomeModel {
|
||||||
|
int? type = 1; //我的e护 2.云关爱
|
||||||
|
|
||||||
|
HomeModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory HomeModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$HomeModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return HomeModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$HomeModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HomeController extends GetControllerEx<HomeModel> {
|
||||||
|
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
BodyDeviceController deviceController = Get.find();
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
HomeController() {
|
||||||
|
attr = GetModel(HomeModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxInt sleepNum = 0.obs;
|
||||||
|
|
||||||
|
getSleepReport() {
|
||||||
|
sleepNum.value = 5;
|
||||||
|
updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
lib/controller/home/home_controller.g.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'home_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
HomeModel _$HomeModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
HomeModel()..type = (json['type'] as num?)?.toInt();
|
||||||
|
|
||||||
|
Map<String, dynamic> _$HomeModelToJson(HomeModel instance) => <String, dynamic>{
|
||||||
|
'type': instance.type,
|
||||||
|
};
|
||||||
@@ -12,6 +12,7 @@ import 'package:vbvs_app/common/color/app_uri_status.dart';
|
|||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/model/api_response.dart';
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
part 'login_controller.g.dart';
|
part 'login_controller.g.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
@@ -84,10 +85,12 @@ class LoginController extends GetControllerEx<LoginModel> {
|
|||||||
if (res.code == HttpStatusCodes.ok) {
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
UserInfoController userInfoController = Get.find();
|
UserInfoController userInfoController = Get.find();
|
||||||
userInfoController.model.login = 1;
|
userInfoController.model.login = 1;
|
||||||
|
userInfoController.model.user = UserModel.fromJson(res.data);
|
||||||
String token = response.headers['token']!.first;
|
String token = response.headers['token']!.first;
|
||||||
EasyDartModule.dio.token = token;
|
EasyDartModule.dio.token = token;
|
||||||
final box = GetStorage();
|
final box = GetStorage();
|
||||||
box.write('token', userInfoController.model.token); // 存储 token
|
box.write('token', token); // 存储 token
|
||||||
|
box.write('user', userInfoController.model.user!.toJson()); // 存储用户信息
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
@@ -97,43 +100,48 @@ class LoginController extends GetControllerEx<LoginModel> {
|
|||||||
|
|
||||||
Future<ApiResponse> getCode(BuildContext context) async {
|
Future<ApiResponse> getCode(BuildContext context) async {
|
||||||
ApiResponse apiResponse = ApiResponse(code: -1, msg: "其他手机登录页.发送失败".tr);
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "其他手机登录页.发送失败".tr);
|
||||||
if (model.register_agree == null || model.register_agree != true) {
|
try {
|
||||||
apiResponse.msg = "登录页.未同意协议".tr;
|
if (model.register_agree == null || model.register_agree != true) {
|
||||||
return apiResponse;
|
apiResponse.msg = "登录页.未同意协议".tr;
|
||||||
}
|
return apiResponse;
|
||||||
if (model.phone == null || model.phone!.isEmpty) {
|
|
||||||
apiResponse.msg = "其他手机登录页.请输入手机号".tr;
|
|
||||||
return apiResponse;
|
|
||||||
}
|
|
||||||
if (!MyUtils.isValidPhoneNumber(model.phone!) &&
|
|
||||||
!MyUtils.isValidEmail(model.phone!)) {
|
|
||||||
apiResponse.msg = '其他手机登录页.不正确手机号'.tr;
|
|
||||||
return apiResponse;
|
|
||||||
}
|
|
||||||
String serviceAddress = ServiceConstant.service_address;
|
|
||||||
String serviceName = ServiceConstant.server_service;
|
|
||||||
String serviceApi = ServiceConstant.send_code;
|
|
||||||
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
|
||||||
var data = {
|
|
||||||
"userName": model.phone,
|
|
||||||
};
|
|
||||||
var response =
|
|
||||||
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
|
|
||||||
if (response != null) {
|
|
||||||
var responseData =
|
|
||||||
response.data is String ? jsonDecode(response.data) : response.data;
|
|
||||||
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
|
|
||||||
if (res.code != HttpStatusCodes.ok) {
|
|
||||||
if (res.msg == null || res.msg!.isEmpty) {
|
|
||||||
res.msg = apiResponse.msg;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (res.msg == null || res.msg!.isEmpty) {
|
|
||||||
res.msg = "其他手机登录页.发送成功".tr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res;
|
if (model.phone == null || model.phone!.isEmpty) {
|
||||||
} else {
|
apiResponse.msg = "其他手机登录页.请输入手机号".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
if (!MyUtils.isValidPhoneNumber(model.phone!) &&
|
||||||
|
!MyUtils.isValidEmail(model.phone!)) {
|
||||||
|
apiResponse.msg = '其他手机登录页.不正确手机号'.tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.send_code;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var data = {
|
||||||
|
"userName": model.phone,
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
if (res.code != HttpStatusCodes.ok) {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = apiResponse.msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (res.msg == null || res.msg!.isEmpty) {
|
||||||
|
res.msg = "其他手机登录页.发送成功".tr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ LoginModel _$LoginModelFromJson(Map<String, dynamic> json) => LoginModel()
|
|||||||
..showPd = json['showPd'] as bool?
|
..showPd = json['showPd'] as bool?
|
||||||
..forceLogin = (json['forceLogin'] as num?)?.toInt()
|
..forceLogin = (json['forceLogin'] as num?)?.toInt()
|
||||||
..isIos = json['isIos'] as bool?
|
..isIos = json['isIos'] as bool?
|
||||||
..isWeChatNotInstalled = json['isWeChatNotInstalled'] as bool?;
|
..isWeChatNotInstalled = json['isWeChatNotInstalled'] as bool?
|
||||||
|
..register_agree = json['register_agree'] as bool?;
|
||||||
|
|
||||||
Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
|
Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
@@ -30,4 +31,5 @@ Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
|
|||||||
'forceLogin': instance.forceLogin,
|
'forceLogin': instance.forceLogin,
|
||||||
'isIos': instance.isIos,
|
'isIos': instance.isIos,
|
||||||
'isWeChatNotInstalled': instance.isWeChatNotInstalled,
|
'isWeChatNotInstalled': instance.isWeChatNotInstalled,
|
||||||
|
'register_agree': instance.register_agree,
|
||||||
};
|
};
|
||||||
|
|||||||
78
lib/controller/message/message_controller.dart
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
|
part 'message_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class MessageModel {
|
||||||
|
int? type = 1; //设备类型 1:体征消息 2.系统消息
|
||||||
|
|
||||||
|
MessageModel();
|
||||||
|
|
||||||
|
// 从JSON反序列化时的异常处理
|
||||||
|
|
||||||
|
factory MessageModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
try {
|
||||||
|
return _$MessageModelFromJson(json);
|
||||||
|
} catch (e) {
|
||||||
|
// 在实际应用中,应该有更细致的异常处理策略和错误日志
|
||||||
|
return MessageModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化为JSON时的异常处理
|
||||||
|
Map<String, dynamic> toJson() => _$MessageModelToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageController extends GetControllerEx<MessageModel> {
|
||||||
|
MessageController() {
|
||||||
|
attr = GetModel(MessageModel()).obs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxList msssageList = [].obs;
|
||||||
|
|
||||||
|
Future<ApiResponse> getMessageList({String? key}) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.message_list;
|
||||||
|
String messageType = "app_system";
|
||||||
|
if (model.type == 1) {
|
||||||
|
messageType = "app_body";
|
||||||
|
} else {
|
||||||
|
messageType = "app_system";
|
||||||
|
}
|
||||||
|
String queryUrl =
|
||||||
|
"${serviceAddress}${serviceName}${serviceApi}?type=${messageType}'}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("设备请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("设备请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lib/controller/message/message_controller.g.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'message_controller.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
MessageModel _$MessageModelFromJson(Map<String, dynamic> json) =>
|
||||||
|
MessageModel()..type = (json['type'] as num?)?.toInt();
|
||||||
|
|
||||||
|
Map<String, dynamic> _$MessageModelToJson(MessageModel instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'type': instance.type,
|
||||||
|
};
|
||||||
@@ -1,14 +1,20 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
|
||||||
part 'person_controller.g.dart'; // 由json_serializable自动生成的部分
|
part 'person_controller.g.dart'; // 由json_serializable自动生成的部分
|
||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class PersonModel {
|
class PersonModel {
|
||||||
int read = 1;
|
int? read = 1;
|
||||||
|
// String? name;
|
||||||
DateTime? birthday;
|
|
||||||
double? weight;
|
|
||||||
|
|
||||||
PersonModel();
|
PersonModel();
|
||||||
|
|
||||||
@@ -31,4 +37,151 @@ class PersonController extends GetControllerEx<PersonModel> {
|
|||||||
PersonController() {
|
PersonController() {
|
||||||
attr = GetModel(PersonModel()).obs;
|
attr = GetModel(PersonModel()).obs;
|
||||||
}
|
}
|
||||||
|
RxList selectedDiseaseIds = [].obs;
|
||||||
|
// RxList diseaseList = [
|
||||||
|
// {'id': 1, 'name': '高血压'},
|
||||||
|
// {'id': 2, 'name': '糖尿病'},
|
||||||
|
// {'id': 3, 'name': '冠心病'},
|
||||||
|
// {'id': 4, 'name': '哮喘'},
|
||||||
|
// {'id': 5, 'name': '脑卒中'},
|
||||||
|
// {'id': 6, 'name': '慢性肾病'},
|
||||||
|
// {'id': 7, 'name': '慢阻肺'},
|
||||||
|
// {'id': 8, 'name': '类风湿关节炎'},
|
||||||
|
// {'id': 9, 'name': '类风湿关节炎类风湿关节炎'},
|
||||||
|
// {'id': 10, 'name': '类风湿关节炎类风湿关节炎类风湿关节炎'},
|
||||||
|
// ].obs;
|
||||||
|
|
||||||
|
RxString currentPersonId = "".obs;
|
||||||
|
RxString name = "".obs;
|
||||||
|
RxInt gender = 1.obs;
|
||||||
|
RxString birthday = "".obs;
|
||||||
|
RxInt weight = 65.obs;
|
||||||
|
DateTime? dateTime; //选择时间
|
||||||
|
RxList diseaseList = [].obs;
|
||||||
|
|
||||||
|
//保存人员资料
|
||||||
|
// void savePersonData() {
|
||||||
|
// print("id->" + currentPersonId.value);
|
||||||
|
// print("name->" + name.value);
|
||||||
|
// print("gender->${gender.value}");
|
||||||
|
// print("生日->${birthday.value}");
|
||||||
|
// print("体重->${weight.value}");
|
||||||
|
// print("慢病->${selectedDiseaseIds.value}");
|
||||||
|
// }
|
||||||
|
|
||||||
|
Future<ApiResponse> savePersonData() async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "蓝牙绑定.绑定失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.person_info;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
if (name.value.isEmpty) {
|
||||||
|
apiResponse.msg = "请输入姓名".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
if (birthday.value.isEmpty) {
|
||||||
|
apiResponse.msg = "请选择生日".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
if (weight.value == 0) {
|
||||||
|
apiResponse.msg = "请输入体重".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
"id": currentPersonId.value,
|
||||||
|
"name": name.value,
|
||||||
|
"gender": gender.value,
|
||||||
|
"birthday": birthday.value,
|
||||||
|
"weight": weight.value,
|
||||||
|
"disease": selectedDiseaseIds.value,
|
||||||
|
};
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("保存人员资料异常: $e");
|
||||||
|
DailyLogUtils.writeLog("保存人员资料异常: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> updatePersonName(person, deviceId) async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.person_info;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
if (name.value.isEmpty) {
|
||||||
|
apiResponse.msg = "请输入姓名".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
person['name'] = name.value;
|
||||||
|
person['id'] = deviceId;
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(person));
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("保存人员资料异常: $e");
|
||||||
|
DailyLogUtils.writeLog("保存人员资料异常: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> getDiseaseData() async {
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.disease_list;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
// bindDeviceNum.value = res.total!;
|
||||||
|
diseaseList.value = res.data!;
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("疾病请求列表: $e");
|
||||||
|
DailyLogUtils.writeLog("疾病请求列表: $e");
|
||||||
|
}
|
||||||
|
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,14 +6,10 @@ part of 'person_controller.dart';
|
|||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
PersonModel _$PersonModelFromJson(Map<String, dynamic> json) => PersonModel()
|
PersonModel _$PersonModelFromJson(Map<String, dynamic> json) =>
|
||||||
..read = (json['read'] as num).toInt()
|
PersonModel()..read = (json['read'] as num?)?.toInt();
|
||||||
..birthday = json['birthday'] == null
|
|
||||||
? null
|
|
||||||
: DateTime.parse(json['birthday'] as String);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$PersonModelToJson(PersonModel instance) =>
|
Map<String, dynamic> _$PersonModelToJson(PersonModel instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'read': instance.read,
|
'read': instance.read,
|
||||||
'birthday': instance.birthday?.toIso8601String(),
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
|
import 'package:EasyDartModule/EasyDartModule.dart';
|
||||||
|
import 'package:dio/dio.dart' as dio;
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:get_storage/get_storage.dart';
|
||||||
|
import 'package:img_picker/img_picker.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/home/home_controller.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
import 'package:vbvs_app/model/user_data.dart';
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
|
|
||||||
part 'user_info_controller.g.dart';
|
part 'user_info_controller.g.dart';
|
||||||
@@ -24,11 +36,12 @@ class UserInfoModel {
|
|||||||
String? img_bucket = 'user';
|
String? img_bucket = 'user';
|
||||||
int? login = 0; //0未登录 1 登录
|
int? login = 0; //0未登录 1 登录
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int? deviceBindNum = 0; //绑定设备数量
|
int? deviceBindNum = 0; //绑定设备数量
|
||||||
|
|
||||||
int? loginPhone = 0;//0 本机号码 1其他手机号
|
int? loginPhone = 0; //0 本机号码 1其他手机号
|
||||||
|
|
||||||
|
// String? nickname; //修改昵称
|
||||||
|
// String? avatar; //修改头像地址
|
||||||
|
|
||||||
UserInfoModel();
|
UserInfoModel();
|
||||||
static UserInfoModel fromJson(Map<String, dynamic> json) =>
|
static UserInfoModel fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -41,4 +54,146 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
|
|||||||
UserInfoController() {
|
UserInfoController() {
|
||||||
attr = GetModel(UserInfoModel()).obs;
|
attr = GetModel(UserInfoModel()).obs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ApiResponse> uploadImg() async {
|
||||||
|
EasyDartModule.logger.info("请求上传图片");
|
||||||
|
DailyLogUtils.writeLog("请求上传图片");
|
||||||
|
final ImagePicker picker = ImagePicker();
|
||||||
|
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.头像上传失败".tr);
|
||||||
|
if (image != null) {
|
||||||
|
int fileSize = await image.length(); // 获取图片大小,单位为字节
|
||||||
|
if (fileSize > 1048576) {
|
||||||
|
apiResponse.msg = "我的.头像限制".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.upload_file;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var formData = dio.FormData.fromMap({
|
||||||
|
"type": 1,
|
||||||
|
"file": await dio.MultipartFile.fromFile(
|
||||||
|
image.path, // 确保 image 是 File 类型
|
||||||
|
filename: image.path.split('/').last,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
var response = await EasyDartModule.dio.post(queryUrl, data: formData);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData = response.data is String
|
||||||
|
? jsonDecode(response.data)
|
||||||
|
: response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(apiResponse, "我的.上传成功".tr, "我的.头像上传失败".tr);
|
||||||
|
model.user!.tmpHead = res.data['path'];
|
||||||
|
updateAll();
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apiResponse.msg = "我的.未选择图片".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.error("上传图片失败->$e");
|
||||||
|
DailyLogUtils.writeError("上传图片失败->$e");
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新用户信息
|
||||||
|
Future<ApiResponse> updateData() async {
|
||||||
|
EasyDartModule.logger.info("更新用户资料");
|
||||||
|
DailyLogUtils.writeLog("更新用户资料");
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.保存失败".tr);
|
||||||
|
UserModel user = model.user!;
|
||||||
|
if (user.tmpNickName == null || user.tmpNickName!.isEmpty) {
|
||||||
|
apiResponse.msg = "我的.昵称为空".tr;
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.user_info;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
final data = {
|
||||||
|
"nickName": user.tmpNickName,
|
||||||
|
if (user.tmpHead != null && user.tmpHead!.isNotEmpty)
|
||||||
|
"avatar": user.tmpHead,
|
||||||
|
};
|
||||||
|
|
||||||
|
var response =
|
||||||
|
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
|
||||||
|
if (apiResponse != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(res, "我的.保存成功".tr, "我的.保存失败".tr);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("更新用户资料失败->$e");
|
||||||
|
DailyLogUtils.writeLog("更新用户资料失败->$e");
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询用户信息
|
||||||
|
Future<ApiResponse> getUserInfo() async {
|
||||||
|
EasyDartModule.logger.info("查询用户资料");
|
||||||
|
DailyLogUtils.writeLog("查询用户资料");
|
||||||
|
try {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.查询失败".tr);
|
||||||
|
String serviceAddress = ServiceConstant.service_address;
|
||||||
|
String serviceName = ServiceConstant.server_service;
|
||||||
|
String serviceApi = ServiceConstant.user_info;
|
||||||
|
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||||||
|
var response = await EasyDartModule.dio.get(queryUrl);
|
||||||
|
if (response != null) {
|
||||||
|
var responseData =
|
||||||
|
response.data is String ? jsonDecode(response.data) : response.data;
|
||||||
|
ApiResponse res =
|
||||||
|
ApiResponse.fromJson(responseData, (object) => object);
|
||||||
|
MyUtils.formatResponse(apiResponse, "我的.保存成功".tr, "我的.保存失败".tr);
|
||||||
|
if (res.code == HttpStatusCodes.ok) {
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
userInfoController.model.user = UserModel.fromJson(res.data);
|
||||||
|
final box = GetStorage();
|
||||||
|
box.write('user', userInfoController.model.user!.toJson()); // 存储用户信息
|
||||||
|
userInfoController.updateAll();
|
||||||
|
}
|
||||||
|
return apiResponse;
|
||||||
|
} else {
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
EasyDartModule.logger.info("更新用户资料失败->$e");
|
||||||
|
DailyLogUtils.writeLog("更新用户资料失败->$e");
|
||||||
|
return ApiResponse(code: -1, msg: "服务器.失败".tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiResponse logOut() {
|
||||||
|
ApiResponse apiResponse = ApiResponse(code: 1, msg: "设置页.退出成功".tr);
|
||||||
|
EasyDartModule.logger.info("退出登录");
|
||||||
|
DailyLogUtils.writeLog("退出登录");
|
||||||
|
model.login = 0;
|
||||||
|
EasyDartModule.dio.token = null;
|
||||||
|
final box = GetStorage();
|
||||||
|
box.remove("user");
|
||||||
|
box.remove("token");
|
||||||
|
BodyDeviceController bodyDeviceController = Get.find();
|
||||||
|
bodyDeviceController.bindDeviceNum.value = 0;
|
||||||
|
HomeController homeController = Get.find();
|
||||||
|
homeController.sleepNum.value = 0;
|
||||||
|
|
||||||
|
bodyDeviceController.sleepReportData.value = {};
|
||||||
|
return apiResponse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
|
|||||||
..deviceModel = json['deviceModel'] as String?
|
..deviceModel = json['deviceModel'] as String?
|
||||||
..appVersion = json['appVersion'] as String?
|
..appVersion = json['appVersion'] as String?
|
||||||
..img_bucket = json['img_bucket'] as String?
|
..img_bucket = json['img_bucket'] as String?
|
||||||
..login = (json['login'] as num?)?.toInt();
|
..login = (json['login'] as num?)?.toInt()
|
||||||
|
..deviceBindNum = (json['deviceBindNum'] as num?)?.toInt()
|
||||||
|
..loginPhone = (json['loginPhone'] as num?)?.toInt();
|
||||||
|
|
||||||
Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
|
Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
@@ -33,4 +35,6 @@ Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
|
|||||||
'appVersion': instance.appVersion,
|
'appVersion': instance.appVersion,
|
||||||
'img_bucket': instance.img_bucket,
|
'img_bucket': instance.img_bucket,
|
||||||
'login': instance.login,
|
'login': instance.login,
|
||||||
|
'deviceBindNum': instance.deviceBindNum,
|
||||||
|
'loginPhone': instance.loginPhone,
|
||||||
};
|
};
|
||||||
|
|||||||
9
lib/enum/BindType.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
enum BindType {
|
||||||
|
active(1, '主动绑定'),
|
||||||
|
share(2, '分享绑定');
|
||||||
|
|
||||||
|
final int code;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const BindType(this.code, this.description);
|
||||||
|
}
|
||||||
9
lib/enum/LoginStatus.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
enum LoginStatus {
|
||||||
|
LOGIN(1, '已登录'),
|
||||||
|
NOT_LOGIN(2, '未登录');
|
||||||
|
|
||||||
|
final int code;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const LoginStatus(this.code, this.description);
|
||||||
|
}
|
||||||
@@ -6,34 +6,39 @@ import 'package:EasyDartModule/base/websocket/WebSocket.dart';
|
|||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:get_storage/get_storage.dart';
|
import 'package:get_storage/get_storage.dart';
|
||||||
import 'package:localstorage/localstorage.dart';
|
import 'package:localstorage/localstorage.dart';
|
||||||
|
import 'package:syncfusion_localizations/syncfusion_localizations.dart';
|
||||||
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
import 'package:vbvs_app/common/color/ServiceConstant.dart';
|
||||||
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/home/home_controller.dart';
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
import 'package:vbvs_app/controller/login/login_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/message/message_controller.dart';
|
||||||
import 'package:vbvs_app/controller/person/person_controller.dart';
|
import 'package:vbvs_app/controller/person/person_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
import 'package:vbvs_app/controller/time/countdown_controller.dart';
|
||||||
import 'package:vbvs_app/language/AppLanguage.dart';
|
import 'package:vbvs_app/language/AppLanguage.dart';
|
||||||
import 'package:vbvs_app/model/CustomThemeColor.dart';
|
import 'package:vbvs_app/model/CustomThemeColor.dart';
|
||||||
import 'package:vbvs_app/model/user_data.dart';
|
import 'package:vbvs_app/model/user_data.dart';
|
||||||
|
|
||||||
import 'controller/user_info_controller.dart';
|
import 'controller/user_info_controller.dart';
|
||||||
import 'routers/routers.dart';
|
import 'routers/routers.dart';
|
||||||
|
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
||||||
import 'package:syncfusion_localizations/syncfusion_localizations.dart';
|
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await AppLanguage().loadLanguage("zh_CN");
|
await AppLanguage().loadLanguage("zh_CN");
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// ApiService.init();
|
// ApiService.init();
|
||||||
// await GetStorage.init();
|
await GetStorage.init();
|
||||||
// 初始化登录
|
// 初始化登录
|
||||||
await initLocalStorage();
|
await initLocalStorage();
|
||||||
initEasyDartModule();
|
initEasyDartModule();
|
||||||
@@ -54,37 +59,37 @@ Future<void> main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initEasyDartModule() {
|
void initEasyDartModule() {
|
||||||
//初始化
|
try {
|
||||||
EasyDartModule.init(
|
EasyDartModule.init(
|
||||||
loggerConfig:
|
loggerConfig:
|
||||||
LoggerConfig(host: ServiceConstant.logService, serviceName: "web"),
|
LoggerConfig(host: ServiceConstant.logService, serviceName: "web"),
|
||||||
webSocketConfig:
|
webSocketConfig:
|
||||||
WebSocketConfig(ServiceConstant.webSocketService, (data) {
|
WebSocketConfig(ServiceConstant.webSocketService, (data) {
|
||||||
// 接收到服务消息
|
// 接收到服务消息
|
||||||
var json = jsonDecode(data);
|
var json = jsonDecode(data);
|
||||||
if (json["path"] != null) {
|
if (json["path"] != null) {
|
||||||
var call = CommonVariables.callMap[json["path"]];
|
var call = CommonVariables.callMap[json["path"]];
|
||||||
if (call != null) {
|
if (call != null) {
|
||||||
try {
|
try {
|
||||||
call(json["data"]);
|
call(json["data"]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("未找到当前路径: ${json["path"]} 回调函数");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
print("未找到当前路径: ${json["path"]} 回调函数");
|
|
||||||
}
|
}
|
||||||
}
|
// print(data);
|
||||||
// print(data);
|
}, onOpen: () {
|
||||||
}, onOpen: () {
|
// 连接建立完毕
|
||||||
//连接建立完毕
|
// EasyDartModule.websocket
|
||||||
// EasyDartModule.websocket
|
// .sendData(jsonEncode({"path": "/aa/bb", "type": 1}));
|
||||||
// .sendData(jsonEncode({"path": "/aa/bb", "type": 1}));
|
print("object");
|
||||||
}));
|
}));
|
||||||
EasyDartModule.dio.token = localStorage.getItem('token');
|
} catch (e) {
|
||||||
// document.onContextMenu.listen((event) {
|
print(e);
|
||||||
// event.preventDefault();
|
}
|
||||||
// });
|
//初始化
|
||||||
EasyDartModule.dio.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI2ODAxY2JmMzY5YjJhODQ5MWQwMDAwMDAiLCJ0aWQiOiI2N2Y1ZDk2ZTI2ZWYzMTA0NjMwMDAwMDAiLCJsZXZlbCI6NSwiaWF0IjoxNzQ0OTQ4MjExfQ._XXG3WzEHuOzWdj01NXJxLJpxe3SU20XQqShBZUHCUU";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initLog() {}
|
initLog() {}
|
||||||
@@ -103,12 +108,16 @@ Future<void> initLogin() async {
|
|||||||
final box = GetStorage();
|
final box = GetStorage();
|
||||||
UserInfoController userInfoController = Get.find();
|
UserInfoController userInfoController = Get.find();
|
||||||
String? token = box.read('token');
|
String? token = box.read('token');
|
||||||
// print('Token: $token');
|
try {
|
||||||
Map<String, dynamic>? userMap = box.read('user');
|
Map<String, dynamic>? userMap = box.read('user');
|
||||||
if (userMap != null) {
|
if (userMap != null) {
|
||||||
UserModel user = UserModel.fromJson(userMap);
|
UserModel user = UserModel.fromJson(userMap);
|
||||||
userInfoController.model.user = user;
|
userInfoController.model.user = user;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
userInfoController.model.login = 1;
|
userInfoController.model.login = 1;
|
||||||
// 根据token去请求
|
// 根据token去请求
|
||||||
@@ -199,13 +208,18 @@ class MyApp extends StatelessWidget {
|
|||||||
initialRoute: "/mianPageBottomChange",
|
initialRoute: "/mianPageBottomChange",
|
||||||
onGenerateRoute: onGenerateRoute,
|
onGenerateRoute: onGenerateRoute,
|
||||||
initialBinding: BindingsBuilder(() => [
|
initialBinding: BindingsBuilder(() => [
|
||||||
Get.lazyPut(() => UserInfoController()),
|
// Get.lazyPut(() => UserInfoController()),
|
||||||
Get.put(GlobalController()),
|
Get.put(GlobalController()),
|
||||||
Get.lazyPut(() => MainPageController()),
|
Get.lazyPut(() => MainPageController()),
|
||||||
Get.lazyPut(() => BlueteethBindController()),
|
Get.lazyPut(() => BlueteethBindController()),
|
||||||
Get.lazyPut(() => PersonController()),
|
Get.lazyPut(() => PersonController()),
|
||||||
Get.lazyPut(() => CountdownController()),
|
Get.lazyPut(() => CountdownController()),
|
||||||
Get.lazyPut(() => LoginController()),
|
Get.lazyPut(() => LoginController()),
|
||||||
|
Get.lazyPut(() => DeviceTypeController()),
|
||||||
|
Get.lazyPut(() => BodyDeviceController()),
|
||||||
|
Get.lazyPut(() => HomeController()),
|
||||||
|
Get.lazyPut(() => DeviceShareController()),
|
||||||
|
Get.lazyPut(() => MessageController()),
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class BleDeviceData {
|
|||||||
final int flag; // 设备属性
|
final int flag; // 设备属性
|
||||||
final int version; // 软件版本
|
final int version; // 软件版本
|
||||||
final int qsn; // 广播帧序列号高16位
|
final int qsn; // 广播帧序列号高16位
|
||||||
bool? bind = true; // 设备状态
|
bool? bind = false; // 设备状态
|
||||||
String? name; //设备名称
|
String? name; //设备名称
|
||||||
int? rssi;
|
int? rssi;
|
||||||
String? mac; //mac地址
|
String? mac; //mac地址
|
||||||
|
|||||||
16
lib/model/WebSocketMessage.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'WebSocketMessage.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class WebSocketMessage {
|
||||||
|
String path;
|
||||||
|
int? type;
|
||||||
|
dynamic data;
|
||||||
|
|
||||||
|
WebSocketMessage({required this.path, this.type, this.data});
|
||||||
|
|
||||||
|
static WebSocketMessage fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$WebSocketMessageFromJson(json);
|
||||||
|
Map<String, dynamic> toJson() => _$WebSocketMessageToJson(this);
|
||||||
|
}
|
||||||
21
lib/model/WebSocketMessage.g.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'WebSocketMessage.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
WebSocketMessage _$WebSocketMessageFromJson(Map<String, dynamic> json) =>
|
||||||
|
WebSocketMessage(
|
||||||
|
path: json['path'] as String,
|
||||||
|
type: (json['type'] as num?)?.toInt(),
|
||||||
|
data: json['data'],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$WebSocketMessageToJson(WebSocketMessage instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'path': instance.path,
|
||||||
|
'type': instance.type,
|
||||||
|
'data': instance.data,
|
||||||
|
};
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
class ApiResponse<T> {
|
class ApiResponse<T> {
|
||||||
int? code;
|
int? code;
|
||||||
T? data;
|
T? data;
|
||||||
String? msg;
|
String? msg;
|
||||||
|
int? total;
|
||||||
|
|
||||||
ApiResponse({required this.code, this.data, this.msg});
|
ApiResponse({required this.code, this.data, this.msg, this.total});
|
||||||
factory ApiResponse.fromJson(
|
factory ApiResponse.fromJson(
|
||||||
Map<String, dynamic> json, T Function(Object?) fromJsonT) {
|
Map<String, dynamic> json, T Function(Object?) fromJsonT) {
|
||||||
return ApiResponse<T>(
|
return ApiResponse<T>(
|
||||||
code: json['code'] as int,
|
code: json['code'] as int,
|
||||||
data: json['data'] != null ? fromJsonT(json['data']) : null,
|
data: json['data'] != null ? fromJsonT(json['data']) : null,
|
||||||
msg: json['msg'] as String?,
|
msg: json['msg'] as String?,
|
||||||
|
total: json['total'] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,16 @@ part 'user_data.g.dart';
|
|||||||
class UserModel {
|
class UserModel {
|
||||||
String? uid;
|
String? uid;
|
||||||
String? userName;
|
String? userName;
|
||||||
String? nickName;
|
String? nick_name;
|
||||||
String? tel;
|
String? phone;
|
||||||
String? exp1;
|
String? exp1;
|
||||||
String? head;
|
String? avatar;
|
||||||
String? tmpHead;
|
String? tmpHead;
|
||||||
String? tmpNickName;
|
String? tmpNickName;
|
||||||
|
int? deleted;
|
||||||
|
String? status;
|
||||||
|
int? created_at;
|
||||||
|
String? email;
|
||||||
|
|
||||||
UserModel();
|
UserModel();
|
||||||
static UserModel fromJson(Map<String, dynamic> json) =>
|
static UserModel fromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -9,20 +9,28 @@ part of 'user_data.dart';
|
|||||||
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel()
|
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel()
|
||||||
..uid = json['uid'] as String?
|
..uid = json['uid'] as String?
|
||||||
..userName = json['userName'] as String?
|
..userName = json['userName'] as String?
|
||||||
..nickName = json['nickName'] as String?
|
..nick_name = json['nick_name'] as String?
|
||||||
..tel = json['tel'] as String?
|
..phone = json['phone'] as String?
|
||||||
..exp1 = json['exp1'] as String?
|
..exp1 = json['exp1'] as String?
|
||||||
..head = json['head'] as String?
|
..avatar = json['avatar'] as String?
|
||||||
..tmpHead = json['tmpHead'] as String?
|
..tmpHead = json['tmpHead'] as String?
|
||||||
..tmpNickName = json['tmpNickName'] as String?;
|
..tmpNickName = json['tmpNickName'] as String?
|
||||||
|
..deleted = (json['deleted'] as num?)?.toInt()
|
||||||
|
..status = json['status'] as String?
|
||||||
|
..created_at = (json['created_at'] as num?)?.toInt()
|
||||||
|
..email = json['email'] as String?;
|
||||||
|
|
||||||
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
||||||
'uid': instance.uid,
|
'uid': instance.uid,
|
||||||
'userName': instance.userName,
|
'userName': instance.userName,
|
||||||
'nickName': instance.nickName,
|
'nick_name': instance.nick_name,
|
||||||
'tel': instance.tel,
|
'phone': instance.phone,
|
||||||
'exp1': instance.exp1,
|
'exp1': instance.exp1,
|
||||||
'head': instance.head,
|
'avatar': instance.avatar,
|
||||||
'tmpHead': instance.tmpHead,
|
'tmpHead': instance.tmpHead,
|
||||||
'tmpNickName': instance.tmpNickName,
|
'tmpNickName': instance.tmpNickName,
|
||||||
|
'deleted': instance.deleted,
|
||||||
|
'status': instance.status,
|
||||||
|
'created_at': instance.created_at,
|
||||||
|
'email': instance.email,
|
||||||
};
|
};
|
||||||
|
|||||||
803
lib/pages/device/BodyDeviceWidget.dart
Normal file
@@ -0,0 +1,803 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/NullDataComponentWidget.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/body_device_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/pages/device/component/DeviceDataComponentWidget.dart';
|
||||||
|
|
||||||
|
class BodyDeviceWidget extends StatefulWidget {
|
||||||
|
const BodyDeviceWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BodyDeviceWidget> createState() => _BodyDevicePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
||||||
|
final ThemeController themeController = Get.find();
|
||||||
|
final BodyDeviceController bodyDeviceController = Get.find();
|
||||||
|
final GlobalKey addIconKey = GlobalKey();
|
||||||
|
OverlayEntry? _popupEntry;
|
||||||
|
|
||||||
|
void _showPopup() {
|
||||||
|
final renderBox =
|
||||||
|
addIconKey.currentContext?.findRenderObject() as RenderBox?;
|
||||||
|
if (renderBox == null) return;
|
||||||
|
|
||||||
|
final position = renderBox.localToGlobal(Offset.zero);
|
||||||
|
final size = renderBox.size;
|
||||||
|
double popupWidth = 190.rpx;
|
||||||
|
|
||||||
|
// 移除之前的弹窗
|
||||||
|
_popupEntry?.remove();
|
||||||
|
|
||||||
|
// 创建新的 OverlayEntry
|
||||||
|
_popupEntry = OverlayEntry(
|
||||||
|
builder: (context) => Stack(
|
||||||
|
children: [
|
||||||
|
// 半透明背景,点击后关闭弹窗
|
||||||
|
ModalBarrier(
|
||||||
|
dismissible: true,
|
||||||
|
color: Colors.transparent,
|
||||||
|
onDismiss: _hidePopup,
|
||||||
|
),
|
||||||
|
|
||||||
|
// 弹窗内容
|
||||||
|
Positioned(
|
||||||
|
top: position.dy + size.height + 26.rpx,
|
||||||
|
left: position.dx + size.width - popupWidth - 40.rpx,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
width: popupWidth,
|
||||||
|
padding: EdgeInsets.all(20.rpx),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc17,
|
||||||
|
borderRadius: BorderRadius.circular(12.rpx),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
blurRadius: 12.rpx,
|
||||||
|
spreadRadius: 2.rpx,
|
||||||
|
offset: Offset(0, 6.rpx),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 11.rpx),
|
||||||
|
ClickableContainer(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10.rpx),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc16.withOpacity(0.1),
|
||||||
|
borderRadius: 0.rpx,
|
||||||
|
onTap: () {
|
||||||
|
print('点击扫一扫');
|
||||||
|
_hidePopup();
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "待开发.提示".tr,
|
||||||
|
textColor: themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'扫一扫'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: AppConstants().normal_text_fontSize,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 35.rpx),
|
||||||
|
ClickableContainer(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10.rpx),
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc16.withOpacity(0.1),
|
||||||
|
borderRadius: 0.rpx,
|
||||||
|
onTap: () {
|
||||||
|
_hidePopup();
|
||||||
|
Get.toNamed("/deviceType");
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'蓝牙绑定'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: AppConstants().normal_text_fontSize,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 13.rpx),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 插入新的 OverlayEntry
|
||||||
|
Overlay.of(context)!.insert(_popupEntry!);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _hidePopup() {
|
||||||
|
_popupEntry?.remove();
|
||||||
|
_popupEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
bodyDeviceController.keyWord.value = "";
|
||||||
|
super.initState();
|
||||||
|
bodyDeviceController.getDeviceList().then((apiResponse) {
|
||||||
|
if (apiResponse.code != HttpStatusCodes.ok) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
Get.context!,
|
||||||
|
text: apiResponse.msg!,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodysize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
// width: bodysize.maxWidth,
|
||||||
|
// height: bodysize.maxHeight * 1,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
|
||||||
|
fit: BoxFit.fill, // 填满整个 Container
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent, // 加上这一行
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
/// 居中标题
|
||||||
|
Text(
|
||||||
|
'体征检测设备.标题'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
// child: returnIconButtom,
|
||||||
|
child: returnIconButtomAddCallback(() {
|
||||||
|
bodyDeviceController.getDeviceNum();
|
||||||
|
bodyDeviceController.getDeviceList();
|
||||||
|
bodyDeviceController.updateAll();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 20.rpx,
|
||||||
|
child: ClickableContainer(
|
||||||
|
key: addIconKey,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: themeController.currentColor.sc16,
|
||||||
|
padding: EdgeInsets.all(8.rpx),
|
||||||
|
onTap: () {
|
||||||
|
// 点击图标时,展示弹窗
|
||||||
|
if (_popupEntry == null) {
|
||||||
|
_showPopup();
|
||||||
|
} else {
|
||||||
|
_hidePopup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/add.svg',
|
||||||
|
width: 39.rpx,
|
||||||
|
height: 39.rpx,
|
||||||
|
color: themeController.currentColor.sc16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: GestureDetector(
|
||||||
|
onTap: _hidePopup, // 点击空白处自动关闭弹窗
|
||||||
|
child: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0.rpx, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 90.rpx,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc5),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 15.rpx, 30.rpx, 15.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// children: [
|
||||||
|
// Obx(() {
|
||||||
|
// return ClickableContainer(
|
||||||
|
// backgroundColor:
|
||||||
|
// Colors.transparent, // 或者你想设置的背景色
|
||||||
|
// highlightColor: themeController
|
||||||
|
// .currentColor.sc3, // 点击涟漪颜色
|
||||||
|
// borderRadius: 8.rpx, // 自定义圆角
|
||||||
|
// padding: EdgeInsets.all(
|
||||||
|
// 0), // 外部已经排版,这里不用加内边距
|
||||||
|
// onTap: () async {
|
||||||
|
// // 点击事件处理逻辑
|
||||||
|
// bodyDeviceController.model.type = 1;
|
||||||
|
// await bodyDeviceController
|
||||||
|
// .getDeviceList();
|
||||||
|
// bodyDeviceController.updateAll();
|
||||||
|
// },
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '体征检测设备.我的e护'.tr,
|
||||||
|
// style:
|
||||||
|
// FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: AppConstants()
|
||||||
|
// .title_text_fontSize,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color:
|
||||||
|
// bodyDeviceController
|
||||||
|
// .model
|
||||||
|
// .type ==
|
||||||
|
// 2
|
||||||
|
// ? themeController
|
||||||
|
// .currentColor
|
||||||
|
// .sc3
|
||||||
|
// : themeController
|
||||||
|
// .currentColor
|
||||||
|
// .sc2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// width: 100.rpx,
|
||||||
|
// child: Divider(
|
||||||
|
// height: 1.rpx,
|
||||||
|
// thickness: 2.rpx,
|
||||||
|
// color: bodyDeviceController
|
||||||
|
// .model.type ==
|
||||||
|
// 2
|
||||||
|
// ? Colors.transparent
|
||||||
|
// : themeController
|
||||||
|
// .currentColor.sc2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ].divide(SizedBox(height: 10.rpx)),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }),
|
||||||
|
// Obx(() {
|
||||||
|
// return ClickableContainer(
|
||||||
|
// backgroundColor: Colors.transparent,
|
||||||
|
// highlightColor:
|
||||||
|
// themeController.currentColor.sc3,
|
||||||
|
// borderRadius: 8.rpx,
|
||||||
|
// padding: EdgeInsets.all(0),
|
||||||
|
// onTap: () async {
|
||||||
|
// // 这里写你的点击逻辑
|
||||||
|
// bodyDeviceController.model.type = 2;
|
||||||
|
// await bodyDeviceController
|
||||||
|
// .getDeviceList();
|
||||||
|
// bodyDeviceController.updateAll();
|
||||||
|
// },
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '体征检测设备.云关爱'.tr,
|
||||||
|
// style:
|
||||||
|
// FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 30.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color:
|
||||||
|
// bodyDeviceController
|
||||||
|
// .model
|
||||||
|
// .type ==
|
||||||
|
// 1
|
||||||
|
// ? themeController
|
||||||
|
// .currentColor
|
||||||
|
// .sc3
|
||||||
|
// : themeController
|
||||||
|
// .currentColor
|
||||||
|
// .sc2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// width: 100.rpx,
|
||||||
|
// child: Divider(
|
||||||
|
// height: 1.rpx,
|
||||||
|
// thickness: 2.rpx,
|
||||||
|
// color: bodyDeviceController
|
||||||
|
// .model.type ==
|
||||||
|
// 1
|
||||||
|
// ? Colors.transparent
|
||||||
|
// : themeController
|
||||||
|
// .currentColor.sc2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ].divide(SizedBox(height: 10.rpx)),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }),
|
||||||
|
// ].divide(SizedBox(width: 60.rpx)),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
Stack(
|
||||||
|
alignment: Alignment.bottomLeft,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Obx(() {
|
||||||
|
return ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
borderRadius: 8.rpx,
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
onTap: () async {
|
||||||
|
bodyDeviceController.model.type =
|
||||||
|
1;
|
||||||
|
await bodyDeviceController
|
||||||
|
.getDeviceList();
|
||||||
|
bodyDeviceController.updateAll();
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width:
|
||||||
|
160.rpx, // 固定宽度为 160.rpx
|
||||||
|
alignment:
|
||||||
|
Alignment.center, // 文字居中
|
||||||
|
child: Text(
|
||||||
|
'体征检测设备.我的e护'.tr,
|
||||||
|
style: FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.title_text_fontSize,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: bodyDeviceController
|
||||||
|
.model
|
||||||
|
.type ==
|
||||||
|
2
|
||||||
|
? themeController
|
||||||
|
.currentColor
|
||||||
|
.sc3
|
||||||
|
: themeController
|
||||||
|
.currentColor
|
||||||
|
.sc2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10.rpx),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
Obx(() {
|
||||||
|
return ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
borderRadius: 8.rpx,
|
||||||
|
padding: EdgeInsets.all(0),
|
||||||
|
onTap: () async {
|
||||||
|
bodyDeviceController.model.type =
|
||||||
|
2;
|
||||||
|
await bodyDeviceController
|
||||||
|
.getDeviceList();
|
||||||
|
bodyDeviceController.updateAll();
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width:
|
||||||
|
160.rpx, // 固定宽度为 160.rpx
|
||||||
|
alignment:
|
||||||
|
Alignment.center, // 文字居中
|
||||||
|
child: Text(
|
||||||
|
'体征检测设备.云关爱'.tr,
|
||||||
|
style: FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.title_text_fontSize,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: bodyDeviceController
|
||||||
|
.model
|
||||||
|
.type ==
|
||||||
|
1
|
||||||
|
? themeController
|
||||||
|
.currentColor
|
||||||
|
.sc3
|
||||||
|
: themeController
|
||||||
|
.currentColor
|
||||||
|
.sc2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10.rpx),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
// 横线宽度固定为 160.rpx
|
||||||
|
double lineWidth = 160.rpx;
|
||||||
|
|
||||||
|
return AnimatedPositioned(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
bottom: 0,
|
||||||
|
left: bodyDeviceController.model.type ==
|
||||||
|
1
|
||||||
|
? 0
|
||||||
|
: 160.rpx, // 第二个按钮横线从 160.rpx 开始
|
||||||
|
child: Container(
|
||||||
|
width: lineWidth, // 横线宽度固定为 160.rpx
|
||||||
|
height: 4.rpx,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(2.rpx),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
width:
|
||||||
|
MediaQuery.sizeOf(context).width * 0.38,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 285.rpx,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black,
|
||||||
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0.rpx, 0, 20.rpx, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
height: 80.rpx,
|
||||||
|
child: Align(
|
||||||
|
alignment:
|
||||||
|
AlignmentDirectional(-1, 0),
|
||||||
|
child: TextFormField(
|
||||||
|
onChanged: (value) {
|
||||||
|
bodyDeviceController
|
||||||
|
.keyWord.value = value;
|
||||||
|
},
|
||||||
|
autofocus: false,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
contentPadding:
|
||||||
|
EdgeInsets.fromLTRB(
|
||||||
|
12.rpx, 0, 0.rpx, 0),
|
||||||
|
isDense: true,
|
||||||
|
labelStyle:
|
||||||
|
FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
hintText: '体征检测设备.输入关键词'.tr,
|
||||||
|
hintStyle: FlutterFlowTheme
|
||||||
|
.of(context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor
|
||||||
|
.sc4),
|
||||||
|
enabledBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
focusedBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
errorBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color:
|
||||||
|
FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.error,
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
focusedErrorBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color:
|
||||||
|
FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.error,
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
filled: false,
|
||||||
|
fillColor:
|
||||||
|
FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.secondaryBackground,
|
||||||
|
),
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
),
|
||||||
|
cursorColor:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.primaryText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(
|
||||||
|
26.rpx, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 40.rpx,
|
||||||
|
child: VerticalDivider(
|
||||||
|
thickness: 2.rpx,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Text(
|
||||||
|
// '体征检测设备.搜索'.tr,
|
||||||
|
// style:
|
||||||
|
// FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: AppConstants()
|
||||||
|
// .normal_text_fontSize,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc2,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor:
|
||||||
|
Colors.transparent,
|
||||||
|
highlightColor: themeController
|
||||||
|
.currentColor.sc5,
|
||||||
|
borderRadius: 6.rpx,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () async {
|
||||||
|
await bodyDeviceController
|
||||||
|
.getDeviceList(
|
||||||
|
key:
|
||||||
|
bodyDeviceController
|
||||||
|
.keyWord
|
||||||
|
.value);
|
||||||
|
bodyDeviceController
|
||||||
|
.updateAll();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'体征检测设备.搜索'.tr,
|
||||||
|
style: FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.normal_text_fontSize,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 14.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
final isEmpty =
|
||||||
|
bodyDeviceController.deviceList.value.isEmpty;
|
||||||
|
|
||||||
|
return isEmpty
|
||||||
|
? Expanded(
|
||||||
|
child: NullDataWidget(),
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 26.rpx, 30.rpx, 0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: bodyDeviceController
|
||||||
|
.deviceList.value
|
||||||
|
.map((device) =>
|
||||||
|
DeviceDataComponentWidget(
|
||||||
|
device: device))
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(height: 25.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDeviceCard(BuildContext context,
|
||||||
|
{required String title, required String imageUrl, required String type}) {
|
||||||
|
return CustomCard(
|
||||||
|
borderRadius: 20.rpx, // 圆角大小
|
||||||
|
onTap: () {
|
||||||
|
if (type != null) {
|
||||||
|
if (type == '1') {
|
||||||
|
Get.toNamed("/blueteethDevice");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: [themeController.currentColor.sc17], // 背景色
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.135,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 220.rpx,
|
||||||
|
),
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(77.rpx, 0, 21.rpx, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFC2CED7),
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
child: Image.asset(
|
||||||
|
imageUrl,
|
||||||
|
width: 212.rpx,
|
||||||
|
height: 168.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1293
lib/pages/device/component/DeviceDataComponentWidget.dart
Normal file
88
lib/pages/device/component/DeviceStatusInfoWidget.dart
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import 'package:ef/base/widget/flutterflow/FlutterFlowTheme.dart';
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
class DeviceStatusInfoWidget extends StatelessWidget {
|
||||||
|
final String title; // 标题,如“在床”
|
||||||
|
final String iconAsset; // SVG 路径,如 'assets/icons/bed.svg'
|
||||||
|
final String value; // 显示内容,如“在离床”
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
|
||||||
|
DeviceStatusInfoWidget({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.iconAsset,
|
||||||
|
required this.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ClickableContainer(
|
||||||
|
backgroundColor: themeController.currentColor.sc5,
|
||||||
|
highlightColor: themeController.currentColor.sc5,
|
||||||
|
borderRadius: AppConstants().normal_container_radius,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () {
|
||||||
|
print('点击了 $title 模块');
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.32,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 201.rpx,
|
||||||
|
minHeight: 182.rpx,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(20.rpx, 29.rpx, 20.rpx, 39.rpx),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
iconAsset,
|
||||||
|
width: 38.rpx,
|
||||||
|
height: 38.rpx,
|
||||||
|
// colorFilter: ColorFilter.mode(
|
||||||
|
// FlutterFlowTheme.of(context).primaryText,
|
||||||
|
// BlendMode.srcIn,
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 48.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.divide(SizedBox(width: 18.rpx))
|
||||||
|
.addToStart(SizedBox(width: 31.rpx)),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 39.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
477
lib/pages/device/device_detail.dart
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
|
||||||
|
class DeviceDetailPage extends StatefulWidget {
|
||||||
|
var device;
|
||||||
|
DeviceDetailPage({super.key, required this.device});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DeviceDetailPage> createState() => _DeviceDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeviceDetailPageState extends State<DeviceDetailPage> {
|
||||||
|
GlobalController globalController = Get.find();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
DeviceTypeController deviceTypeController = Get.find();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodySize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
|
||||||
|
fit: BoxFit.fill, // 填满整个 Container
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent, // 加上这一行
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
// backgroundColor: Colors.transparent,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
titleSpacing: 0.rpx,
|
||||||
|
// leading: returnIconButtom,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
/// 居中标题
|
||||||
|
Text(
|
||||||
|
'设备详情.标题'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// 左边返回按钮
|
||||||
|
Positioned(
|
||||||
|
left: 0.rpx,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 26.rpx, 30.rpx, 0.rpx),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc5,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
AppConstants().normal_container_radius),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
50.rpx, 0.rpx, 0.rpx, 0.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.267,
|
||||||
|
height: MediaQuery.sizeOf(context).width * 0.267,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 200.rpx,
|
||||||
|
minHeight: 200.rpx,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.设备名称'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.MAC'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.型号'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.版本'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.网络状态'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.故障状态'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.更新状态'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'设备详情.更新时间'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.divide(SizedBox(height: 34.rpx))
|
||||||
|
.addToStart(SizedBox(height: 92.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 97.rpx)),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.267,
|
||||||
|
height: MediaQuery.sizeOf(context).width * 0.267,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 200.rpx,
|
||||||
|
minHeight: 200.rpx,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: FlutterFlowTheme.of(context)
|
||||||
|
.secondaryBackground,
|
||||||
|
),
|
||||||
|
// child: ClipRRect(
|
||||||
|
// borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
// child: Image.network(
|
||||||
|
// 'https://picsum.photos/seed/851/600',
|
||||||
|
// width: 200.rpx,
|
||||||
|
// height: 200.rpx,
|
||||||
|
// fit: BoxFit.cover,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
child: QrImageView(
|
||||||
|
data: '1234567890',
|
||||||
|
version: QrVersions.auto,
|
||||||
|
size: 200.0.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'A35968956',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['person']['name'] ?? '未命名'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['mac'] ?? '-'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'-',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'-',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['status']['status'] == 1 ? '在线'.tr : '离线'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['status']['failure'] == 1 ? '有故障'.tr : '无故障'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['status']['upgrade'] == 1 ? '有更新'.tr : '无更新'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 50.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
|
||||||
|
child: Text(
|
||||||
|
'${widget.device['update_time'] ?? '-'.tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.rpx,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.divide(SizedBox(height: 34.rpx))
|
||||||
|
.addToStart(SizedBox(height: 92.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 97.rpx)),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 34.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
505
lib/pages/device/instant_body_page.dart
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
|
||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
import 'package:vbvs_app/model/WebSocketMessage.dart';
|
||||||
|
import 'package:vbvs_app/pages/device/component/DeviceStatusInfoWidget.dart';
|
||||||
|
|
||||||
|
class InstantBodyPage extends StatefulWidget {
|
||||||
|
var personInfo;
|
||||||
|
InstantBodyPage({super.key, required this.personInfo});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InstantBodyPage> createState() => _InstantBodyPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InstantBodyPageState extends State<InstantBodyPage> {
|
||||||
|
GlobalController globalController = Get.find();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
DeviceTypeController deviceTypeController = Get.find();
|
||||||
|
|
||||||
|
int maxBodyMotion = 1;
|
||||||
|
String breathState = "否";
|
||||||
|
String inBed = "离床".tr;
|
||||||
|
String onlineState = "离线".tr;
|
||||||
|
Timer? _onlineTimer; // 添加 Timer 引用
|
||||||
|
int bodyMotion = 0;
|
||||||
|
int breathrate = 0;
|
||||||
|
String snores = "否".tr;
|
||||||
|
int heartrate = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
|
||||||
|
path: "/vsbs/web/rt/marttress",
|
||||||
|
type: 1,
|
||||||
|
data: {"mac": widget.personInfo['mac']})));
|
||||||
|
_startOnlineTimer(); // 初始化时启动定时器
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_onlineTimer?.cancel(); // 取消定时器,防止内存泄漏
|
||||||
|
edm.EasyDartModule.websocket.sendData(
|
||||||
|
jsonEncode(WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2)));
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startOnlineTimer() {
|
||||||
|
_onlineTimer?.cancel(); // 取消之前的定时器
|
||||||
|
_onlineTimer = Timer.periodic(Duration(seconds: 30), (timer) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
onlineState = "离线".tr; // 30 秒内没有接收到数据,设置为离线
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Map device = widget.personInfo;
|
||||||
|
CommonVariables.callMap["/vsbs/web/rt/marttress"] = (data) {
|
||||||
|
inBed = data["inBed"];
|
||||||
|
// 心率 呼吸 体动 呼吸暂停
|
||||||
|
if ("离床" == inBed) {
|
||||||
|
breathState = "否";
|
||||||
|
data["breathRate"] = 0;
|
||||||
|
data["heartRate"] = 0;
|
||||||
|
data["bodyMotion"] = 0;
|
||||||
|
} else {
|
||||||
|
breathState = data["breathState"];
|
||||||
|
bodyMotion = data['bodyMotion'];
|
||||||
|
breathrate = data["breathRate"];
|
||||||
|
heartrate = data['heartRate'];
|
||||||
|
snores = data['snores'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
onlineState = "在线".tr; // 接收到数据,设置为在线
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_startOnlineTimer(); // 重置定时器
|
||||||
|
};
|
||||||
|
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodySize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/bgNoImg.png'),
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
titleSpacing: 0.rpx,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: '实时体征.标题'.tr,
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: "(${onlineState})",
|
||||||
|
style: TextStyle(
|
||||||
|
color: onlineState == '在线'
|
||||||
|
? themeController.currentColor.sc2
|
||||||
|
: themeController
|
||||||
|
.currentColor.sc9, // 👈 单独设置颜色
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0.rpx,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0.rpx, 29.rpx, 0.rpx, 0.rpx),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 0.rpx, 30.rpx, 120.rpx),
|
||||||
|
child: ClickableContainer(
|
||||||
|
backgroundColor: themeController.currentColor.sc5,
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc5, // 或你希望的点击水波纹颜色
|
||||||
|
borderRadius: AppConstants()
|
||||||
|
.normal_container_radius, // 如果你想加圆角可以设置 eg. 12.rpx
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onTap: () {
|
||||||
|
print('点击了体征卡片');
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'实时体征.姓名'.tr,
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'实时体征.年龄'.tr,
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 34.rpx)),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${device['person']['name'] ?? '未命名'.tr}',
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(device['person']['birthday'])) ?? '未知数据'.tr}',
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 34.rpx)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.divide(SizedBox(width: 33.rpx))
|
||||||
|
.addToStart(SizedBox(width: 37.rpx)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.addToStart(SizedBox(height: 36.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 36.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'实时体征.设备ID'.tr,
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'实时体征.体重'.tr,
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 34.rpx)),
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
// '${device['_id']??'未知数据'.tr}',
|
||||||
|
"D11250300003",
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${device['person']['weight'] ?? '未知数据'.tr}kg',
|
||||||
|
style:
|
||||||
|
FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 34.rpx)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.divide(SizedBox(width: 33.rpx))
|
||||||
|
.addToStart(SizedBox(width: 37.rpx)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.addToStart(SizedBox(height: 36.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 36.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
66.rpx, 0, 66.rpx, 0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage(
|
||||||
|
'assets/img/body_black.gif'), // 本地图片
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "在离床".tr,
|
||||||
|
iconAsset: "assets/img/icon/bed_status.svg",
|
||||||
|
value: inBed,
|
||||||
|
),
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "体动".tr,
|
||||||
|
iconAsset: "assets/img/icon/bodymotion.svg",
|
||||||
|
value: "${bodyMotion}" ?? "未知数据".tr,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "心率".tr,
|
||||||
|
iconAsset: "assets/img/icon/heart.svg",
|
||||||
|
value: "${heartrate}",
|
||||||
|
),
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "打鼾".tr,
|
||||||
|
iconAsset: "assets/img/icon/snore.svg",
|
||||||
|
value: '${snores}'.tr,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "呼吸".tr,
|
||||||
|
iconAsset: "assets/img/icon/breathe.svg",
|
||||||
|
value: '${breathrate}',
|
||||||
|
),
|
||||||
|
DeviceStatusInfoWidget(
|
||||||
|
title: "呼吸暂停".tr,
|
||||||
|
iconAsset:
|
||||||
|
"assets/img/icon/breathe_pause.svg",
|
||||||
|
value: '${breathState}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
].divide(SizedBox(height: 49.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0.rpx, 67.rpx, 0.rpx, 0.rpx),
|
||||||
|
child: Container(
|
||||||
|
height: 40.rpx,
|
||||||
|
child: Text(
|
||||||
|
bodyMotion >= maxBodyMotion ? '请保持静止'.tr : "",
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 207.rpx,
|
||||||
|
),
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent, // 可自定义背景色
|
||||||
|
highlightColor: Colors.white, // 点击涟漪颜色
|
||||||
|
borderRadius: 16.rpx, // 圆角大小,可按需调整
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 0.rpx, 30.rpx, 0.rpx),
|
||||||
|
onTap: () {},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
26.rpx, 26.rpx, 26.rpx, 26.rpx),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
// color: FlutterFlowTheme.of(context)
|
||||||
|
// .primaryBackground
|
||||||
|
// .withOpacity(0.6), // 半透明背景
|
||||||
|
borderRadius: BorderRadius.circular(16.rpx),
|
||||||
|
border: Border.all(
|
||||||
|
// 设置边框颜色和宽度
|
||||||
|
color: themeController.currentColor.sc4, // 边框颜色
|
||||||
|
width: 2.rpx, // 边框宽度
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 8.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 23.rpx,
|
||||||
|
height: 23.rpx,
|
||||||
|
// width: double.infinity,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/tips.svg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'实时体征.提示'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 23.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 26.rpx,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
255
lib/pages/device_bind/MobileScannerTestPage.dart
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:img_picker/img_picker.dart';
|
||||||
|
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
||||||
|
|
||||||
|
class MobileScannerTestPage extends StatefulWidget {
|
||||||
|
const MobileScannerTestPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MobileScannerTestPage> createState() => _MobileScannerTestPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MobileScannerTestPageState extends State<MobileScannerTestPage>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
String? scannedText;
|
||||||
|
bool isScanning = true;
|
||||||
|
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<double> _animation;
|
||||||
|
late MobileScannerController _scannerController;
|
||||||
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
|
||||||
|
final double scanAreaSize = 480.rpx;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scannerController = MobileScannerController();
|
||||||
|
_controller = AnimationController(
|
||||||
|
duration: const Duration(seconds: 2),
|
||||||
|
vsync: this,
|
||||||
|
)..repeat(reverse: true);
|
||||||
|
|
||||||
|
_animation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
|
||||||
|
parent: _controller,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
_scannerController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onDetect(BarcodeCapture capture) {
|
||||||
|
if (!isScanning) return;
|
||||||
|
|
||||||
|
final Barcode? barcode = capture.barcodes.first;
|
||||||
|
final String? value = barcode?.rawValue;
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
setState(() {
|
||||||
|
scannedText = value;
|
||||||
|
isScanning = false;
|
||||||
|
if (scannedText != null && scannedText!.isNotEmpty) {
|
||||||
|
blueteethBindController.scanMac.value = scannedText!;
|
||||||
|
showConfirmDialog(
|
||||||
|
context,
|
||||||
|
Container(),
|
||||||
|
'蓝牙绑定.确定绑定提示'.tr,
|
||||||
|
onConfirm: () async {
|
||||||
|
ApiResponse response =
|
||||||
|
await blueteethBindController.bindDeviceByScan(scannedText!);
|
||||||
|
if (response.code == HttpStatusCodes.ok) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "蓝牙绑定.连接成功".tr,
|
||||||
|
textColor: themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: response.msg ?? "蓝牙绑定.连接异常".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancel: () {
|
||||||
|
print('用户点击了取消');
|
||||||
|
// 执行取消后的处理逻辑
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
|
setState(() {
|
||||||
|
isScanning = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'扫一扫.标题'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
MobileScanner(
|
||||||
|
controller: _scannerController,
|
||||||
|
onDetect: _onDetect,
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topCenter, // 使扫描框位于顶部居中
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 219.rpx), // 向上移动扫描框
|
||||||
|
child: SizedBox(
|
||||||
|
width: scanAreaSize,
|
||||||
|
height: scanAreaSize,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AnimatedBuilder(
|
||||||
|
animation: _animation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Positioned(
|
||||||
|
top: scanAreaSize * _animation.value,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: Container(
|
||||||
|
height: 2,
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 31.rpx),
|
||||||
|
Text(
|
||||||
|
'扫一扫.提示'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0, 0, 0, 83.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () async {
|
||||||
|
final picker = ImagePicker();
|
||||||
|
final pickedFile =
|
||||||
|
await picker.pickImage(source: ImageSource.gallery);
|
||||||
|
if (pickedFile != null) {
|
||||||
|
final bytes = await pickedFile.readAsBytes();
|
||||||
|
final image = await decodeImageFromList(bytes);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.photo,
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
size: 60.rpx),
|
||||||
|
SizedBox(height: 10.rpx),
|
||||||
|
Text(
|
||||||
|
'扫一扫.相册'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
fontSize: 24.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 80.rpx),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
_scannerController.toggleTorch();
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.flashlight_on,
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
size: 60.rpx),
|
||||||
|
SizedBox(height: 10.rpx),
|
||||||
|
Text(
|
||||||
|
'扫一扫.手电筒'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController.currentColor.sc2,
|
||||||
|
fontSize: 24.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -200,7 +200,7 @@ class _EPageState extends State<BindDeviceSuccess> {
|
|||||||
'assets/img/icon/share.svg',
|
'assets/img/icon/share.svg',
|
||||||
width: 25.rpx,
|
width: 25.rpx,
|
||||||
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
||||||
color: themeController.currentColor.sc3,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'绑定成功.立即分享'.tr,
|
'绑定成功.立即分享'.tr,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
@@ -14,19 +13,17 @@ import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
|||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/model/BleDeviceData.dart';
|
import 'package:vbvs_app/model/BleDeviceData.dart';
|
||||||
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
|
||||||
import 'package:vbvs_app/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart';
|
import 'package:vbvs_app/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart';
|
||||||
import 'package:vbvs_app/common/util/Ble.dart' as ble;
|
|
||||||
|
|
||||||
class BlueteethDevicePage extends StatefulWidget {
|
class BlueteethDevicePage extends StatefulWidget {
|
||||||
int tid = -1;
|
int tid = -1;
|
||||||
BlueteethDevicePage({super.key, this.tid = -1});
|
BlueteethDevicePage({super.key, this.tid = -1});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BlueteethDevicePage> createState() => _EPageState();
|
State<BlueteethDevicePage> createState() => _BlueteethDevicePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EPageState extends State<BlueteethDevicePage> {
|
class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
|
||||||
GlobalController globalController = Get.find();
|
GlobalController globalController = Get.find();
|
||||||
UserInfoController userInfoController = Get.find();
|
UserInfoController userInfoController = Get.find();
|
||||||
BlueteethBindController blueteethBindController = Get.find();
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
@@ -49,6 +46,8 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
blueteethBindController.model.devicelist = [];
|
||||||
|
blueteethBindController.model.betDevicelist = [];
|
||||||
flutterBlue = FlutterBluePlus(); // 初始化flutterBlue实例
|
flutterBlue = FlutterBluePlus(); // 初始化flutterBlue实例
|
||||||
_checkBluetoothPermission(); // 检查蓝牙权限
|
_checkBluetoothPermission(); // 检查蓝牙权限
|
||||||
Get.find<BlueteethBindController>().startStatusPolling();
|
Get.find<BlueteethBindController>().startStatusPolling();
|
||||||
@@ -114,6 +113,7 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
|
|
||||||
// 开始扫描蓝牙设备
|
// 开始扫描蓝牙设备
|
||||||
void _startScanning() async {
|
void _startScanning() async {
|
||||||
|
if (!mounted) return;
|
||||||
var bluetoothState = await FlutterBluePlus.isOn;
|
var bluetoothState = await FlutterBluePlus.isOn;
|
||||||
if (!bluetoothState && !_isDialogShowing) {
|
if (!bluetoothState && !_isDialogShowing) {
|
||||||
_isDialogShowing = true;
|
_isDialogShowing = true;
|
||||||
@@ -128,8 +128,9 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await FlutterBluePlus.startScan(timeout: Duration(seconds: 10));
|
await FlutterBluePlus.startScan(timeout: Duration(seconds: 10));
|
||||||
|
// await FlutterBluePlus.startScan(timeout: Duration(minutes: 30));
|
||||||
|
|
||||||
FlutterBluePlus.scanResults.listen((results) {
|
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
|
||||||
final signalThreshold = blueteethBindController.model.singal!;
|
final signalThreshold = blueteethBindController.model.singal!;
|
||||||
final filteredResults = results
|
final filteredResults = results
|
||||||
.where((r) =>
|
.where((r) =>
|
||||||
@@ -149,6 +150,9 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
deviceData.rssi = r.rssi;
|
deviceData.rssi = r.rssi;
|
||||||
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
|
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
|
||||||
parsedDeviceList.add(deviceData);
|
parsedDeviceList.add(deviceData);
|
||||||
|
if (deviceData.mac!.toLowerCase() == 'b43a45c3dfa0') {
|
||||||
|
print('匹配设备数据: ${deviceData.mac}-->sn:${deviceData.sn}');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("设备数据解析失败: $e");
|
print("设备数据解析失败: $e");
|
||||||
}
|
}
|
||||||
@@ -188,13 +192,15 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
|
|
||||||
// 等待扫描完成
|
// 等待扫描完成
|
||||||
await Future.delayed(Duration(seconds: 10));
|
await Future.delayed(Duration(seconds: 10));
|
||||||
|
// await Future.delayed(Duration(minutes: 30));
|
||||||
await FlutterBluePlus.stopScan();
|
await FlutterBluePlus.stopScan();
|
||||||
|
|
||||||
setState(() {
|
if (mounted) {
|
||||||
isScanning = false;
|
setState(() {
|
||||||
});
|
isScanning = false;
|
||||||
|
});
|
||||||
print("扫描完成");
|
}
|
||||||
|
// print("扫描完成");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,10 +216,13 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
// 停止扫描
|
// 停止扫描
|
||||||
void _stopScanning() {
|
void _stopScanning() {
|
||||||
if (isScanning) {
|
if (isScanning) {
|
||||||
FlutterBluePlus.stopScan(); // 停止扫描
|
FlutterBluePlus.stopScan();
|
||||||
setState(() {
|
_scanSubscription?.cancel(); // 取消订阅
|
||||||
isScanning = false; // 更新扫描状态
|
if (mounted) {
|
||||||
});
|
setState(() {
|
||||||
|
isScanning = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,396 +231,15 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StreamSubscription<List<ScanResult>>? _scanSubscription; // 添加扫描订阅变量
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
|
||||||
_stopPeriodicScan(); // 停止定时扫描
|
_stopPeriodicScan(); // 停止定时扫描
|
||||||
_stopScanning(); // 确保离开页面时停止扫描
|
_stopScanning(); // 停止扫描
|
||||||
}
|
_scanSubscription?.cancel(); // 取消扫描订阅
|
||||||
|
connectTimer?.cancel(); // 取消连接定时器
|
||||||
connectToDevice(device, {int time = 5}) {
|
blueteethBindController.stopStatusPolling(); // 停止状态轮询
|
||||||
ble.connectToDevice(
|
super.dispose();
|
||||||
{
|
|
||||||
"device": device,
|
|
||||||
'success': (ble.ConnectedDeviceProp deviceProp) {
|
|
||||||
if (deviceProp.connectedDevicePropType ==
|
|
||||||
ble.ConnectedDevicePropType.JunHe) {
|
|
||||||
currentConnectedDeviceProp = deviceProp;
|
|
||||||
deviceProp.write3OfString("blog enable");
|
|
||||||
deviceProp.write3OfString("blog rlmax=128");
|
|
||||||
Timer(const Duration(microseconds: 100), () async {
|
|
||||||
String log = "";
|
|
||||||
Function logAdd = (l) {
|
|
||||||
log += l;
|
|
||||||
};
|
|
||||||
deviceProp.receiveLogArr.add(logAdd);
|
|
||||||
deviceProp.encodeType = 1;
|
|
||||||
deviceProp.deviceType = 1;
|
|
||||||
Timer.periodic(const Duration(milliseconds: 300), (timer) async {
|
|
||||||
if (timer.tick > 20) {
|
|
||||||
ble.disconnect(currentConnectedDeviceProp);
|
|
||||||
failSelectDialog();
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
if (log.contains("GB2312") || log.contains("UTF-8")) {
|
|
||||||
timer.cancel();
|
|
||||||
if (log.contains('CHARSET:UTF-8')) {
|
|
||||||
deviceProp.encodeType = 2;
|
|
||||||
}
|
|
||||||
if (log.contains('TARGET:ESPXX')) {
|
|
||||||
deviceProp.deviceType = 2;
|
|
||||||
}
|
|
||||||
log = "";
|
|
||||||
bool isSuccess = false;
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
deviceProp.write3OfString("at+system info");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 400));
|
|
||||||
RegExp regExp = RegExp(r"Target Mac:(\S*)");
|
|
||||||
RegExpMatch? regExpMatch = regExp.firstMatch(log);
|
|
||||||
if (regExpMatch != null && regExpMatch.group(1) != null) {
|
|
||||||
String? mac = regExpMatch.group(1);
|
|
||||||
if (mac?.length == 12 && mac != "000000000000") {
|
|
||||||
bindArr[2] = "$mac".toUpperCase();
|
|
||||||
}
|
|
||||||
isSuccess = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deviceProp.receiveLogArr.remove(logAdd);
|
|
||||||
print("$bindArr");
|
|
||||||
RegExp regExp = RegExp(
|
|
||||||
r"WIFI CONNECTED INFO:SSID=([^\t\n]*)\s*,RSSI=(\S*)\s*,");
|
|
||||||
RegExpMatch? regExpMatch = regExp.firstMatch(log);
|
|
||||||
if (regExpMatch != null && log.contains("Status=connect")) {
|
|
||||||
blueteethBindController.model.connectedWifiName =
|
|
||||||
regExpMatch.group(1) ?? "";
|
|
||||||
if (int.tryParse("${regExpMatch.group(2)}") != null) {
|
|
||||||
blueteethBindController.model.connectedRssi =
|
|
||||||
int.parse("${regExpMatch.group(2)}");
|
|
||||||
}
|
|
||||||
blueteethBindController.updateAll();
|
|
||||||
}
|
|
||||||
ble.bleParse();
|
|
||||||
if (bindArr[0] != null &&
|
|
||||||
bindArr[0] != "" &&
|
|
||||||
bindArr[1] != "") {
|
|
||||||
setState(() {
|
|
||||||
currentMsg = "绑定中...";
|
|
||||||
});
|
|
||||||
blueteethBindController.bindDevice({
|
|
||||||
"tid": widget.tid,
|
|
||||||
"name": blueteethBindController.model.deviceName,
|
|
||||||
"mac": bindArr[0],
|
|
||||||
"macA": bindArr[1],
|
|
||||||
"macB": bindArr[2]
|
|
||||||
}).then((d) {
|
|
||||||
blueteethBindController.model.bindArr = bindArr;
|
|
||||||
globalController.getDeviceList();
|
|
||||||
LoadingDialog.hide();
|
|
||||||
showCustomConfirmDialog(context, "设备添加成功!",
|
|
||||||
btnName: "打开WIFI配置",
|
|
||||||
icon: ConfirmDialogIcon.success)
|
|
||||||
.then((d) {
|
|
||||||
if (d == "confirm") {
|
|
||||||
Get.offAndToNamed("/wifi", arguments: deviceProp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).catchError((d) {
|
|
||||||
print("$d");
|
|
||||||
currentMsg = "绑定失败: ${d.message}";
|
|
||||||
ble.disconnect(currentConnectedDeviceProp);
|
|
||||||
failSelectDialog(title: "${d.message}");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
LoadingDialog.hide();
|
|
||||||
Get.offAndToNamed("/wifi", arguments: deviceProp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deviceProp.read6();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else if (deviceProp.connectedDevicePropType ==
|
|
||||||
ble.ConnectedDevicePropType.QuanShi) {
|
|
||||||
List receive = [];
|
|
||||||
Function fun = (d) {
|
|
||||||
receive.add(d);
|
|
||||||
};
|
|
||||||
deviceProp.receiveLogArr.add(fun);
|
|
||||||
List<int> head = [
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
12,
|
|
||||||
17,
|
|
||||||
];
|
|
||||||
Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
||||||
if (timer.tick > 20) {
|
|
||||||
timer.cancel();
|
|
||||||
currentMsg = "错误:未能获取到MAC";
|
|
||||||
failSelectDialog();
|
|
||||||
}
|
|
||||||
deviceProp.write(
|
|
||||||
Uint8List.fromList([
|
|
||||||
0xFF,
|
|
||||||
0xFF,
|
|
||||||
0xFF,
|
|
||||||
0xFF,
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
0x0C,
|
|
||||||
0x0B,
|
|
||||||
0x0F,
|
|
||||||
0x23,
|
|
||||||
0x04
|
|
||||||
]),
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
if (receive.length > 0) {
|
|
||||||
receive.forEach((data) {
|
|
||||||
if (data.length != 17) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool r = true;
|
|
||||||
for (var i = 0; i < head.length; i++) {
|
|
||||||
if (head[i] != data[i]) {
|
|
||||||
r = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bindArr[1] = ble.ab2str(data.sublist(9, 15)).toUpperCase();
|
|
||||||
timer.cancel();
|
|
||||||
deviceProp.receiveLogArr.remove(fun);
|
|
||||||
blueteethBindController.model.deviceName =
|
|
||||||
deviceProp.connectDevice?.advName;
|
|
||||||
ble.disconnect(deviceProp);
|
|
||||||
toFindJunhe();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
List receive = [];
|
|
||||||
Function fun = (d) {
|
|
||||||
receive.add(d);
|
|
||||||
};
|
|
||||||
deviceProp.receiveLogArr.add(fun);
|
|
||||||
List<int> head = [255, 255, 255, 255, 0x00, 0x08, 0x40, 0x01];
|
|
||||||
Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
||||||
if (timer.tick > 20) {
|
|
||||||
timer.cancel();
|
|
||||||
currentMsg = "错误:未能获取到MAC";
|
|
||||||
failSelectDialog();
|
|
||||||
}
|
|
||||||
deviceProp.write(
|
|
||||||
Uint8List.fromList([
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
255,
|
|
||||||
0x00,
|
|
||||||
0x03,
|
|
||||||
0x40,
|
|
||||||
0x01,
|
|
||||||
0x01,
|
|
||||||
0x00,
|
|
||||||
0x45,
|
|
||||||
0xfd
|
|
||||||
]),
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
if (receive.length > 0) {
|
|
||||||
receive.forEach((data) {
|
|
||||||
if (data.length != 17) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool r = true;
|
|
||||||
for (var i = 0; i < head.length; i++) {
|
|
||||||
if (head[i] != data[i]) {
|
|
||||||
r = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bindArr[1] = ble.ab2str(data.sublist(8, 14)).toUpperCase();
|
|
||||||
print("$bindArr");
|
|
||||||
timer.cancel();
|
|
||||||
deviceProp.receiveLogArr.remove(fun);
|
|
||||||
blueteethBindController.model.deviceName =
|
|
||||||
deviceProp.connectDevice?.advName;
|
|
||||||
ble.disconnect(deviceProp);
|
|
||||||
toFindJunhe();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'fail': (e) {
|
|
||||||
print(e);
|
|
||||||
if (time > 0) {
|
|
||||||
connectToDevice(device, time: time - 1);
|
|
||||||
} else {
|
|
||||||
currentMsg = "蓝牙无法连接上设备";
|
|
||||||
failSelectDialog(title: currentMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
isBind() {
|
|
||||||
return !(blueteethBindController.model.bindArr[1]?.length == 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
failSelectDialog({String title = ""}) {
|
|
||||||
LoadingDialog.hide();
|
|
||||||
setState(() {});
|
|
||||||
showCustomConfirmAndCancelDialog(
|
|
||||||
context, title == "" ? (isBind() ? "绑定失败" : "连接失败") : title,
|
|
||||||
confirmName: "重试", cancelName: "返回")
|
|
||||||
.then((d) {
|
|
||||||
if (d == "confirm") {
|
|
||||||
if (connectDeviceCurrent != null) {
|
|
||||||
ble.bleParse();
|
|
||||||
ble.start((List d) {
|
|
||||||
setState(() {
|
|
||||||
bleDevice = d;
|
|
||||||
});
|
|
||||||
}, bleOnCall: () {
|
|
||||||
LoadingDialog.show("连接中...\n靠近设备2米内",
|
|
||||||
icon:
|
|
||||||
isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
|
|
||||||
setState(() {
|
|
||||||
currentMsg = "连接设备中...";
|
|
||||||
});
|
|
||||||
connectToDevice(connectDeviceCurrent);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
bleExec();
|
|
||||||
}
|
|
||||||
} else if (d == "cancel") {
|
|
||||||
Get.back();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bleExec() {
|
|
||||||
ble.bleParse();
|
|
||||||
connectTimer?.cancel();
|
|
||||||
int index = 0;
|
|
||||||
bool isCloseLoadingDialog = false;
|
|
||||||
isFind = false;
|
|
||||||
blueteethBindController.model.bindArr = bindArrBackup;
|
|
||||||
bindArr = ["", "", ""];
|
|
||||||
ble.start((List d) {
|
|
||||||
setState(() {
|
|
||||||
bleDevice = d;
|
|
||||||
});
|
|
||||||
if (isBind()) {
|
|
||||||
if (isCloseLoadingDialog == false &&
|
|
||||||
bleDevice.indexWhere((item) {
|
|
||||||
if (widget.tid == 1) {
|
|
||||||
return ble.isQuanShiDevice(item["name"]);
|
|
||||||
} else {
|
|
||||||
return ble.isMHTSWES(item["name"]);
|
|
||||||
}
|
|
||||||
}) !=
|
|
||||||
-1) {
|
|
||||||
isCloseLoadingDialog = true;
|
|
||||||
LoadingDialog.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, bleOnCall: () {
|
|
||||||
if (isBind()) {
|
|
||||||
LoadingDialog.show("搜索蓝牙设备中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内",
|
|
||||||
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
|
|
||||||
Timer.periodic(const Duration(seconds: 1), (t) {
|
|
||||||
if (t.tick > 15) {
|
|
||||||
t.cancel();
|
|
||||||
isCloseLoadingDialog = true;
|
|
||||||
LoadingDialog.hide();
|
|
||||||
showCustomConfirmAndCancelDialog(context, "未发现设备",
|
|
||||||
confirmName: "重试", cancelName: "返回")
|
|
||||||
.then((d) {
|
|
||||||
if (d == "confirm") {
|
|
||||||
bleExec();
|
|
||||||
} else if (d == "cancel") {
|
|
||||||
Get.back();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (isCloseLoadingDialog == true) {
|
|
||||||
t.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LoadingDialog.show(
|
|
||||||
"${isBind() ? "绑定中...\n与设备距离在2米内" : "连接中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内"}",
|
|
||||||
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
|
|
||||||
connectTimer = Timer.periodic(const Duration(seconds: 1), (t) {
|
|
||||||
index++;
|
|
||||||
if (index > 15) {
|
|
||||||
connectTimer = null;
|
|
||||||
t.cancel();
|
|
||||||
failSelectDialog();
|
|
||||||
}
|
|
||||||
var d = bleDevice;
|
|
||||||
if (d != null && d.length > 0) {
|
|
||||||
if (isBind()) {
|
|
||||||
var deviceble = d.firstWhere((item) {
|
|
||||||
bool isFF = false;
|
|
||||||
if (widget.tid == 1) {
|
|
||||||
isFF = ble.isQuanShiDevice(item["name"]);
|
|
||||||
} else {
|
|
||||||
isFF = ble.isMHTSWES(item["name"]);
|
|
||||||
}
|
|
||||||
if (isFF) {
|
|
||||||
isFF = globalController.model.deviceList.indexWhere(
|
|
||||||
(d) => d["mac"] == item["adData"]["deviceId"]) ==
|
|
||||||
-1
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
}
|
|
||||||
return isFF;
|
|
||||||
}, orElse: () => null);
|
|
||||||
if (!isFind && deviceble != null) {
|
|
||||||
print("quanshidevice");
|
|
||||||
isFind = true;
|
|
||||||
setState(() {
|
|
||||||
currentMsg = "连接设备中...";
|
|
||||||
});
|
|
||||||
t.cancel();
|
|
||||||
connectToDevice(deviceble["device"]);
|
|
||||||
bindArr[0] = deviceble["adData"]["deviceId"];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var deviceble = d.firstWhere(
|
|
||||||
(item) =>
|
|
||||||
item["adData"]["deviceId"] ==
|
|
||||||
blueteethBindController.model.bindArr[1],
|
|
||||||
orElse: () => null);
|
|
||||||
if (!isFind && deviceble != null) {
|
|
||||||
print("junhedevice");
|
|
||||||
isFind = true;
|
|
||||||
t.cancel();
|
|
||||||
setState(() {
|
|
||||||
currentMsg = "连接设备中...";
|
|
||||||
});
|
|
||||||
connectToDevice(deviceble["device"]);
|
|
||||||
bindArr[1] = deviceble["adData"]["deviceId"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -679,7 +307,7 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
0, 30.rpx, 0, 30.rpx),
|
0, 30.rpx, 0, 30.rpx),
|
||||||
child: Text(
|
child: Text(
|
||||||
'蓝牙绑定.扫描蓝牙设备中…'.tr,
|
'蓝牙绑定.扫描'.tr,
|
||||||
style: FlutterFlowTheme.of(context)
|
style: FlutterFlowTheme.of(context)
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
.override(
|
.override(
|
||||||
@@ -917,42 +545,48 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding:
|
||||||
EdgeInsetsDirectional.fromSTEB(19.rpx, 0, 0, 0),
|
EdgeInsetsDirectional.fromSTEB(19.rpx, 0, 0, 0),
|
||||||
child: Text(
|
child: Obx(() {
|
||||||
'匹配出的外围设备(${blueteethBindController.model.devicelist!.length})',
|
return Text(
|
||||||
style: FlutterFlowTheme.of(context)
|
'匹配出的外围设备(${blueteethBindController.model.betDevicelist!.length})',
|
||||||
.bodyMedium
|
style: FlutterFlowTheme.of(context)
|
||||||
.override(
|
.bodyMedium
|
||||||
fontFamily: 'Inter',
|
.override(
|
||||||
fontSize: 30.rpx,
|
fontFamily: 'Inter',
|
||||||
letterSpacing: 0.0,
|
fontSize: 30.rpx,
|
||||||
color: themeController.currentColor.sc3,
|
letterSpacing: 0.0,
|
||||||
),
|
color: themeController.currentColor.sc3,
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return Expanded(
|
if (blueteethBindController
|
||||||
child: Container(
|
.model.betDevicelist!.isNotEmpty) {
|
||||||
width: double.infinity,
|
return Expanded(
|
||||||
child: SingleChildScrollView(
|
child: Container(
|
||||||
child: Column(
|
width: double.infinity,
|
||||||
mainAxisSize: MainAxisSize.max,
|
child: SingleChildScrollView(
|
||||||
children: [
|
child: Column(
|
||||||
...blueteethBindController.model.blelist!
|
mainAxisSize: MainAxisSize.max,
|
||||||
.map((device) =>
|
children: [
|
||||||
SingleBlueteethDeviceCompoentWidget(
|
...blueteethBindController.model.blelist!
|
||||||
// device: device,
|
.map((device) =>
|
||||||
bleDevice: device,
|
SingleBlueteethDeviceCompoentWidget(
|
||||||
))
|
// device: device,
|
||||||
.toList()
|
bleDevice: device,
|
||||||
.divide(SizedBox(height: 30.rpx))
|
))
|
||||||
.addToEnd(SizedBox(height: 30.rpx)),
|
.toList()
|
||||||
],
|
.divide(SizedBox(height: 30.rpx))
|
||||||
|
.addToEnd(SizedBox(height: 30.rpx)),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
|
return Container();
|
||||||
}),
|
}),
|
||||||
].divide(SizedBox(height: 30.rpx)),
|
].divide(SizedBox(height: 30.rpx)),
|
||||||
),
|
),
|
||||||
@@ -979,38 +613,6 @@ class _EPageState extends State<BlueteethDevicePage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toFindJunhe() {
|
|
||||||
bool isSuccess = false;
|
|
||||||
int i = 0;
|
|
||||||
Timer.periodic(const Duration(seconds: 1), (t) async {
|
|
||||||
i++;
|
|
||||||
if (isSuccess) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (i > 8) {
|
|
||||||
if (!isSuccess) {
|
|
||||||
currentMsg = "错误:未找到关联设备";
|
|
||||||
failSelectDialog(title: "绑定失败:未找到关联设备");
|
|
||||||
}
|
|
||||||
t.cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bleDevice.forEach((item) {
|
|
||||||
if (isSuccess) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (item['adData']['deviceId'] == bindArr[1]) {
|
|
||||||
isSuccess = true;
|
|
||||||
t.cancel();
|
|
||||||
setState(() {
|
|
||||||
currentMsg = "寻找关联设备中...";
|
|
||||||
});
|
|
||||||
connectToDevice(item["device"]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BleDeviceData parseBleData(List<int> data) {
|
BleDeviceData parseBleData(List<int> data) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class _FancyCircleCheckboxState extends State<FancyCircleCheckbox>
|
|||||||
child: ScaleTransition(
|
child: ScaleTransition(
|
||||||
scale: _scaleAnimation,
|
scale: _scaleAnimation,
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.all(8.rpx),
|
margin: EdgeInsets.all(6.rpx),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: widget.fillColor,
|
color: widget.fillColor,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
|
|||||||
deviceData.rssi = widget.bleDevice.rssi;
|
deviceData.rssi = widget.bleDevice.rssi;
|
||||||
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
|
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
|
||||||
BleDeviceData device = deviceData;
|
BleDeviceData device = deviceData;
|
||||||
device = blueteethBindController.model.devicelist!.firstWhere(
|
device = blueteethBindController.model.betDevicelist!.firstWhere(
|
||||||
(d) => d.mac == device.mac,
|
(d) => d.mac == device.mac,
|
||||||
orElse: () => device,
|
orElse: () => device,
|
||||||
);
|
);
|
||||||
@@ -64,15 +64,12 @@ class _SingleBlueteethDeviceCompoentWidgetState
|
|||||||
onConfirm: () async {
|
onConfirm: () async {
|
||||||
ApiResponse response =
|
ApiResponse response =
|
||||||
await blueteethBindController.bindDeviceAndMAC(device);
|
await blueteethBindController.bindDeviceAndMAC(device);
|
||||||
|
TopSlideNotification.show(context, text: response.msg!);
|
||||||
if (response.code == HttpStatusCodes.ok) {
|
if (response.code == HttpStatusCodes.ok) {
|
||||||
showLoadingDialog(context); // 显示 loading
|
showLoadingDialog(context); // 显示 loading
|
||||||
BLEDevice bledevice =
|
THapp bledevice = THapp(device: widget.bleDevice.device);
|
||||||
BLEDevice(device: widget.bleDevice.device);
|
|
||||||
var res1 = bledevice.isConnected;
|
|
||||||
print("res1: $res1");
|
|
||||||
await bledevice.device.connect();
|
await bledevice.device.connect();
|
||||||
var res2 = bledevice.isConnected;
|
var res2 = bledevice.isConnected;
|
||||||
print("res2: $res2");
|
|
||||||
if (res2) {
|
if (res2) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
TopSlideNotification.show(
|
TopSlideNotification.show(
|
||||||
@@ -94,7 +91,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
|
|||||||
} else {
|
} else {
|
||||||
TopSlideNotification.show(
|
TopSlideNotification.show(
|
||||||
context,
|
context,
|
||||||
text: "蓝牙绑定.连接异常".tr,
|
text: response.msg ?? "蓝牙绑定.连接异常".tr,
|
||||||
textColor: themeController.currentColor.sc9,
|
textColor: themeController.currentColor.sc9,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -104,6 +101,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
|
|||||||
// 执行取消后的处理逻辑
|
// 执行取消后的处理逻辑
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
import 'package:loading_indicator/loading_indicator.dart';
|
import 'package:loading_indicator/loading_indicator.dart';
|
||||||
import 'package:vbvs_app/common/color/appConstants.dart';
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
import 'package:vbvs_app/component/tool/FrostedDialog.dart';
|
import 'package:vbvs_app/component/tool/FrostedDialog.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/model/BleDeviceData.dart';
|
import 'package:vbvs_app/model/BleDeviceData.dart';
|
||||||
@@ -248,7 +251,7 @@ void showHaveBindDialog(BuildContext context) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showLoadingDialog(BuildContext context) {
|
void showLoadingDialog(BuildContext context, {String? title}) {
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -310,7 +313,7 @@ void showLoadingDialog(BuildContext context) {
|
|||||||
child: RichText(
|
child: RichText(
|
||||||
text: TextSpan(children: [
|
text: TextSpan(children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: "连接中...".tr,
|
text: title ?? "连接中...".tr,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: themeController.currentColor.sc3,
|
color: themeController.currentColor.sc3,
|
||||||
fontSize: AppConstants().normal_text_fontSize,
|
fontSize: AppConstants().normal_text_fontSize,
|
||||||
@@ -433,6 +436,30 @@ void showConfirmDialog(
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
// 标题
|
// 标题
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent, // 容器背景色
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc21, // 点击时的背景色
|
||||||
|
padding: EdgeInsets.zero, // 这里去掉外部的 padding,避免影响点击范围
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 33.rpx, 0, 0.rpx),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/close.svg',
|
||||||
|
width: 25.rpx,
|
||||||
|
height: 25.rpx, // 如果 SVG 中没有固定颜色,使用 color 设置
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: AlignmentDirectional(0, 0),
|
alignment: AlignmentDirectional(0, 0),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -457,9 +484,10 @@ void showConfirmDialog(
|
|||||||
children: [
|
children: [
|
||||||
CustomCard(
|
CustomCard(
|
||||||
borderRadius: AppConstants().button_container_radius,
|
borderRadius: AppConstants().button_container_radius,
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
Get.back();
|
|
||||||
onConfirm();
|
onConfirm();
|
||||||
|
// await Future.delayed(Duration(milliseconds: 300));
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
colors: [
|
colors: [
|
||||||
themeController.currentColor.sc1,
|
themeController.currentColor.sc1,
|
||||||
@@ -542,3 +570,141 @@ void showConfirmDialog(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showWifiDialog(
|
||||||
|
BuildContext context,
|
||||||
|
Widget widget,
|
||||||
|
String title, {
|
||||||
|
required VoidCallback onConfirm,
|
||||||
|
}) {
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: true,
|
||||||
|
barrierColor: Colors.black.withOpacity(0.5), // 背景模糊色
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return FrostedDialog(
|
||||||
|
blurSigma: 3.0,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: themeController.currentColor.sc17,
|
||||||
|
borderRadius: BorderRadius.circular(20.0),
|
||||||
|
),
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 64.rpx, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxHeight: MediaQuery.sizeOf(context).height * 0.656,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent, // 容器背景色
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc21, // 点击时的背景色
|
||||||
|
padding: EdgeInsets.zero, // 这里去掉外部的 padding,避免影响点击范围
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 33.rpx, 0, 0.rpx),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/close.svg',
|
||||||
|
width: 25.rpx,
|
||||||
|
height: 25.rpx, // 如果 SVG 中没有固定颜色,使用 color 设置
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0.rpx, 40.rpx, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
widget,
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 60.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
CustomCard(
|
||||||
|
borderRadius: AppConstants().button_container_radius,
|
||||||
|
onTap: () {
|
||||||
|
if (blueteethBindController.model.wifiPass == null ||
|
||||||
|
blueteethBindController.model.wifiPass!.isEmpty) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "wifi页.密码为空".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Get.back();
|
||||||
|
onConfirm();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: [
|
||||||
|
themeController.currentColor.sc1,
|
||||||
|
themeController.currentColor.sc2,
|
||||||
|
],
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.115,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.055,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 160.rpx,
|
||||||
|
minHeight: 90.rpx,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"蓝牙绑定.连接".tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize:
|
||||||
|
AppConstants().normal_text_fontSize,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 17.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(
|
||||||
|
width: 70.rpx,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
421
lib/pages/device_bind/device_share_page.dart
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
||||||
|
import 'package:vbvs_app/model/api_response.dart';
|
||||||
|
import 'package:vbvs_app/pages/device_bind/componnet/FancyCircleCheckbox.dart';
|
||||||
|
|
||||||
|
class DeviceSharePage extends StatefulWidget {
|
||||||
|
var device;
|
||||||
|
DeviceSharePage({super.key, required this.device});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DeviceSharePage> createState() => _DeviceSharePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeviceSharePageState extends State<DeviceSharePage> {
|
||||||
|
DeviceShareController deviceShareController = Get.find();
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
deviceShareController.msg = "".obs;
|
||||||
|
deviceShareController.code = 0.obs;
|
||||||
|
deviceShareController.account = "".obs;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var device = widget.device;
|
||||||
|
RxBool flag1 = true.obs;
|
||||||
|
RxBool flag2 = false.obs;
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodySize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/bgNoImg.png'),
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'设备分享'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(47.rpx, 0, 47.rpx, 0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 28.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Text(
|
||||||
|
'要分享的设备'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 62.rpx, 0, 62.rpx),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Obx(() => FancyCircleCheckbox(
|
||||||
|
borderColor:
|
||||||
|
themeController.currentColor.sc3,
|
||||||
|
fillColor:
|
||||||
|
themeController.currentColor.sc2,
|
||||||
|
value: flag1.value,
|
||||||
|
onChanged: (value) {
|
||||||
|
flag1.value = !flag1.value;
|
||||||
|
deviceShareController.updateAll();
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Text(
|
||||||
|
'主设备'.tr +
|
||||||
|
"${device['person']?['name'] == null ? '未命名'.tr : device['person']['name']}",
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color:
|
||||||
|
themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 20.rpx)),
|
||||||
|
),
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
// children: [
|
||||||
|
// Obx(() => FancyCircleCheckbox(
|
||||||
|
// borderColor:
|
||||||
|
// themeController.currentColor.sc3,
|
||||||
|
// fillColor:
|
||||||
|
// themeController.currentColor.sc2,
|
||||||
|
// value: true,
|
||||||
|
// onChanged: (value) {},
|
||||||
|
// )),
|
||||||
|
// Text(
|
||||||
|
// '主设备:蓝盈盈(A9876451)',
|
||||||
|
// style: FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 26.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color:
|
||||||
|
// themeController.currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ].divide(SizedBox(width: 20.rpx)),
|
||||||
|
// ),
|
||||||
|
].divide(SizedBox(height: 64.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.66,
|
||||||
|
height: 100.rpx,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(50.rpx),
|
||||||
|
border: Border.all(
|
||||||
|
color: Color(0xFFF3EDED),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: TextFormField(
|
||||||
|
// controller: _model.textController1,
|
||||||
|
// focusNode: _model.textFieldFocusNode1,
|
||||||
|
initialValue: deviceShareController.account.value,
|
||||||
|
onChanged: (Value) {
|
||||||
|
deviceShareController.account.value = Value;
|
||||||
|
},
|
||||||
|
autofocus: false,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
fillColor: Colors.transparent,
|
||||||
|
isDense: true,
|
||||||
|
labelStyle: FlutterFlowTheme.of(context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
hintText: '请输入对方手机号或邮箱'.tr,
|
||||||
|
hintStyle: FlutterFlowTheme.of(context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: FlutterFlowTheme.of(context).error,
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: FlutterFlowTheme.of(context).error,
|
||||||
|
width: 1.rpx,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
),
|
||||||
|
filled: true,
|
||||||
|
),
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
cursorColor:
|
||||||
|
FlutterFlowTheme.of(context).primaryText,
|
||||||
|
// validator: _model.textController1Validator
|
||||||
|
// .asValidator(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
return Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 15.rpx, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 30.rpx,
|
||||||
|
),
|
||||||
|
child: deviceShareController.code != 0
|
||||||
|
? Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: RichText(
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
'${deviceShareController.code == 1 ? "邀请成功".tr : "邀请失败".tr}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: deviceShareController
|
||||||
|
.code ==
|
||||||
|
1
|
||||||
|
? themeController
|
||||||
|
.currentColor.sc2
|
||||||
|
: themeController
|
||||||
|
.currentColor.sc9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
'${deviceShareController.msg}',
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc9,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 0),
|
||||||
|
child: CustomCard(
|
||||||
|
borderRadius:
|
||||||
|
AppConstants().button_container_radius, // 圆角半径
|
||||||
|
onTap: () async {
|
||||||
|
ApiResponse apiResponse =
|
||||||
|
await deviceShareController
|
||||||
|
.shareDevice(device['mac']);
|
||||||
|
if (apiResponse.code == HttpStatusCodes.ok) {
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: apiResponse.msg!);
|
||||||
|
} else {
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: apiResponse.msg!,
|
||||||
|
textColor: themeController.currentColor.sc9);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: [
|
||||||
|
// 渐变色
|
||||||
|
themeController.currentColor.sc1,
|
||||||
|
themeController.currentColor.sc2,
|
||||||
|
],
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.214,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.037,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 160.rpx,
|
||||||
|
minHeight: 60.rpx,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'发送邀请'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.normal_text_fontSize, // 自定义字体大小
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 17.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 379.rpx, 0, 0),
|
||||||
|
child: CustomCard(
|
||||||
|
borderRadius:
|
||||||
|
AppConstants().button_container_radius, // 圆角半径
|
||||||
|
onTap: () {
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: "待开发功能".tr);
|
||||||
|
},
|
||||||
|
colors: [
|
||||||
|
// 渐变色
|
||||||
|
themeController.currentColor.sc1,
|
||||||
|
themeController.currentColor.sc2,
|
||||||
|
],
|
||||||
|
child: Container(
|
||||||
|
width: MediaQuery.sizeOf(context).width * 0.66,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.055,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 500.rpx,
|
||||||
|
minHeight: 90.rpx,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'微信好友一键分享'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.normal_text_fontSize, // 自定义字体大小
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 17.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,18 +3,21 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
import 'package:vbvs_app/common/color/appConstants.dart';
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
import 'package:vbvs_app/component/tool/FrostedDialog.dart';
|
import 'package:vbvs_app/component/tool/FrostedDialog.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
|
||||||
class DeviceTypePage extends StatefulWidget {
|
class DeviceTypePage extends StatefulWidget {
|
||||||
int type = 0;//0绑定设备 1.查询我的设备
|
int type = 0; //0绑定设备 1.查询我的设备
|
||||||
DeviceTypePage({super.key,this.type = 0});
|
DeviceTypePage({super.key, this.type = 0});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DeviceTypePage> createState() => _EPageState();
|
State<DeviceTypePage> createState() => _EPageState();
|
||||||
@@ -25,10 +28,20 @@ class _EPageState extends State<DeviceTypePage> {
|
|||||||
UserInfoController userInfoController = Get.find();
|
UserInfoController userInfoController = Get.find();
|
||||||
BlueteethBindController blueteethBindController = Get.find();
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
|
DeviceTypeController deviceTypeController = Get.find();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
deviceTypeController.getDeviceType().then((response) {
|
||||||
|
if (response.code != HttpStatusCodes.ok) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
Get.context!,
|
||||||
|
text: response.msg ?? "服务器.失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
// 延迟到 build 完成后执行弹窗逻辑
|
// 延迟到 build 完成后执行弹窗逻辑
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (blueteethBindController.model.read == 1 && widget.type == 0) {
|
if (blueteethBindController.model.read == 1 && widget.type == 0) {
|
||||||
@@ -349,28 +362,29 @@ class _EPageState extends State<DeviceTypePage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
_buildDeviceCard(
|
// 使用 Obx 来监听 deviceTypeList 的变化
|
||||||
context,
|
Obx(() {
|
||||||
title: '设备类型.体征监测设备'.tr,
|
return Column(
|
||||||
imageUrl: 'assets/img/device.png',
|
children: [
|
||||||
type: '1',
|
SizedBox(height: 26.rpx), // 开始的间隔
|
||||||
),
|
...deviceTypeController.deviceTypeList.value
|
||||||
_buildDeviceCard(
|
.map((device) {
|
||||||
context,
|
return Padding(
|
||||||
title: '设备类型.智能床/床垫'.tr,
|
padding: EdgeInsets.only(
|
||||||
imageUrl: 'assets/img/bed.png',
|
bottom: 26.rpx), // 添加每个设备之间的间隔
|
||||||
type: '2',
|
child: _buildDeviceCard(
|
||||||
),
|
context,
|
||||||
_buildDeviceCard(
|
title: device['name'], // 这里假设 device 是一个 Map
|
||||||
context,
|
imageUrl: device['image'],
|
||||||
title: '设备类型.摄像头'.tr,
|
type: device['type'],
|
||||||
imageUrl: 'assets/img/camera.png',
|
),
|
||||||
type: '3',
|
);
|
||||||
),
|
}).toList(),
|
||||||
]
|
SizedBox(height: 26.rpx), // 结束的间隔
|
||||||
.divide(SizedBox(height: 26.rpx))
|
],
|
||||||
.addToStart(SizedBox(height: 26.rpx))
|
);
|
||||||
.addToEnd(SizedBox(height: 26.rpx)),
|
}),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -382,16 +396,20 @@ class _EPageState extends State<DeviceTypePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDeviceCard(BuildContext context,
|
Widget _buildDeviceCard(BuildContext context,
|
||||||
{required String title, required String imageUrl, required String type}) {
|
{required String title, required String imageUrl, required double type}) {
|
||||||
return CustomCard(
|
return CustomCard(
|
||||||
borderRadius: 20.rpx, // 圆角大小
|
borderRadius: 20.rpx, // 圆角大小
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
if (type == '1') {
|
if (type == 1) {
|
||||||
Get.toNamed("/blueteethDevice");
|
Get.toNamed("/blueteethDevice");
|
||||||
}
|
}
|
||||||
if (type == '2') {
|
if (type == 2) {
|
||||||
Get.toNamed("/wifiPage");
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "待开发.提示".tr,
|
||||||
|
textColor: themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -418,8 +436,14 @@ class _EPageState extends State<DeviceTypePage> {
|
|||||||
),
|
),
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(8.rpx),
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
child: Image.asset(
|
// child: Image.asset(
|
||||||
|
// imageUrl,
|
||||||
|
// width: 212.rpx,
|
||||||
|
// height: 168.rpx,
|
||||||
|
// ),
|
||||||
|
child: Image.network(
|
||||||
imageUrl,
|
imageUrl,
|
||||||
|
// fit: BoxFit.cover,
|
||||||
width: 212.rpx,
|
width: 212.rpx,
|
||||||
height: 168.rpx,
|
height: 168.rpx,
|
||||||
),
|
),
|
||||||
|
|||||||
192
lib/pages/device_bind/device_type_list.dart
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
|
|
||||||
|
class DeviceTypeListPage extends StatefulWidget {
|
||||||
|
DeviceTypeListPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DeviceTypeListPage> createState() => _DeviceTypeListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DeviceTypeListPageState extends State<DeviceTypeListPage> {
|
||||||
|
GlobalController globalController = Get.find();
|
||||||
|
UserInfoController userInfoController = Get.find();
|
||||||
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
DeviceTypeController deviceTypeController = Get.find();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
deviceTypeController.getDeviceType().then((response) {
|
||||||
|
if (response.code != HttpStatusCodes.ok) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
Get.context!,
|
||||||
|
text: response.msg ?? "服务器.失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, bodySize) => GestureDetector(
|
||||||
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
|
||||||
|
fit: BoxFit.fill, // 填满整个 Container
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent, // 加上这一行
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: themeController.currentColor.sc17,
|
||||||
|
// backgroundColor: Colors.transparent,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
|
||||||
|
titleSpacing: 0,
|
||||||
|
// leading: returnIconButtom,
|
||||||
|
title: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180.rpx,
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
/// 居中标题
|
||||||
|
Text(
|
||||||
|
'设备列表',
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
letterSpacing: 0,
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
/// 左边返回按钮
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
child: returnIconButtom,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
actions: [],
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
// 使用 Obx 来监听 deviceTypeList 的变化
|
||||||
|
Obx(() {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 26.rpx), // 开始的间隔
|
||||||
|
...deviceTypeController.deviceTypeList.value
|
||||||
|
.map((device) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: 26.rpx), // 添加每个设备之间的间隔
|
||||||
|
child: _buildDeviceCard(
|
||||||
|
context,
|
||||||
|
title: device['name'], // 这里假设 device 是一个 Map
|
||||||
|
imageUrl: device['image'],
|
||||||
|
type: device['type'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
SizedBox(height: 26.rpx), // 结束的间隔
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDeviceCard(BuildContext context,
|
||||||
|
{required String title, required String imageUrl, required double type}) {
|
||||||
|
return CustomCard(
|
||||||
|
borderRadius: 20.rpx, // 圆角大小
|
||||||
|
onTap: () {
|
||||||
|
if (type != null) {
|
||||||
|
if (type == 1) {
|
||||||
|
Get.toNamed("/bodyDevice");
|
||||||
|
}
|
||||||
|
if (type == 2) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "待开发.提示".tr,
|
||||||
|
textColor: themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors: [themeController.currentColor.sc17], // 背景色
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: MediaQuery.sizeOf(context).height * 0.135,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 220.rpx,
|
||||||
|
),
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(77.rpx, 0, 21.rpx, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
color: const Color(0xFFC2CED7),
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.rpx),
|
||||||
|
// child: Image.asset(
|
||||||
|
// imageUrl,
|
||||||
|
// width: 212.rpx,
|
||||||
|
// height: 168.rpx,
|
||||||
|
// ),
|
||||||
|
child: Image.network(
|
||||||
|
imageUrl,
|
||||||
|
// fit: BoxFit.cover,
|
||||||
|
width: 212.rpx,
|
||||||
|
height: 168.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:easydevice/easydevice.dart';
|
import 'package:easydevice/easydevice.dart';
|
||||||
import 'package:ef/ef.dart';
|
import 'package:ef/ef.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
import 'package:vbvs_app/common/color/appConstants.dart';
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/cmd.dart';
|
||||||
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
import 'package:vbvs_app/controller/person/person_controller.dart';
|
import 'package:vbvs_app/controller/person/person_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
import 'package:vbvs_app/controller/user_info_controller.dart';
|
import 'package:vbvs_app/controller/user_info_controller.dart';
|
||||||
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
|
||||||
|
|
||||||
class WifiPage extends StatefulWidget {
|
class WifiPage extends StatefulWidget {
|
||||||
BLEDevice bleDevice;
|
WifiPage({super.key});
|
||||||
WifiPage({super.key, required this.bleDevice});
|
|
||||||
// WifiPage({super.key});
|
// WifiPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -30,18 +31,29 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
BlueteethBindController blueteethBindController = Get.find();
|
BlueteethBindController blueteethBindController = Get.find();
|
||||||
PersonController personController = Get.find();
|
PersonController personController = Get.find();
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
|
var lisObj;
|
||||||
|
// List<String> _logBuffer = [];
|
||||||
|
// bool _isCollecting = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
// connectedDeviceProp = widget.connectedDeviceProp;
|
blueteethBindController.wifiList = [].obs;
|
||||||
Timer(const Duration(microseconds: 100), () {
|
initWifiStatusAndWifiList();
|
||||||
getWifiList();
|
}
|
||||||
});
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
if (lisObj != null) {
|
||||||
|
lisObj.cancel();
|
||||||
|
}
|
||||||
|
blueteethBindController.currentDevice!.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
print("object");
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, bodySize) => GestureDetector(
|
builder: (context, bodySize) => GestureDetector(
|
||||||
onTap: () => FocusScope.of(context).unfocus(),
|
onTap: () => FocusScope.of(context).unfocus(),
|
||||||
@@ -87,11 +99,19 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
child: CustomCard(
|
child: CustomCard(
|
||||||
borderRadius: 20.rpx,
|
borderRadius: 20.rpx,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Get.offAllNamed("/bindDeviceSuccess");
|
if (blueteethBindController.wifiStatus.value != 1) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "wifi页.需配网".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Get.toNamed("/personPage");
|
||||||
|
// Get.toNamed("/bindDeviceSuccess");
|
||||||
},
|
},
|
||||||
colors: [
|
colors: [
|
||||||
themeController.currentColor.sc1,
|
themeController.currentColor.sc1,
|
||||||
themeController.currentColor.sc2,
|
themeController.currentColor.sc2,
|
||||||
],
|
],
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 100.rpx,
|
width: 100.rpx,
|
||||||
@@ -132,41 +152,87 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
padding:
|
padding:
|
||||||
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
|
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFF242835),
|
color: Color(0xFF242835),
|
||||||
borderRadius: BorderRadius.circular(20.rpx),
|
borderRadius: BorderRadius.circular(20.rpx),
|
||||||
),
|
|
||||||
child: Align(
|
|
||||||
alignment: AlignmentDirectional(0, 0),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
|
||||||
30.rpx, 30.rpx, 30.rpx, 30.rpx),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"wifi页.WLAN".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
fontSize:
|
|
||||||
AppConstants().title_text_fontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"wifi页.未连接".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
fontSize:
|
|
||||||
AppConstants().normal_text_fontSize,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
child: Column(
|
||||||
),
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 30.rpx, 30.rpx, 30.rpx),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"wifi页.WLAN".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.title_text_fontSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
return Text(
|
||||||
|
blueteethBindController
|
||||||
|
.wifiStatus.value ==
|
||||||
|
0
|
||||||
|
? "wifi页.未连接".tr
|
||||||
|
: "wifi页.已连接".tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: blueteethBindController
|
||||||
|
.wifiStatus.value ==
|
||||||
|
0
|
||||||
|
? themeController
|
||||||
|
.currentColor.sc4
|
||||||
|
: themeController
|
||||||
|
.currentColor.sc2,
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.normal_text_fontSize,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
if (blueteethBindController
|
||||||
|
.connect_wifi.value ==
|
||||||
|
null ||
|
||||||
|
blueteethBindController
|
||||||
|
.connect_wifi.value.isEmpty) {
|
||||||
|
return Container();
|
||||||
|
} else {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
blueteethBindController
|
||||||
|
.connect_wifi.value['ssid'] ??
|
||||||
|
'未命名'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.title_text_fontSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
getWifiIconByRsso(
|
||||||
|
blueteethBindController
|
||||||
|
.connect_wifi.value),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
@@ -190,7 +256,7 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'可用WLAN',
|
'可用WLAN'.tr,
|
||||||
style: FlutterFlowTheme.of(context)
|
style: FlutterFlowTheme.of(context)
|
||||||
.bodyMedium
|
.bodyMedium
|
||||||
.override(
|
.override(
|
||||||
@@ -203,157 +269,436 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Column(
|
// Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
// mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
// children: [
|
||||||
Row(
|
// Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
// mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment:
|
// mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceBetween,
|
// MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
// children: [
|
||||||
Text(
|
// Text(
|
||||||
'6503',
|
// '6503',
|
||||||
style: FlutterFlowTheme.of(context)
|
// style: FlutterFlowTheme.of(context)
|
||||||
.bodyMedium
|
// .bodyMedium
|
||||||
.override(
|
// .override(
|
||||||
fontFamily: 'Inter',
|
// fontFamily: 'Inter',
|
||||||
fontSize: 30.rpx,
|
// fontSize: 30.rpx,
|
||||||
letterSpacing: 0.0,
|
// letterSpacing: 0.0,
|
||||||
color: themeController
|
// color: themeController
|
||||||
.currentColor.sc3,
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Icon(
|
||||||
|
// Icons.wifi_outlined,
|
||||||
|
// size: 30.rpx,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// mainAxisAlignment:
|
||||||
|
// MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '6503',
|
||||||
|
// style: FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 30.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Icon(
|
||||||
|
// Icons.wifi_outlined,
|
||||||
|
// size: 30.rpx,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// mainAxisAlignment:
|
||||||
|
// MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '6503',
|
||||||
|
// style: FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 30.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Icon(
|
||||||
|
// Icons.wifi_outlined,
|
||||||
|
// size: 30.rpx,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// mainAxisAlignment:
|
||||||
|
// MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '6503',
|
||||||
|
// style: FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 30.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Icon(
|
||||||
|
// Icons.wifi_outlined,
|
||||||
|
// size: 30.rpx,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// mainAxisAlignment:
|
||||||
|
// MainAxisAlignment.spaceBetween,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// '6503',
|
||||||
|
// style: FlutterFlowTheme.of(context)
|
||||||
|
// .bodyMedium
|
||||||
|
// .override(
|
||||||
|
// fontFamily: 'Inter',
|
||||||
|
// fontSize: 30.rpx,
|
||||||
|
// letterSpacing: 0.0,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Icon(
|
||||||
|
// Icons.wifi_outlined,
|
||||||
|
// size: 30.rpx,
|
||||||
|
// color: themeController
|
||||||
|
// .currentColor.sc3,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ].divide(SizedBox(height: 67.rpx)),
|
||||||
|
// ),
|
||||||
|
Obx(() {
|
||||||
|
final sortedList = [
|
||||||
|
...blueteethBindController.wifiList.value
|
||||||
|
]..sort((a, b) => b['rssi']
|
||||||
|
.compareTo(a['rssi'])); // 按 rssi 倒序
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: sortedList
|
||||||
|
.map((wifiItem) => ClickableContainer(
|
||||||
|
backgroundColor:
|
||||||
|
Colors.transparent,
|
||||||
|
highlightColor: themeController
|
||||||
|
.currentColor.sc3,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 0.rpx,
|
||||||
|
horizontal: 20.rpx),
|
||||||
|
borderRadius: 16.rpx,
|
||||||
|
onTap: () {
|
||||||
|
showWifiDialog(
|
||||||
|
context,
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional
|
||||||
|
.fromSTEB(
|
||||||
|
0.rpx,
|
||||||
|
41.rpx,
|
||||||
|
0.rpx,
|
||||||
|
0),
|
||||||
|
child: Container(
|
||||||
|
height: 80.rpx,
|
||||||
|
decoration:
|
||||||
|
BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius
|
||||||
|
.circular(12
|
||||||
|
.rpx), // 加圆角
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment:
|
||||||
|
AlignmentDirectional(
|
||||||
|
-1, 0),
|
||||||
|
child: Obx(() {
|
||||||
|
return TextFormField(
|
||||||
|
onChanged:
|
||||||
|
(value) {
|
||||||
|
blueteethBindController
|
||||||
|
.model
|
||||||
|
.wifiPass =
|
||||||
|
value;
|
||||||
|
},
|
||||||
|
autofocus:
|
||||||
|
false,
|
||||||
|
obscureText:
|
||||||
|
blueteethBindController
|
||||||
|
.model
|
||||||
|
.wifiPassShow,
|
||||||
|
decoration:
|
||||||
|
InputDecoration(
|
||||||
|
isDense:
|
||||||
|
true,
|
||||||
|
labelStyle: FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.labelMedium
|
||||||
|
.override(
|
||||||
|
fontFamily:
|
||||||
|
'Inter',
|
||||||
|
fontSize:
|
||||||
|
26.rpx,
|
||||||
|
letterSpacing:
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
hintText:
|
||||||
|
'蓝牙绑定.输入wifi密码'
|
||||||
|
.tr,
|
||||||
|
hintStyle: FlutterFlowTheme.of(context).labelMedium.override(
|
||||||
|
fontFamily:
|
||||||
|
'Inter',
|
||||||
|
fontSize: 26
|
||||||
|
.rpx,
|
||||||
|
letterSpacing:
|
||||||
|
0.0,
|
||||||
|
color: themeController
|
||||||
|
.currentColor
|
||||||
|
.sc4),
|
||||||
|
enabledBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(
|
||||||
|
color: Color(
|
||||||
|
0x00000000),
|
||||||
|
width: 1
|
||||||
|
.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
focusedBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(
|
||||||
|
color: Color(
|
||||||
|
0x00000000),
|
||||||
|
width: 1
|
||||||
|
.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
errorBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(
|
||||||
|
color: FlutterFlowTheme.of(context)
|
||||||
|
.error,
|
||||||
|
width: 1
|
||||||
|
.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
focusedErrorBorder:
|
||||||
|
OutlineInputBorder(
|
||||||
|
borderSide:
|
||||||
|
BorderSide(
|
||||||
|
color: FlutterFlowTheme.of(context)
|
||||||
|
.error,
|
||||||
|
width: 1
|
||||||
|
.rpx,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(
|
||||||
|
8.rpx),
|
||||||
|
),
|
||||||
|
filled:
|
||||||
|
false,
|
||||||
|
fillColor: FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.secondaryBackground,
|
||||||
|
suffixIcon:
|
||||||
|
InkWell(
|
||||||
|
onTap:
|
||||||
|
() {
|
||||||
|
blueteethBindController
|
||||||
|
.model
|
||||||
|
.wifiPassShow = !blueteethBindController.model.wifiPassShow;
|
||||||
|
blueteethBindController
|
||||||
|
.updateAll();
|
||||||
|
},
|
||||||
|
focusNode:
|
||||||
|
FocusNode(
|
||||||
|
skipTraversal: true),
|
||||||
|
child:
|
||||||
|
Icon(
|
||||||
|
blueteethBindController.model.wifiPassShow
|
||||||
|
? Icons.visibility_outlined
|
||||||
|
: Icons.visibility_off_outlined,
|
||||||
|
size: 30
|
||||||
|
.rpx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily:
|
||||||
|
'Inter',
|
||||||
|
fontSize: 26
|
||||||
|
.rpx,
|
||||||
|
letterSpacing:
|
||||||
|
0.0,
|
||||||
|
color: Colors
|
||||||
|
.black),
|
||||||
|
cursorColor:
|
||||||
|
FlutterFlowTheme.of(
|
||||||
|
context)
|
||||||
|
.primaryText,
|
||||||
|
);
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wifiItem['ssid'] ??
|
||||||
|
'未命名'.tr,
|
||||||
|
onConfirm: () async {
|
||||||
|
showLoadingDialog(
|
||||||
|
context); // 显示 loading
|
||||||
|
bool flag = await sendWifiSetting(
|
||||||
|
wifiItem,
|
||||||
|
blueteethBindController
|
||||||
|
.model.wifiPass!,
|
||||||
|
blueteethBindController
|
||||||
|
.currentDevice!);
|
||||||
|
Navigator.pop(context);
|
||||||
|
if (flag) {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "wifi页.配网成功".tr,
|
||||||
|
textColor:
|
||||||
|
themeController
|
||||||
|
.currentColor
|
||||||
|
.sc2,
|
||||||
|
);
|
||||||
|
blueteethBindController
|
||||||
|
.wifiStatus.value = 1;
|
||||||
|
blueteethBindController
|
||||||
|
.updateAll();
|
||||||
|
} else {
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "wifi页.配网失败".tr,
|
||||||
|
textColor:
|
||||||
|
themeController
|
||||||
|
.currentColor
|
||||||
|
.sc9,
|
||||||
|
);
|
||||||
|
blueteethBindController
|
||||||
|
.wifiStatus.value = 0;
|
||||||
|
blueteethBindController
|
||||||
|
.updateAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize:
|
||||||
|
MainAxisSize.max,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment
|
||||||
|
.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
wifiItem['ssid'] ?? '',
|
||||||
|
style: FlutterFlowTheme
|
||||||
|
.of(context)
|
||||||
|
.bodyMedium
|
||||||
|
.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color:
|
||||||
|
themeController
|
||||||
|
.currentColor
|
||||||
|
.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
getWifiIconByRsso(wifiItem),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
))
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(height: 67.rpx)),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.white,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 20.rpx, vertical: 10.rpx),
|
||||||
|
borderRadius: 20.rpx,
|
||||||
|
onTap: () async {
|
||||||
|
print("点击刷新");
|
||||||
|
await initWifiList();
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "获取wifi列表成功".tr,
|
||||||
|
textColor:
|
||||||
|
themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 25.rpx,
|
||||||
|
height: 25.rpx,
|
||||||
|
decoration: BoxDecoration(),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
'assets/img/icon/refresh.svg',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
color: Colors.white, // 图标固定白色
|
||||||
),
|
),
|
||||||
Icon(
|
),
|
||||||
Icons.wifi_outlined,
|
Text(
|
||||||
size: 30.rpx,
|
'刷新',
|
||||||
color: themeController
|
style: FlutterFlowTheme.of(context)
|
||||||
.currentColor.sc3,
|
.bodyMedium
|
||||||
),
|
.override(
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'6503',
|
|
||||||
style: FlutterFlowTheme.of(context)
|
|
||||||
.bodyMedium
|
|
||||||
.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.wifi_outlined,
|
|
||||||
size: 30.rpx,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'6503',
|
|
||||||
style: FlutterFlowTheme.of(context)
|
|
||||||
.bodyMedium
|
|
||||||
.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.wifi_outlined,
|
|
||||||
size: 30.rpx,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'6503',
|
|
||||||
style: FlutterFlowTheme.of(context)
|
|
||||||
.bodyMedium
|
|
||||||
.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.wifi_outlined,
|
|
||||||
size: 30.rpx,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'6503',
|
|
||||||
style: FlutterFlowTheme.of(context)
|
|
||||||
.bodyMedium
|
|
||||||
.override(
|
|
||||||
fontFamily: 'Inter',
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
letterSpacing: 0.0,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Icon(
|
|
||||||
Icons.wifi_outlined,
|
|
||||||
size: 30.rpx,
|
|
||||||
color: themeController
|
|
||||||
.currentColor.sc3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
].divide(SizedBox(height: 67.rpx)),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.arrow_back,
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
size: 30.rpx,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'刷新',
|
|
||||||
style: FlutterFlowTheme.of(context)
|
|
||||||
.bodyMedium
|
|
||||||
.override(
|
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
fontSize: 30.rpx,
|
fontSize: 30.rpx,
|
||||||
letterSpacing: 0.0,
|
letterSpacing: 0.0,
|
||||||
color: themeController
|
color: themeController
|
||||||
.currentColor.sc3),
|
.currentColor.sc3,
|
||||||
),
|
),
|
||||||
].divide(SizedBox(width: 26.rpx)),
|
),
|
||||||
|
].divide(SizedBox(width: 26.rpx)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
].divide(SizedBox(height: 65.rpx)),
|
].divide(SizedBox(height: 65.rpx)),
|
||||||
),
|
),
|
||||||
@@ -419,42 +764,143 @@ class _WifiPageState extends State<WifiPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getWifiList({int time = 3}) {
|
void initWifiStatusAndWifiList() {
|
||||||
// LoadingDialog.show("扫描WIFI列表中...", icon: LoadingDialogIcon.wifi);
|
if (lisObj != null) {
|
||||||
try {
|
lisObj!.cancel();
|
||||||
// var device = widget.bluetoothDevice;
|
}
|
||||||
// String log = "";
|
lisObj = blueteethBindController.currentDevice!.statusStream
|
||||||
// Function logAdd = (l) {
|
.listen((onData) async {
|
||||||
// log += l;
|
if (onData.status == BleEventType.recvLineLog) {
|
||||||
// };
|
final line = onData.val;
|
||||||
|
print("[bleee]:" + line);
|
||||||
|
}
|
||||||
|
if (onData.status == BleEventType.ready) {
|
||||||
|
showLoadingDialog(context, title: "获取wifi列表中...".tr);
|
||||||
|
bool wifiStatus =
|
||||||
|
await getWifiStatus(blueteethBindController.currentDevice!);
|
||||||
|
blueteethBindController.wifiStatus.value = wifiStatus == true ? 1 : 0;
|
||||||
|
if (wifiStatus) {
|
||||||
|
Map connect_wifiInfo =
|
||||||
|
await getDeviceWifiStatus(blueteethBindController.currentDevice!);
|
||||||
|
if (connect_wifiInfo != null) {
|
||||||
|
blueteethBindController.connect_wifi.value = connect_wifiInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List wifiList =
|
||||||
|
await getWifiList(blueteethBindController.currentDevice!);
|
||||||
|
if (wifiList.length > 0) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "获取wifi列表成功".tr,
|
||||||
|
textColor: themeController.currentColor.sc2,
|
||||||
|
);
|
||||||
|
blueteethBindController.wifiList.value = wifiList;
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
} else {
|
||||||
|
Navigator.pop(context);
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "获取wifi列表失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initWifiList() async {
|
||||||
|
try {
|
||||||
|
var wifiList = await getWifiList(blueteethBindController.currentDevice!);
|
||||||
|
print(wifiList);
|
||||||
|
if (wifiList.length > 0) {
|
||||||
|
blueteethBindController.wifiList.value = wifiList;
|
||||||
|
blueteethBindController.updateAll();
|
||||||
|
}
|
||||||
|
return wifiList;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
TopSlideNotification.show(
|
||||||
|
context,
|
||||||
|
text: "获取wifi列表失败".tr,
|
||||||
|
textColor: themeController.currentColor.sc9,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkIsCalibration() {
|
getWifiIconByRsso(wifiItem) {
|
||||||
// if (controller.model.bindArr[0] == "" ||
|
if (wifiItem['rssi'] >= -30) {
|
||||||
// controller.model.bindArr[0] == null) {
|
// return SvgPicture.asset(
|
||||||
// return;
|
// 'assets/img/icon/wifi4.svg',
|
||||||
// }
|
// width: 25.rpx,
|
||||||
// if (controller.model.bindArr[2] == "" ||
|
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
||||||
// controller.model.bindArr[2] == null) {
|
// color: themeController.currentColor.sc3,
|
||||||
// return;
|
// );
|
||||||
// }
|
return Container(
|
||||||
// if (controller.model.connectedWifiName == "" ||
|
width: 40.rpx,
|
||||||
// controller.model.connectedWifiName == null) {
|
height: 40.rpx,
|
||||||
// return;
|
clipBehavior: Clip.antiAlias,
|
||||||
// }
|
decoration: BoxDecoration(
|
||||||
showCustomConfirmAndCancelDialog(context, "是否进行设备校准?", confirmName: "去校准")
|
shape: BoxShape.circle,
|
||||||
.then((d) async {
|
),
|
||||||
// if (d == "confirm") {
|
child: Image.asset(
|
||||||
// await Get.offAndToNamed("/calibration", arguments: [
|
"assets/img/wifi4.png",
|
||||||
// controller.model.bindArr[1],
|
),
|
||||||
// controller.model.bindArr[2]
|
);
|
||||||
// ]);
|
} else if (wifiItem['rssi'] >= -45) {
|
||||||
// Get.find<GlobalController>().getDeviceList();
|
// return SvgPicture.asset(
|
||||||
// }
|
// 'assets/img/icon/wifi3.svg',
|
||||||
});
|
// width: 25.rpx,
|
||||||
|
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
||||||
|
// color: themeController.currentColor.sc3,
|
||||||
|
// );
|
||||||
|
return Container(
|
||||||
|
width: 40.rpx,
|
||||||
|
height: 40.rpx,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/img/wifi3.png",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (wifiItem['rssi'] >= -60) {
|
||||||
|
// return SvgPicture.asset(
|
||||||
|
// 'assets/img/icon/wifi2.svg',
|
||||||
|
// width: 25.rpx,
|
||||||
|
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
||||||
|
// color: themeController.currentColor.sc3,
|
||||||
|
// );
|
||||||
|
return Container(
|
||||||
|
width: 40.rpx,
|
||||||
|
height: 40.rpx,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/img/wifi3.png",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// return SvgPicture.asset(
|
||||||
|
// 'assets/img/icon/wifi1.svg',
|
||||||
|
// width: 25.rpx,
|
||||||
|
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
|
||||||
|
// color: themeController.currentColor.sc3,
|
||||||
|
// );
|
||||||
|
return Container(
|
||||||
|
width: 40.rpx,
|
||||||
|
height: 40.rpx,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/img/wifi1.png",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:vbvs_app/common/util/FitTool.dart';
|
|||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
import 'package:vbvs_app/controller/login/login_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
@@ -168,6 +169,8 @@ class _EPageState extends State<LoginPage> {
|
|||||||
borderRadius: AppConstants()
|
borderRadius: AppConstants()
|
||||||
.button_container_radius, // 圆角半径
|
.button_container_radius, // 圆角半径
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
TopSlideNotification.show(context,
|
||||||
|
text: "待开发功能".tr);
|
||||||
bool agree =
|
bool agree =
|
||||||
loginController.model.register_agree!;
|
loginController.model.register_agree!;
|
||||||
if (!agree) {
|
if (!agree) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:ef/ef.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:get_storage/get_storage.dart';
|
||||||
import 'package:vbvs_app/common/color/appConstants.dart';
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
import 'package:vbvs_app/common/color/app_uri_status.dart';
|
||||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
@@ -442,9 +443,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
try {
|
try {
|
||||||
await DailyLogUtils
|
DailyLogUtils.writeLog(
|
||||||
.writeLog(
|
"点击获取验证码");
|
||||||
"点击获取验证码");
|
|
||||||
if (countdownController
|
if (countdownController
|
||||||
.countdown
|
.countdown
|
||||||
.value !=
|
.value !=
|
||||||
@@ -457,7 +457,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
.getCode(
|
.getCode(
|
||||||
context);
|
context);
|
||||||
if (apiResponse.code !=
|
if (apiResponse.code !=
|
||||||
HttpStatusCodes.ok) {
|
HttpStatusCodes
|
||||||
|
.ok) {
|
||||||
TopSlideNotification
|
TopSlideNotification
|
||||||
.show(
|
.show(
|
||||||
context,
|
context,
|
||||||
@@ -551,7 +552,7 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
.button_container_radius, // 圆角半径
|
.button_container_radius, // 圆角半径
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
try {
|
try {
|
||||||
await DailyLogUtils.writeLog("点击登录");
|
DailyLogUtils.writeLog("点击登录");
|
||||||
bool agree =
|
bool agree =
|
||||||
loginController.model.register_agree!;
|
loginController.model.register_agree!;
|
||||||
if (!agree) {
|
if (!agree) {
|
||||||
@@ -565,7 +566,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
ApiResponse apiResponse =
|
ApiResponse apiResponse =
|
||||||
await loginController
|
await loginController
|
||||||
.login(context);
|
.login(context);
|
||||||
if (apiResponse.code != HttpStatusCodes.ok) {
|
if (apiResponse.code !=
|
||||||
|
HttpStatusCodes.ok) {
|
||||||
TopSlideNotification.show(
|
TopSlideNotification.show(
|
||||||
context,
|
context,
|
||||||
text: apiResponse.msg!,
|
text: apiResponse.msg!,
|
||||||
@@ -580,7 +582,9 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
textColor: themeController
|
textColor: themeController
|
||||||
.currentColor.sc2,
|
.currentColor.sc2,
|
||||||
);
|
);
|
||||||
Get.offAllNamed('/homePage');
|
// Get.offAllNamed('/homePage');
|
||||||
|
Get.offAllNamed(
|
||||||
|
"/mianPageBottomChange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
168
lib/pages/main_bottom/component/MessageWidgetWidget.dart
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import 'package:ef/ef.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:vbvs_app/common/color/appConstants.dart';
|
||||||
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/CustomCard.dart';
|
||||||
|
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
|
||||||
|
|
||||||
|
class MessageWidgetWidget extends StatefulWidget {
|
||||||
|
const MessageWidgetWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MessageWidgetWidget> createState() => _MessageWidgetWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
|
||||||
|
ThemeController themeController = Get.find();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ClickableContainer(
|
||||||
|
backgroundColor: themeController.currentColor.sc5,
|
||||||
|
highlightColor: themeController.currentColor.sc3,
|
||||||
|
borderRadius: 20.rpx,
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(31.rpx, 33.rpx, 0.rpx, 33.rpx),
|
||||||
|
onTap: () {},
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 66.rpx,
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1, 0),
|
||||||
|
child: Text(
|
||||||
|
'实时监测结果通知'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 30.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 30.rpx,
|
||||||
|
maxWidth: 120.rpx,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildInfoItem(context, '设备ID'),
|
||||||
|
_buildInfoItem(context, '使用人员'),
|
||||||
|
_buildInfoItem(context, '消息类型'),
|
||||||
|
_buildInfoItem(context, '检测数值'),
|
||||||
|
_buildInfoItem(context, '发生时间'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: 30.rpx,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildValueItem(context, '设备ID'),
|
||||||
|
_buildValueItem(context, '使用人员'),
|
||||||
|
_buildValueItem(context, '消息类型'),
|
||||||
|
_buildValueItem(context, '检测数值'),
|
||||||
|
_buildValueItem(context, '发生时间'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 35.rpx)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 46.rpx,
|
||||||
|
right: 20.rpx,
|
||||||
|
child: Container(
|
||||||
|
width: 123.rpx,
|
||||||
|
height: 47.rpx,
|
||||||
|
child: CustomCard(
|
||||||
|
borderRadius: AppConstants().button_container_radius, // 直角
|
||||||
|
colors: [
|
||||||
|
themeController.currentColor.sc1,
|
||||||
|
themeController.currentColor.sc2
|
||||||
|
], // 单色背景
|
||||||
|
enableAnimation: true, // 有点击缩放动画
|
||||||
|
enableGradient: false, // 不用渐变
|
||||||
|
onTap: () {
|
||||||
|
// 点击处理逻辑
|
||||||
|
print('处理按钮点击了');
|
||||||
|
},
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
'处理'.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoItem(BuildContext context, String label) {
|
||||||
|
return Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 62.rpx,
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1, 0),
|
||||||
|
child: Text(
|
||||||
|
label.tr,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildValueItem(BuildContext context, String value) {
|
||||||
|
return Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 62.rpx,
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(-1, 0),
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: FlutterFlowTheme.of(context).bodyMedium.override(
|
||||||
|
fontFamily: 'Inter',
|
||||||
|
fontSize: 26.rpx,
|
||||||
|
letterSpacing: 0.0,
|
||||||
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||