2
0

2 Коммиты 6efb9f5f08 ... 6a0845b206

Автор SHA1 Сообщение Дата
  fanghuisheng 6a0845b206 移除echarts图表相关依赖以及文件 2 недель назад
  fanghuisheng 1b04259e86 门禁以及会议代码场景功能优化 2 недель назад
72 измененных файлов с 2975 добавлено и 5890 удалено
  1. BIN
      nativeplugins/FaceAISDKModule/android/faceAISDK-release.aar
  2. 9 0
      nativeplugins/FaceAISDKModule/changelog.md
  3. 56 0
      nativeplugins/FaceAISDKModule/package.json
  4. BIN
      nativeplugins/Sys-Plugin/android/sysPlugin-release.aar
  5. 50 0
      nativeplugins/Sys-Plugin/package.json
  6. 0 2
      package.json
  7. 4 4
      src/App.vue
  8. 9 0
      src/api/business/door.js
  9. 7 0
      src/api/business/face.js
  10. 2 2
      src/api/business/meeting.js
  11. 181 124
      src/components/oa-passBody/index.vue
  12. 6 0
      src/config.js
  13. 44 8
      src/pages.json
  14. 191 0
      src/pages/door/components/face-verify-popup.nvue
  15. 1116 0
      src/pages/door/faceStorage/index.vue
  16. 519 0
      src/pages/door/index.js
  17. 325 0
      src/pages/door/index.nvue
  18. 1 0
      src/pages/door/index4.vue
  19. 2 1
      src/pages/door/setting/index.scss
  20. 9 22
      src/pages/door/setting/index.vue
  21. 0 96
      src/pages/door/setting/other/index.vue
  22. 2 41
      src/pages/door/setting/public/index.vue
  23. 0 71
      src/pages/door/setting/serve/index.vue
  24. 54 10
      src/pages/door/setting/system/index.vue
  25. 76 0
      src/pages/door/setting/system/network.vue
  26. 17 7
      src/pages/door/setting/system/senior.vue
  27. 2 4
      src/pages/meeting/index.vue
  28. 12 2
      src/pages/meeting/setting/index.vue
  29. 1 55
      src/plugins/device/ph.plugins.js
  30. 106 18
      src/plugins/device/sys.plugins.js
  31. 0 9
      src/plugins/device/yx.plugins.js
  32. 28 10
      src/static/face/door.html
  33. 0 360
      src/static/face/door1.html
  34. 7 3
      src/static/face/js/meeting-page.js
  35. 11 2
      src/static/face/meeting.html
  36. 11 5
      src/static/face/meeting_template_preview.html
  37. BIN
      src/static/iconfont/iconfont.ttf
  38. BIN
      src/static/iconfont/iconfont.woff
  39. BIN
      src/static/iconfont/iconfont.woff2
  40. 80 167
      src/store/modules/control.js
  41. 37 0
      src/store/modules/setting.js
  42. 0 226
      src/uni_modules/lime-echart/changelog.md
  43. 0 399
      src/uni_modules/lime-echart/components/l-echart/canvas.js
  44. 0 323
      src/uni_modules/lime-echart/components/l-echart/l-echart.uvue
  45. 0 484
      src/uni_modules/lime-echart/components/l-echart/l-echart.vue
  46. 0 515
      src/uni_modules/lime-echart/components/l-echart/l-echart_old.vue
  47. 0 56
      src/uni_modules/lime-echart/components/l-echart/nvue.js
  48. 0 27
      src/uni_modules/lime-echart/components/l-echart/props.ts
  49. 0 11
      src/uni_modules/lime-echart/components/l-echart/type.ts
  50. 0 181
      src/uni_modules/lime-echart/components/l-echart/utils.js
  51. 0 136
      src/uni_modules/lime-echart/components/l-echart/uvue.uts
  52. 0 16
      src/uni_modules/lime-echart/components/l-echart/vue.ts
  53. 0 0
      src/uni_modules/lime-echart/components/lime-echart/index.vue
  54. 0 227
      src/uni_modules/lime-echart/components/lime-echart/lime-echart-old.vue
  55. 0 159
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.nvue
  56. 0 158
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.uvue
  57. 0 152
      src/uni_modules/lime-echart/components/lime-echart/lime-echart.vue
  58. 0 110
      src/uni_modules/lime-echart/package.json
  59. 0 499
      src/uni_modules/lime-echart/readme.md
  60. 0 408
      src/uni_modules/lime-echart/readme.old.md
  61. 0 0
      src/uni_modules/lime-echart/static/app/ecStat.min.js
  62. 0 34
      src/uni_modules/lime-echart/static/app/echarts.min.js
  63. 0 0
      src/uni_modules/lime-echart/static/app/uni.webview.1.5.5.js
  64. 0 184
      src/uni_modules/lime-echart/static/app/uvue.html
  65. 0 0
      src/uni_modules/lime-echart/static/ecStat.min.js
  66. 0 49
      src/uni_modules/lime-echart/static/echarts.min.js
  67. 0 129
      src/uni_modules/lime-echart/static/index.html
  68. 0 177
      src/uni_modules/lime-echart/static/nvue.html
  69. 0 0
      src/uni_modules/lime-echart/static/uni.webview.1.5.3.js
  70. 0 0
      src/uni_modules/lime-echart/static/uni.webview.1.5.5.js
  71. 0 173
      src/uni_modules/lime-echart/static/uvue.html
  72. 0 34
      src/uni_modules/lime-echart/static/web/echarts.esm.min.js

BIN
nativeplugins/FaceAISDKModule/android/faceAISDK-release.aar


+ 9 - 0
nativeplugins/FaceAISDKModule/changelog.md

@@ -0,0 +1,9 @@
+## 2025.09.22
+ - 1.完善插件各种参数传递
+ - 2.添加人脸可选择精确模式或快速模式
+ - 3.完善不同场景使用,解决bug
+ - 4.允许用户自行管理拓展摄像头
+
+## 2025.01.06
+ - 1.添加人脸识别活体检测Android 插件原生支持
+ 

+ 56 - 0
nativeplugins/FaceAISDKModule/package.json

@@ -0,0 +1,56 @@
+{  
+    "name": "FaceAISDKModule",  
+    "id": "FaceAISDKModule",  
+    "version": "3.4.0",
+    "description": "FaceAI SDK是设备端可离线不联网Android 人脸识别、活体检测以及人脸搜索SDK,可快速集成实现人脸识别,人脸搜索功能",
+    "_dp_type":"nativeplugin",  
+    "_dp_nativeplugin":{  
+        "android": {  
+            "plugins": [  
+                {  
+                    "type": "module",  
+                    "name": "FaceAISDKModule",  
+                    "class": "io.face.uniplugin.FaceAISDKModule"  
+                },
+				{
+					"type": "component",
+					"name": "door-camera-x",
+					"class": "io.face.uniplugin.door.DoorCameraXComponent"
+				}
+            ],  
+            "hooksClass": "",  
+            "integrateType": "aar",  
+            "dependencies": [
+              "io.github.faceaisdk:Android:2025.09.25",
+              "com.airbnb.android:lottie:6.0.0",
+              "androidx.constraintlayout:constraintlayout:2.1.4",
+              "pub.devrel:easypermissions:3.0.0",
+              "com.airbnb.android:lottie:6.0.0",
+              "com.github.princekin-f:EasyFloat:2.0.4",
+              "androidx.cardview:cardview:1.0.0",
+              "androidx.recyclerview:recyclerview:1.3.2",
+              "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.8",
+              "com.github.bumptech.glide:glide:4.16.0",
+              "androidx.appcompat:appcompat:1.6.0",
+              "com.github.javakam:file.core:3.9.8@aar",
+              "com.github.javakam:file.selector:3.9.8@aar",
+              "com.github.javakam:file.compressor:3.9.8@aar"
+            ],  
+            "compileOptions": {
+                "sourceCompatibility": "17",  
+                "targetCompatibility": "17"  
+            },  
+            "abis": [  
+				"armeabi-v7a",
+                "arm64-v8a"  
+            ],  
+            "minSdkVersion": "21",  
+            "permissions": [  
+				"<uses-permission android:name=\"android.permission.CAMERA\"/>"
+            ],  
+            "parameters": {  
+
+            }  
+        }
+	}  
+}

BIN
nativeplugins/Sys-Plugin/android/sysPlugin-release.aar


+ 50 - 0
nativeplugins/Sys-Plugin/package.json

@@ -0,0 +1,50 @@
+{
+    "name": "Sys-Plugin",
+    "id": "Sys-Plugin",
+    "version": "1.0.0",
+    "description": "系统硬件",
+    "_dp_type": "nativeplugin",
+    "_dp_nativeplugin": {
+        "android": {
+            "plugins": [
+                {
+                    "type": "module",
+                    "name": "sysPlugin",
+                    "class": "com.example.sysplugin.system"
+                },
+                {
+                    "type": "module",
+                    "name": "SerialPortModule",
+                    "class": "com.example.sysplugin.SerialPortModule"
+                },                
+                {
+                    "type": "module",
+                    "name": "yxPlugin",
+                    "class": "com.example.sysplugin.YxPluginModule"
+                },
+				{
+				    "type": "module",
+				    "name": "phPlugin",
+				    "class": "com.example.sysplugin.PhPluginModule"
+				},
+                {
+                    "type": "module",
+                    "name": "mqttPlugin",
+                    "class": "com.example.sysplugin.mqtt"
+                }
+            ],
+            "integrateType": "aar",
+            "dependencies": [],
+            "compileOptions": {
+                "sourceCompatibility": "1.8",
+                "targetCompatibility": "1.8"
+            },
+            "abis": [
+                "armeabi-v7a",
+                "x86"
+            ],
+            "minSdkVersion": "21",
+            "permissions": []
+        }
+    }
+}

+ 0 - 2
package.json

@@ -53,13 +53,11 @@
     "@dcloudio/uni-mp-weixin": "3.0.0-alpha-4020320240703001",
     "@dcloudio/uni-mp-xhs": "3.0.0-alpha-4020320240703001",
     "@dcloudio/uni-quickapp-webview": "3.0.0-alpha-4020320240703001",
-    "echarts": "^5.3.3",
     "jquery": "^3.7.1",
     "jsencrypt": "^3.3.2",
     "pinia": "2.0.14",
     "pinia-plugin-persistedstate": "^3.1.0",
     "vue": "^3.4.21",
-    "vue-echarts": "^6.2.3",
     "vue-i18n": "^9.1.9",
     "vue-json-excel": "^0.3.0",
     "vuex": "^4.0.2",

+ 4 - 4
src/App.vue

@@ -24,7 +24,7 @@ function stteingInit() {
   plus.screen.unlockOrientation(); //解除屏幕方向的锁定,但是不一定是竖屏;
   // 智能会议
   if (config.appInfo.appid === "__UNI__F3963F8") {
-    // plus.screen.lockOrientation("portrait-primary"); 
+    // plus.screen.lockOrientation("portrait-primary");
     plus.screen.lockOrientation("landscape-primary"); //设置屏幕方向(1.竖屏正方向:portrait-primary 2.竖屏反方向:portrait-secondary 3.横屏正方向:landscape-primary 4.横屏反方向:landscape-secondary 5.自然方向:default)
     proxy.$keyListen.startListen({
       needStopSystem: true,
@@ -59,10 +59,8 @@ onHide(() => {
 </script>
 
 <style lang="scss">
+// #ifndef APP-PLUS-NVUE
 @import "@/static/scss/index.scss";
-</style>
-
-<style lang="scss">
 @import "@/uni_modules/uview-plus/index.scss";
 
 uni-page-body,
@@ -80,4 +78,6 @@ uni-page-refresh {
   font-size: $uni-font-size-lg;
   font-weight: bold;
 }
+
+//#endif
 </style>

+ 9 - 0
src/api/business/door.js

@@ -68,4 +68,13 @@ export function doorApi() {
             });
         },
     };
+}
+
+//门禁设备心跳接口
+export function egDeviceHeartbeat(data) {
+    return request({
+        url: '/service-eg/egDeviceHeartbeat/escalation',
+        method: 'POST',
+        data
+    })
 }

+ 7 - 0
src/api/business/face.js

@@ -13,5 +13,12 @@ export function faceApi() {
                 data,
             });
         },
+        facePerson: (data) => {
+            return request({
+                url: '/service-eg/smartface/compare/person',
+                method: 'POST',
+                data,
+            });
+        },
     };
 }

+ 2 - 2
src/api/business/meeting.js

@@ -288,8 +288,8 @@ export function signOnOut(data) {
     })
 }
 
-//设备心跳接口
-export function escalation(data) {
+//会议设备心跳接口
+export function meetingDeviceHeartbeat(data) {
     return request({
         url: '/service-meeting/meetingDeviceHeartbeat/escalation',
         method: 'POST',

+ 181 - 124
src/components/oa-passBody/index.vue

@@ -1,22 +1,30 @@
 <template>
   <view class="visit-box" v-if="show">
+    <image class="visit-bg" src="./bg.png" mode="scaleToFill"></image>
     <!-- <view class="forget-pass" @tap="forgetpass">忘记密码</view> -->
     <image class="visit-close" src="./close1.png" @click="close"></image>
-    <view class="visit-icon"><image :src="icon"></image></view>
-    <view class="visit-text">请输入密码</view>
+    <text class="visit-text">请输入密码</text>
     <view class="visit-list">
-      <view class="visit-list-box" v-for="(item, index) in passselect" :key="index" :style="{ background: index < selectIndex ? '#FFFFFF' : 'transparent' }"> </view>
+      <view class="visit-list-box" v-for="(item, index) in passselect" :key="index"
+        :class="{ 'visit-list-box-last': index === passselect.length - 1 }" :style="{
+          backgroundColor: index < selectIndex ? '#FFFFFF' : 'rgba(0,0,0,0)',
+        }"></view>
     </view>
     <view class="visit-Nine-palaces">
-      <view
-        class="visit-Nine-palaces-list"
-        v-for="(item, index) in Keylist"
-        :key="index"
-        :style="{ borderColor: styleClass(item.key), background: keytype(item.key, index) }"
-        @click="selectkey(item, index)"
-      >
-        <text v-if="item.key !== 'backspace'">{{ item.key }}</text>
-        <view class="qingchu-box" v-else><image src="./qingchu1.png"></image></view>
+      <view class="nine-row" v-for="(row, ri) in keyRows" :key="'row-' + ri"
+        :class="{ 'nine-row-last': ri === keyRows.length - 1 }">
+        <view class="visit-Nine-palaces-list" v-for="(item, ci) in row" :key="'cell-' + ri + '-' + ci"
+          :class="{ 'visit-Nine-palaces-list-row-end': ci === 2 }" :style="{
+            borderColor: styleClass(item.key),
+            backgroundColor: keytype(item.key, ri * 3 + ci),
+          }" @click="selectkey(item, ri * 3 + ci)">
+          <text v-if="item.key !== 'backspace'" class="nine-key-text">{{
+            item.key
+            }}</text>
+          <view class="qingchu-box" v-else>
+            <image class="qingchu-img" src="./qingchu1.png" mode="aspectFit"></image>
+          </view>
+        </view>
       </view>
     </view>
   </view>
@@ -38,13 +46,37 @@ export default {
   data() {
     return {
       passselect: new Array(6),
-      Keylist: [{ key: 1 }, { key: 2 }, { key: 3 }, { key: 4 }, { key: 5 }, { key: 6 }, { key: 7 }, { key: 8 }, { key: 9 }, { key: "#" }, { key: 0 }, { key: "backspace" }],
+      Keylist: [
+        { key: 1 },
+        { key: 2 },
+        { key: 3 },
+        { key: 4 },
+        { key: 5 },
+        { key: 6 },
+        { key: 7 },
+        { key: 8 },
+        { key: 9 },
+        { key: "#" },
+        { key: 0 },
+        { key: "backspace" },
+      ],
       key_index: null,
       select: [], //选择的时候,
       selectIndex: null,
       KeylistIndex: null,
     };
   },
+  computed: {
+    /** 一行三个键,避免 nvue 下 flex-wrap 表现不一致 */
+    keyRows() {
+      const list = this.Keylist;
+      const rows = [];
+      for (let i = 0; i < list.length; i += 3) {
+        rows.push(list.slice(i, i + 3));
+      }
+      return rows;
+    },
+  },
   methods: {
     styleClass(type) {
       // return typeof type !== "number" ? "transparent" : "#ffffff";
@@ -54,7 +86,7 @@ export default {
       if (this.key_index === index && typeof type === "number") {
         type = this.selectColor;
       } else {
-        type = "transparent";
+        type = "rgba(0,0,0,0)";
       }
       return type;
     },
@@ -101,120 +133,145 @@ export default {
 };
 </script>
 
-<style lang="scss" scoped>
+<style scoped>
 .qingchu-box {
-  width: 100%;
-  height: 100%;
-  text-align: center;
-  padding-top: 0.325rem;
-  & > image {
-    width: 50%;
-    height: 50%;
-  }
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  flex-direction: row;
+  justify-content: center;
+  align-items: center;
+}
+
+.qingchu-img {
+  width: 46px;
+  height: 46px;
+}
+
+.visit-bg {
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
 }
+
 .visit-box {
-  width: 100vw;
-  height: 100vh;
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
   overflow: hidden;
+  flex-direction: column;
+  align-items: center;
+}
+
+/* 预留:忘记密码 */
+.visit-box .forget-pass {
+  width: 72px;
+  height: 28px;
+  background-color: rgba(0, 0, 0, 0.3);
+  border-radius: 14px 0px 0px 14px;
+  font-size: 13px;
+  font-weight: 400;
+  line-height: 28px;
+  color: #ffffff;
+  opacity: 1;
+  text-align: center;
+  position: absolute;
+  top: 10px;
+  right: 0px;
+}
+
+.visit-close {
+  position: absolute;
+  top: 25rpx;
+  right: 25rpx;
+  width: 40px;
+  height: 40px;
+}
+
+.visit-text {
+  /* 不用百分比:直接用左右贴边铺满 */
   position: relative;
-  background: url(./bg.png) no-repeat;
-  background-size: 100% 100%;
-
-  .forget-pass {
-    width: 144rpx;
-    height: 56rpx;
-    background: rgba(0, 0, 0, 0.3);
-    border-radius: 28rpx 0rpx 0rpx 28rpx;
-    font-size: 26rpx;
-    font-family: PingFang SC;
-    font-weight: 400;
-    line-height: 56rpx;
-    color: #ffffff;
-    opacity: 1;
-    text-align: center;
-    position: absolute;
-    top: 19rpx;
-    right: 0rpx;
-  }
-
-  .visit-close {
-    display: block;
-    width: 40rpx;
-    height: 40rpx;
-    margin-top: 50rpx;
-    margin-right: 50rpx;
-    margin-left: auto;
-    margin-bottom: 180rpx;
-  }
-
-  .visit-icon {
-    width: 68rpx;
-    height: 68rpx;
-    opacity: 1;
-    margin: 0 auto;
-    & > image {
-      width: 100%;
-      height: 100%;
-    }
-  }
-  .visit-text {
-    width: 100%;
-    height: 42rpx;
-    font-size: 30rpx;
-    font-family: PingFang SC;
-    font-weight: bold;
-    line-height: 41rpx;
-    color: #ffffff;
-    opacity: 1;
-    text-align: center;
-    margin-top: 15rpx;
-  }
-  .visit-list {
-    width: 45vw;
-    height: 28rpx;
-    display: flex;
-    flex-wrap: wrap;
-    margin: 0 auto;
-    margin-top: 35rpx;
-    margin-bottom: 50rpx;
-    justify-content: center;
-    .visit-list-box {
-      width: 28rpx;
-      height: 28rpx;
-      border: 2px solid #ffffff;
-      border-radius: 50%;
-      margin-right: 20rpx;
-
-      &:nth-last-child(1) {
-        margin-right: 0rpx;
-      }
-    }
-  }
-  .visit-Nine-palaces {
-    width: 70vw;
-    height: 579rpx;
-    margin: 0 auto;
-    // border: 1rpx solid;
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: center;
-    .visit-Nine-palaces-list {
-      width: 128rpx;
-      height: 128rpx;
-      border: 4rpx solid #ffffff;
-      border-radius: 50%;
-      opacity: 1;
-      text-align: center;
-      font-size: 50rpx;
-      font-family: Roboto;
-      font-weight: bold;
-      line-height: 120rpx;
-      color: #ffffff;
-      margin-right: 50rpx;
-      &:nth-child(3n) {
-        margin-right: 0rpx;
-      }
-    }
-  }
+  left: 0px;
+  right: 0px;
+  font-size: 30px;
+  font-weight: bold;
+  color: #ffffff;
+  text-align: center;
+  margin-top: 110rpx;
+}
+
+.visit-list {
+  width: 200px;
+  height: 25px;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  margin-top: 18px;
+  margin-bottom: 50px;
+  justify-content: center;
+  align-items: center;
+}
+
+.visit-list-box {
+  width: 25px;
+  height: 25px;
+  border-radius: 15px;
+  border-width: 2px;
+  border-style: solid;
+  border-color: #ffffff;
+  margin-right: 10px;
+}
+
+.visit-list-box-last {
+  margin-right: 0px;
+}
+
+.visit-Nine-palaces {
+  width: 340px;
+  flex-direction: column;
+}
+
+.nine-row {
+  width: 340px;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: center;
+  margin-bottom: 18px;
+}
+
+.nine-row-last {
+  margin-bottom: 0px;
+}
+
+.visit-Nine-palaces-list {
+  position: relative;
+  width: 90px;
+  height: 90px;
+  border-radius: 45px;
+  border-width: 3px;
+  border-style: solid;
+  border-color: #ffffff;
+  opacity: 1;
+  flex-direction: row;
+  justify-content: center;
+  align-items: center;
+  margin-right: 35px;
+}
+
+.visit-Nine-palaces-list-row-end {
+  margin-right: 0px;
+}
+
+.nine-key-text {
+  font-size: 36px;
+  font-weight: bold;
+  line-height: 86px;
+  color: #ffffff;
+  text-align: center;
 }
 </style>

+ 6 - 0
src/config.js

@@ -6,12 +6,18 @@ export default {
 
   //#ifdef APP-PLUS || MP-WEIXIN
   baseUrl: "https://gateWay.usky.cn/prod-api",
+  // baseUrl: "http://192.168.10.165:801/dev-api",
   //#endif
 
   //#ifdef H5
   baseUrl: import.meta.env.MODE === "production" ? `https://${window.location.host}/prod-api` : `http://192.168.10.165:801/dev-api`,
   //#endif
 
+  //#ifdef APP-PLUS
+  // mqttUrl: "wss://gateWay.usky.cn/mqtt",
+  mqttUrl: "wss://192.168.10.165:801/mqtt",
+  //#endif
+
   websiteUrl: "https://qhome.usky.cn",
   // 应用信息
   appInfo: {

+ 44 - 8
src/pages.json

@@ -13,9 +13,9 @@
             }
         },
         {
-            "path": "pages/door/setting/index",
+            "path": "pages/meeting/setting/password",
             "style": {
-                "navigationBarTitleText": "",
+                "navigationBarTitleText": "密码验证",
                 "enablePullDownRefresh": false,
                 "navigationStyle": "custom",
                 "app-plus": {
@@ -25,9 +25,9 @@
             }
         },
         {
-            "path": "pages/door/setting/other/index",
+            "path": "pages/meeting/setting/SerialPort",
             "style": {
-                "navigationBarTitleText": "",
+                "navigationBarTitleText": "串口通讯",
                 "enablePullDownRefresh": false,
                 "navigationStyle": "custom",
                 "app-plus": {
@@ -37,7 +37,19 @@
             }
         },
         {
-            "path": "pages/door/setting/public/index",
+            "path": "pages/meeting/setting/index",
+            "style": {
+                "navigationBarTitleText": "会议配置",
+                "enablePullDownRefresh": false,
+                "navigationStyle": "custom",
+                "app-plus": {
+                    "bounce": "none",
+                    "titleNView": false
+                }
+            }
+        },
+        {
+            "path": "pages/door/setting/index",
             "style": {
                 "navigationBarTitleText": "",
                 "enablePullDownRefresh": false,
@@ -49,7 +61,7 @@
             }
         },
         {
-            "path": "pages/door/setting/serve/index",
+            "path": "pages/door/setting/public/index",
             "style": {
                 "navigationBarTitleText": "",
                 "enablePullDownRefresh": false,
@@ -85,9 +97,33 @@
             }
         },
         {
-            "path": "pages/face/index",
+            "path": "pages/door/setting/system/network",
+            "style": {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false,
+                "navigationStyle": "custom",
+                "app-plus": {
+                    "bounce": "none",
+                    "titleNView": false
+                }
+            }
+        },
+        {
+            "path": "pages/door/faceStorage/index",
+            "style": {
+                "navigationBarTitleText": "人脸数据管理",
+                "enablePullDownRefresh": false,
+                "navigationStyle": "custom",
+                "app-plus": {
+                    "bounce": "none",
+                    "titleNView": false
+                }
+            }
+        },
+        {
+            "path": "pages/meeting/index",
             "style": {
-                "navigationBarTitleText": "人脸识别",
+                "navigationBarTitleText": "智能会议",
                 "enablePullDownRefresh": false,
                 "navigationStyle": "custom",
                 "app-plus": {

+ 191 - 0
src/pages/door/components/face-verify-popup.nvue

@@ -0,0 +1,191 @@
+<template>
+  <view v-if="show" class="mask" @click="handleMaskClick">
+    <view class="card" :class="success ? 'cardOk' : 'cardFail'" @click.stop="noop">
+      <view class="avatar">
+        <view class="avatar-inner">
+          <image
+            v-if="resolvedAvatarSrc"
+            class="avatar-img"
+            :src="resolvedAvatarSrc"
+            mode="aspectFill"
+          ></image>
+        </view>
+      </view>
+      <text class="mark">{{ success ? "✓" : "×" }}</text>
+      <text class="title">{{ success ? "身份验证通过" : "身份验证失败" }}</text>
+      <text class="sub">{{ subLine }}</text>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: "FaceVerifyPopup",
+  props: {
+    show: {
+      type: Boolean,
+      default: false,
+    },
+    success: {
+      type: Boolean,
+      default: false,
+    },
+    faceName: {
+      type: String,
+      default: "",
+    },
+    failMessage: {
+      type: String,
+      default: "",
+    },
+    avatarSrc: {
+      type: String,
+      default: "",
+    },
+    duration: {
+      type: Number,
+      default: 2800,
+    },
+    closeOnMask: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      closeTimer: null,
+    };
+  },
+  computed: {
+    /** App 本地绝对路径需 file:// 前缀以便 <image> 加载 */
+    resolvedAvatarSrc() {
+      const raw = String(this.avatarSrc || "").trim();
+      if (!raw) return "";
+      if (/^https?:\/\//i.test(raw)) return raw;
+      if (raw.startsWith("/static/")) return raw;
+      if (raw.startsWith("file://")) return raw;
+      if (raw.startsWith("/")) return "file://" + raw;
+      return raw;
+    },
+    subLine() {
+      if (this.success) {
+        const n = (this.faceName || "").trim();
+        return n ? `欢迎您,${n}` : "欢迎您";
+      }
+      const m = (this.failMessage || "").trim();
+      return m || "陌生人";
+    },
+  },
+  watch: {
+    show(val) {
+      if (this.closeTimer) {
+        clearTimeout(this.closeTimer);
+        this.closeTimer = null;
+      }
+      if (val && this.duration > 0) {
+        this.closeTimer = setTimeout(() => {
+          this.closeTimer = null;
+          this.$emit("close");
+        }, this.duration);
+      }
+    },
+  },
+  beforeDestroy() {
+    if (this.closeTimer) {
+      clearTimeout(this.closeTimer);
+    }
+  },
+  methods: {
+    noop() {},
+    handleMaskClick() {
+      if (this.closeOnMask) {
+        if (this.closeTimer) {
+          clearTimeout(this.closeTimer);
+          this.closeTimer = null;
+        }
+        this.$emit("close");
+      }
+    },
+  },
+};
+</script>
+
+<style scoped>
+.mask {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.45);
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  z-index: 100080;
+}
+.card {
+  width: 336px;
+  padding-top: 34px;
+  padding-bottom: 30px;
+  padding-left: 26px;
+  padding-right: 26px;
+  border-radius: 22px;
+  flex-direction: column;
+  align-items: center;
+}
+.cardOk {
+  background-color: #525f7f;
+}
+.cardFail {
+  background-color: #a56961;
+}
+/* 外圈白边;内层与图片同尺寸,避免 border 下仍用 104 全宽 + absolute 在 weex 中错位 */
+.avatar {
+  width: 104px;
+  height: 104px;
+  border-radius: 52px;
+  border-width: 4px;
+  border-color: #ffffff;
+  border-style: solid;
+  background-color: #ffffff;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+}
+.avatar-inner {
+  width: 96px;
+  height: 96px;
+  border-radius: 48px;
+  background-color: #ffffff;
+  overflow: hidden;
+}
+.avatar-img {
+  width: 96px;
+  height: 96px;
+  border-radius: 48px;
+}
+.mark {
+  margin-top: 18px;
+  font-size: 54px;
+  line-height: 54px;
+  color: #ffffff;
+  font-weight: 700;
+}
+.title {
+  margin-top: 16px;
+  font-size: 26px;
+  line-height: 34px;
+  color: #ffffff;
+  font-weight: 700;
+  text-align: center;
+}
+.sub {
+  margin-top: 10px;
+  font-size: 20px;
+  line-height: 28px;
+  color: rgba(255, 255, 255, 0.95);
+  font-weight: 400;
+  text-align: center;
+}
+</style>

+ 1116 - 0
src/pages/door/faceStorage/index.vue

@@ -0,0 +1,1116 @@
+<template>
+  <view
+    class="faceStorage-page"
+    :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
+  >
+    <view class="faceStorage-header">
+      <text class="iconfont oaIcon-left" @click="handleExit()"></text>
+      <view class="faceStorage-title">人脸数据管理</view>
+    </view>
+
+    <oa-scroll
+      customClass="faceStorage-container scroll-height"
+      :customStyle="{
+        //#ifdef APP-PLUS || MP-WEIXIN
+        height: `calc(100vh - (60px))`,
+        //#endif
+        //#ifdef H5
+        height: `calc(100vh - (60px))`,
+        //#endif
+      }"
+      :refresherLoad="false"
+      :refresherEnabled="false"
+      :refresherDefaultStyle="'none'"
+      :refresherBackground="'#f5f6f7'"
+      :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
+    >
+      <template #default>
+        <view class="container">
+          <!-- 顶部统计 -->
+          <view class="stats-bar">
+            <view class="stat-item">
+              <text class="stat-num">{{ stats.total || 0 }}</text>
+              <text class="stat-label">总数</text>
+            </view>
+            <view class="stat-item">
+              <text class="stat-num">{{ stats.unsynced || 0 }}</text>
+              <text class="stat-label">未同步</text>
+            </view>
+            <view class="stat-item">
+              <text class="stat-num">{{ stats.synced || 0 }}</text>
+              <text class="stat-label">已同步</text>
+            </view>
+          </view>
+
+          <!-- 操作按钮 -->
+          <view class="action-bar">
+            <button class="btn btn-primary" @click="addFace">添加人脸</button>
+            <button class="btn btn-info" @click="verifyFace">校验人脸</button>
+            <button class="btn btn-secondary" @click="syncServer">
+              同步服务器
+            </button>
+            <button class="btn btn-success" @click="exportData">
+              导出数据
+            </button>
+            <button class="btn btn-warning" @click="importData">
+              导入数据
+            </button>
+            <button class="btn btn-danger" @click="clearAll">清空数据</button>
+          </view>
+
+          <!-- 搜索框 -->
+          <view class="search-box">
+            <input
+              class="search-input"
+              placeholder="搜索人脸ID或姓名..."
+              v-model="searchText"
+              @input="onSearch"
+            />
+          </view>
+
+          <view class="face-list">
+            <view
+              v-for="face in displayList"
+              :key="face.faceId"
+              class="face-item"
+            >
+              <image
+                v-if="faceImageSrc(face)"
+                class="face-thumb"
+                :src="faceImageSrc(face)"
+                mode="aspectFill"
+              />
+              <view class="face-info">
+                <text class="face-id">{{ face.faceId }}</text>
+                <text v-if="face.faceName" class="face-name">{{
+                  face.faceName
+                }}</text>
+                <text class="face-time">{{ formatTime(face.createTime) }}</text>
+                <text
+                  class="face-status"
+                  :class="getStatusClass(face.syncStatus)"
+                >
+                  {{ getStatusText(face.syncStatus) }}
+                </text>
+              </view>
+              <view class="face-actions">
+                <button
+                  class="btn-small btn-danger"
+                  @click.stop="deleteFace(face.faceId)"
+                >
+                  删除
+                </button>
+              </view>
+            </view>
+
+            <view v-if="displayList.length === 0" class="empty-state">
+              <text class="empty-text">暂无数据</text>
+            </view>
+          </view>
+
+          <!-- 添加人脸弹窗 -->
+          <view v-if="showAddDialog" class="modal" @click="closeAddDialog">
+            <view class="modal-content" @click.stop>
+              <view class="modal-header">
+                <text class="modal-title">添加人脸</text>
+                <text class="modal-close" @click="closeAddDialog">×</text>
+              </view>
+
+              <view class="modal-body">
+                <view class="form-item">
+                  <text class="form-label">姓名</text>
+                  <input
+                    class="form-input"
+                    v-model="newFace.faceName"
+                    placeholder="请输入姓名"
+                  />
+                </view>
+
+                <view class="form-item">
+                  <text class="form-label">选择图片</text>
+                  <button class="btn btn-secondary" @click="selectImage">
+                    {{ newFace.imageBase64 ? "重新选择" : "选择图片" }}
+                  </button>
+                  <image
+                    v-if="newFace.imageBase64"
+                    class="preview-img"
+                    :src="newFace.imageBase64"
+                  />
+                </view>
+              </view>
+
+              <view class="modal-footer">
+                <button class="btn btn-secondary" @click="closeAddDialog">
+                  取消
+                </button>
+                <button
+                  class="btn btn-primary"
+                  @click="confirmAdd"
+                  :disabled="!canAdd"
+                >
+                  确定
+                </button>
+              </view>
+            </view>
+          </view>
+
+          <!-- 校验人脸弹窗 -->
+          <view
+            v-if="showVerifyDialog"
+            class="modal"
+            @click="closeVerifyDialog"
+          >
+            <view class="modal-content large" @click.stop>
+              <view class="modal-header">
+                <text class="modal-title">校验人脸</text>
+                <text class="modal-close" @click="closeVerifyDialog">×</text>
+              </view>
+
+              <view class="modal-body">
+                <view class="form-item">
+                  <text class="form-label">选择图片</text>
+                  <button class="btn btn-secondary" @click="selectVerifyImage">
+                    {{ verifyImage.imageBase64 ? "重新选择" : "选择图片" }}
+                  </button>
+                  <image
+                    v-if="verifyImage.imageBase64"
+                    class="preview-img"
+                    :src="verifyImage.imageBase64"
+                  />
+                </view>
+
+                <!-- 校验结果 -->
+                <view v-if="verifyResult" class="verify-result">
+                  <view class="result-header">
+                    <text class="result-title">校验结果</text>
+                  </view>
+
+                  <view class="result-summary">
+                    <text
+                      class="result-text"
+                      :class="verifyResult.hasFace ? 'success' : 'error'"
+                    >
+                      {{ verifyResult.hasFace ? "检测到人脸" : "未检测到人脸" }}
+                    </text>
+                    <text
+                      v-if="verifyResult.hasFace && verifyResult.matchedFaceId"
+                      class="result-text success"
+                    >
+                      匹配的人脸ID: {{ verifyResult.matchedFaceId }}
+                    </text>
+                    <text
+                      v-if="verifyResult.hasFace && verifyResult.matchedFaceId"
+                      class="result-text success"
+                    >
+                      相似度: {{ (verifyResult.similarity * 100).toFixed(1) }}%
+                    </text>
+                    <text
+                      v-if="verifyResult.hasFace && !verifyResult.matchedFaceId"
+                      class="result-text warning"
+                    >
+                      未找到匹配的人脸
+                    </text>
+                  </view>
+                </view>
+              </view>
+
+              <view class="modal-footer">
+                <button class="btn btn-secondary" @click="closeVerifyDialog">
+                  关闭
+                </button>
+                <button
+                  class="btn btn-primary"
+                  @click="confirmVerify"
+                  :disabled="!verifyImage.imageBase64 || loading"
+                >
+                  {{ loading ? "校验中..." : "开始校验" }}
+                </button>
+              </view>
+            </view>
+          </view>
+
+          <!-- 加载提示 -->
+          <view v-if="loading" class="loading">
+            <text class="loading-text">{{ loadingText }}</text>
+          </view>
+        </view>
+      </template>
+    </oa-scroll>
+  </view>
+</template>
+
+<script setup>
+import { computed, getCurrentInstance, reactive, ref } from "vue";
+import { onLoad, onPullDownRefresh, onShow } from "@dcloudio/uni-app";
+import sysPlugins from "@/plugins/device/sys.plugins";
+
+const { proxy } = getCurrentInstance();
+
+// 人脸识别插件
+const faceAIModule = uni.requireNativePlugin("FaceAISDKModule");
+const modal = uni.requireNativePlugin("modal");
+
+// 数据
+const faceList = ref([]);
+const stats = ref({});
+const searchText = ref("");
+
+// 弹窗状态
+const showAddDialog = ref(false);
+const showVerifyDialog = ref(false);
+
+// 添加人脸(人脸ID 由原生插件按本地库规则生成,前端不传 faceId)
+const newFace = reactive({
+  faceName: "",
+  imageBase64: "",
+});
+
+// 校验人脸
+const verifyImage = reactive({
+  imageBase64: "",
+});
+const verifyResult = ref(null);
+
+// 加载状态
+const loading = ref(false);
+const loadingText = ref("加载中...");
+
+const displayList = computed(() => {
+  const q = searchText.value.trim().toLowerCase();
+  if (!q) return faceList.value;
+  return faceList.value.filter((face) => {
+    const idMatch =
+      face.faceId && String(face.faceId).toLowerCase().includes(q);
+    const nameMatch =
+      face.faceName && String(face.faceName).toLowerCase().includes(q);
+    return idMatch || nameMatch;
+  });
+});
+
+const canAdd = computed(() => {
+  return Boolean(newFace.faceName.trim() && newFace.imageBase64);
+});
+
+function handleExit() {
+  proxy.$tab.navigateBack(1);
+}
+
+async function loadData() {
+  loading.value = true;
+  loadingText.value = "加载数据中...";
+
+  try {
+    await Promise.all([getStats(), getFaceList()]);
+  } catch (e) {
+    console.error("加载数据失败:", e);
+    modal.toast({ message: "加载失败", duration: 1500 });
+  } finally {
+    loading.value = false;
+  }
+}
+
+async function getStats() {
+  await faceAIModule.getFaceStorageStats({}, (result) => {
+    if (result && result.code === 1) {
+      stats.value = result.data || {};
+    } else {
+      console.error("获取统计失败:", result);
+    }
+  });
+}
+
+async function getFaceList() {
+  await faceAIModule.getFaceList({ page: 0, pageSize: 1000 }, (result) => {
+    if (result && result.code === 1) {
+      faceList.value = result.data || [];
+    } else {
+      console.error("获取列表失败:", result);
+    }
+  });
+}
+
+function addFace() {
+  newFace.faceName = "";
+  newFace.imageBase64 = "";
+  showAddDialog.value = true;
+}
+
+function verifyFace() {
+  verifyImage.imageBase64 = "";
+  verifyResult.value = null;
+  showVerifyDialog.value = true;
+}
+
+// 同步服务器数据:deviceCode 从 sysPlugins.getDeviceInfo().serial 获取
+async function syncServer() {
+  const info = sysPlugins.getDeviceInfo();
+  const deviceCode = info && info.serial ? String(info.serial).trim() : "";
+  if (!deviceCode) {
+    modal.toast({ message: "获取设备编码失败(serial 为空)", duration: 2000 });
+    return;
+  }
+
+  loading.value = true;
+  loadingText.value = "同步服务器数据中...";
+
+  await faceAIModule.downloadFacesFromServer(
+    { deviceCode, faceIds: [] },
+    (result) => {
+      if (result && result.code === 1) {
+        modal.toast({ message: result.msg || "同步完成", duration: 2000 });
+        loadData();
+      } else {
+        modal.toast({
+          message: "同步失败: " + (result ? result.msg : "未知错误"),
+          duration: 2500,
+        });
+      }
+      loading.value = false;
+    },
+  );
+}
+
+function selectImage() {
+  uni.chooseImage({
+    count: 1,
+    sizeType: ["compressed"],
+    sourceType: ["album", "camera"],
+    success: (res) => readImageFile(res.tempFilePaths[0]),
+    fail: (e) => {
+      console.error("选择图片失败:", e);
+      modal.toast({ message: "选择图片失败", duration: 1500 });
+    },
+  });
+}
+
+function selectVerifyImage() {
+  uni.chooseImage({
+    count: 1,
+    sizeType: ["compressed"],
+    sourceType: ["album", "camera"],
+    success: (res) => readVerifyImageFile(res.tempFilePaths[0]),
+    fail: (e) => {
+      console.error("选择图片失败:", e);
+      modal.toast({ message: "选择图片失败", duration: 1500 });
+    },
+  });
+}
+
+function readImageFile(filePath) {
+  console.log("开始读取图片文件:", filePath);
+  readImageFileWithPlus(filePath);
+}
+
+function readVerifyImageFile(filePath) {
+  console.log("开始读取校验图片文件:", filePath);
+  readVerifyImageFileWithPlus(filePath);
+}
+
+function readImageFileWithPlus(filePath) {
+  if (typeof plus === "undefined") {
+    console.error("plus对象不可用,可能不在App环境中");
+    modal.toast({
+      message: "当前环境不支持文件读取,请重新选择",
+      duration: 1500,
+    });
+    return;
+  }
+
+  plus.io.resolveLocalFileSystemURL(
+    filePath,
+    (entry) => {
+      if (entry.isDirectory) {
+        console.error("路径指向目录,不是文件:", filePath);
+        modal.toast({
+          message: "选择的路径是目录,请选择图片文件",
+          duration: 1500,
+        });
+        return;
+      }
+
+      entry.file(
+        (file) => {
+          if (file.size === 0) {
+            modal.toast({ message: "文件为空,请重新选择", duration: 1500 });
+            return;
+          }
+
+          const reader = new plus.io.FileReader();
+          reader.onloadend = (e) => {
+            const dataUrl = (e && e.target && e.target.result) || "";
+            if (dataUrl) {
+              const base64 = String(dataUrl).replace(/^data:[^;]+;base64,/, "");
+              newFace.imageBase64 = `data:image/jpeg;base64,${base64}`;
+            } else {
+              modal.toast({
+                message: "图片数据为空,请重新选择",
+                duration: 1500,
+              });
+            }
+          };
+          reader.onerror = (err) => {
+            console.error("文件读取失败:", err);
+            modal.toast({
+              message: "读取图片失败,请重新选择",
+              duration: 1500,
+            });
+          };
+          reader.readAsDataURL(file);
+        },
+        (err) => {
+          console.error("获取文件对象失败:", err);
+          modal.toast({ message: "文件访问失败,请重新选择", duration: 1500 });
+        },
+      );
+    },
+    (err) => {
+      console.error("解析文件路径失败:", err);
+      modal.toast({ message: "文件路径解析失败,请重新选择", duration: 1500 });
+    },
+  );
+}
+
+function readVerifyImageFileWithPlus(filePath) {
+  if (typeof plus === "undefined") {
+    console.error("plus对象不可用,可能不在App环境中");
+    modal.toast({
+      message: "当前环境不支持文件读取,请重新选择",
+      duration: 1500,
+    });
+    return;
+  }
+
+  plus.io.resolveLocalFileSystemURL(
+    filePath,
+    (entry) => {
+      if (entry.isDirectory) {
+        console.error("路径指向目录,不是文件:", filePath);
+        modal.toast({
+          message: "选择的路径是目录,请选择图片文件",
+          duration: 1500,
+        });
+        return;
+      }
+
+      entry.file(
+        (file) => {
+          if (file.size === 0) {
+            modal.toast({ message: "文件为空,请重新选择", duration: 1500 });
+            return;
+          }
+
+          const reader = new plus.io.FileReader();
+          reader.onloadend = (e) => {
+            const dataUrl = (e && e.target && e.target.result) || "";
+            if (dataUrl) {
+              const base64 = String(dataUrl).replace(/^data:[^;]+;base64,/, "");
+              verifyImage.imageBase64 = `data:image/jpeg;base64,${base64}`;
+            } else {
+              modal.toast({
+                message: "图片数据为空,请重新选择",
+                duration: 1500,
+              });
+            }
+          };
+          reader.onerror = (err) => {
+            console.error("校验图片文件读取失败:", err);
+            modal.toast({
+              message: "读取图片失败,请重新选择",
+              duration: 1500,
+            });
+          };
+          reader.readAsDataURL(file);
+        },
+        (err) => {
+          console.error("获取校验图片文件对象失败:", err);
+          modal.toast({ message: "文件访问失败,请重新选择", duration: 1500 });
+        },
+      );
+    },
+    (err) => {
+      console.error("解析校验图片文件路径失败:", err);
+      modal.toast({ message: "文件路径解析失败,请重新选择", duration: 1500 });
+    },
+  );
+}
+
+async function confirmAdd() {
+  if (!canAdd.value) {
+    modal.toast({ message: "请填写完整信息", duration: 1500 });
+    return;
+  }
+
+  loading.value = true;
+  loadingText.value = "添加中...";
+
+  await faceAIModule.addFaceToStorage(
+    {
+      faceName: newFace.faceName.trim(),
+      faceBase64: newFace.imageBase64,
+      source: 0,
+    },
+    (result) => {
+      if (result && result.code === 1) {
+        const fid = result.data && result.data.faceId;
+        modal.toast({
+          message: fid ? `添加成功,人脸ID:${fid}` : "添加成功",
+          duration: 1500,
+        });
+        closeAddDialog();
+        loadData();
+      } else {
+        modal.toast({
+          message: "添加失败: " + (result ? result.msg : "未知错误"),
+          duration: 2000,
+        });
+      }
+      loading.value = false;
+    },
+  );
+}
+
+async function confirmVerify() {
+  if (!verifyImage.imageBase64) {
+    modal.toast({ message: "请选择图片", duration: 1500 });
+    return;
+  }
+
+  loading.value = true;
+  loadingText.value = "校验中...";
+
+  await faceAIModule.verifyFaceByImage(
+    { imageBase64: verifyImage.imageBase64 },
+    (result) => {
+      if (result && result.code === 1) {
+        modal.toast({
+          message: `人脸验证成功: ${result.matchedFaceId}`,
+          duration: 2000,
+        });
+      } else {
+        modal.toast({
+          message: `人脸验证失败: ${result ? result.msg : "未知错误"}`,
+          duration: 2000,
+        });
+      }
+      loading.value = false;
+    },
+  );
+}
+
+async function deleteFace(faceId) {
+  const res = await new Promise((resolve) => {
+    uni.showModal({
+      title: "确认删除",
+      content: `确定要删除 "${faceId}" 吗?`,
+      success: (r) => resolve(Boolean(r.confirm)),
+    });
+  });
+  if (!res) return;
+
+  loading.value = true;
+  loadingText.value = "删除中...";
+
+  await faceAIModule.deleteFaceFromStorage({ faceId }, (result) => {
+    if (result && result.code === 1) {
+      modal.toast({ message: "删除成功", duration: 1500 });
+      loadData();
+    } else {
+      modal.toast({
+        message: "删除失败: " + (result ? result.msg : "未知错误"),
+        duration: 2000,
+      });
+    }
+    loading.value = false;
+  });
+}
+
+async function exportData() {
+  loading.value = true;
+  loadingText.value = "导出中...";
+
+  await faceAIModule.exportFaceData({}, (result) => {
+    if (result && result.code === 1) {
+      modal.toast({
+        message: `已导出 ${faceList.value.length} 条数据`,
+        duration: 2000,
+      });
+    } else {
+      modal.toast({
+        message: "导出失败: " + (result ? result.msg : "未知错误"),
+        duration: 2000,
+      });
+    }
+    loading.value = false;
+  });
+}
+
+function importData() {
+  modal.toast({ message: "导入功能开发中", duration: 1500 });
+}
+
+async function clearAll() {
+  const res = await new Promise((resolve) => {
+    uni.showModal({
+      title: "确认清空",
+      content: "确定要清空所有数据吗?此操作不可恢复!",
+      success: (r) => resolve(Boolean(r.confirm)),
+    });
+  });
+  if (!res) return;
+
+  loading.value = true;
+  loadingText.value = "清空中...";
+
+  await faceAIModule.clearAllFaceData({}, (result) => {
+    if (result && result.code === 1) {
+      modal.toast({ message: "清空成功", duration: 1500 });
+      loadData();
+    } else {
+      modal.toast({
+        message: "清空失败: " + (result ? result.msg : "未知错误"),
+        duration: 2000,
+      });
+    }
+
+    loading.value = false;
+  });
+}
+
+function onSearch() {
+  // 搜索逻辑在computed中处理
+}
+
+function closeAddDialog() {
+  showAddDialog.value = false;
+  newFace.faceName = "";
+  newFace.imageBase64 = "";
+}
+
+function closeVerifyDialog() {
+  showVerifyDialog.value = false;
+  verifyImage.imageBase64 = "";
+  verifyResult.value = null;
+}
+
+function formatTime(timestamp) {
+  if (!timestamp) return "";
+  const date = new Date(timestamp);
+  return date.toLocaleDateString() + " " + date.toLocaleTimeString();
+}
+
+function getStatusText(status) {
+  const statusMap = { 0: "未同步", 1: "已同步", 2: "同步失败" };
+  return statusMap[status] || "未知";
+}
+
+function getStatusClass(status) {
+  const classMap = {
+    0: "status-unsynced",
+    1: "status-synced",
+    2: "status-failed",
+  };
+  return classMap[status] || "";
+}
+
+function getSourceText(source) {
+  const sourceMap = { 0: "本地录入", 1: "服务器下发" };
+  return sourceMap[source] || "未知";
+}
+
+function faceImageSrc(face) {
+  if (!face) return "";
+  const p = String(face.imagePath || face.face_image_path || "").trim();
+  if (!p) return "";
+  if (p.startsWith("data:image/")) return p;
+  if (p.startsWith("/")) return "file://" + p;
+  if (p.includes("://")) return p;
+  return p;
+}
+
+onLoad(() => {
+  loadData();
+});
+
+onShow(() => {
+  loadData();
+});
+
+onPullDownRefresh(() => {
+  loadData().finally(() => {
+    uni.stopPullDownRefresh();
+  });
+});
+</script>
+<style lang="scss" scoped>
+@import "../setting/index.scss";
+</style>
+<style scoped>
+.faceStorage-page {
+  background: white;
+  min-height: 100vh;
+}
+
+.faceStorage-header {
+  height: 60px;
+  padding: 0 20rpx;
+  background: white;
+  display: flex;
+  align-items: center;
+  position: sticky;
+  top: 0;
+  z-index: 50;
+}
+
+.faceStorage-title {
+  flex: 1;
+  text-align: center;
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #111;
+  margin-right: 40rpx; /* 视觉居中,抵消左侧返回按钮 */
+}
+
+.faceStorage-container {
+  background: #f5f5f5 !important;
+}
+
+/* 统计栏 */
+.stats-bar {
+  display: flex;
+  background: white;
+  border-radius: 12rpx;
+  padding: 30rpx;
+  margin-bottom: 20rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.stat-item {
+  flex: 1;
+  text-align: center;
+}
+
+.stat-num {
+  display: block;
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #007aff;
+  margin-bottom: 8rpx;
+}
+
+.stat-label {
+  font-size: 24rpx;
+  color: #666;
+}
+
+/* 操作栏 */
+.action-bar {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 15rpx;
+  margin-bottom: 20rpx;
+}
+
+.btn {
+  flex: 1;
+  min-width: 150rpx;
+  height: 70rpx;
+  border-radius: 8rpx;
+  border: none;
+  font-size: 24rpx;
+  color: white;
+}
+
+.btn-primary {
+  background: #007aff;
+}
+
+.btn-success {
+  background: #28a745;
+}
+
+.btn-warning {
+  background: #ffc107;
+  color: #333;
+}
+
+.btn-danger {
+  background: #dc3545;
+}
+
+.btn-secondary {
+  background: #6c757d;
+}
+
+.btn-info {
+  background: #17a2b8;
+}
+
+.btn:disabled {
+  opacity: 0.6;
+}
+
+/* 搜索框 */
+.search-box {
+  margin-bottom: 20rpx;
+}
+
+.search-input {
+  width: 100%;
+  height: 70rpx;
+  padding: 0 20rpx;
+  border: 2rpx solid #ddd;
+  border-radius: 8rpx;
+  background: white;
+  font-size: 26rpx;
+  box-sizing: border-box;
+}
+
+.face-list {
+  width: 100%;
+  background: white;
+  border-radius: 12rpx;
+  padding: 20rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.face-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20rpx 0;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+
+.face-thumb {
+  width: 96rpx;
+  height: 96rpx;
+  border-radius: 10rpx;
+  background: #f0f0f0;
+  margin-right: 18rpx;
+  flex-shrink: 0;
+}
+
+.face-item:last-child {
+  border-bottom: none;
+}
+
+.face-info {
+  flex: 1;
+}
+
+.face-id {
+  display: block;
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 8rpx;
+}
+
+.face-name {
+  display: block;
+  font-size: 24rpx;
+  color: #555;
+  margin-bottom: 6rpx;
+}
+
+.face-time {
+  display: block;
+  font-size: 22rpx;
+  color: #666;
+  margin-bottom: 4rpx;
+}
+
+.face-status {
+  font-size: 20rpx;
+  padding: 4rpx 8rpx;
+  border-radius: 4rpx;
+  color: white;
+}
+
+.status-unsynced {
+  background: #ffc107;
+  color: #333;
+}
+
+.status-synced {
+  background: #28a745;
+}
+
+.status-failed {
+  background: #dc3545;
+}
+
+.face-actions {
+  margin-left: 20rpx;
+}
+
+.btn-small {
+  padding: 8rpx 16rpx;
+  border-radius: 6rpx;
+  border: none;
+  font-size: 20rpx;
+  color: white;
+}
+
+/* 空状态 */
+.empty-state {
+  text-align: center;
+  padding: 100rpx 0;
+}
+
+.empty-text {
+  font-size: 26rpx;
+  color: #999;
+}
+
+/* 弹窗 */
+.modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  width: 90%;
+  max-width: 600rpx;
+  background: white;
+  border-radius: 12rpx;
+  overflow: hidden;
+}
+
+.modal-content.large {
+  max-width: 800rpx;
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 30rpx;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+
+.modal-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #333;
+}
+
+.modal-close {
+  font-size: 40rpx;
+  color: #999;
+  line-height: 1;
+}
+
+.modal-body {
+  padding: 30rpx;
+  max-height: 60vh;
+  overflow-y: auto;
+}
+
+.modal-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 20rpx;
+  padding: 30rpx;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+/* 表单 */
+.form-item {
+  margin-bottom: 30rpx;
+}
+
+.form-label {
+  display: block;
+  font-size: 26rpx;
+  color: #333;
+  margin-bottom: 10rpx;
+}
+
+.form-input {
+  width: 100%;
+  height: 70rpx;
+  padding: 0 20rpx;
+  border: 2rpx solid #ddd;
+  border-radius: 8rpx;
+  font-size: 26rpx;
+  box-sizing: border-box;
+}
+
+.preview-img {
+  width: 200rpx;
+  height: 200rpx;
+  border-radius: 8rpx;
+  margin-top: 20rpx;
+}
+
+/* 加载提示 */
+.loading {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2000;
+}
+
+.loading-text {
+  background: white;
+  padding: 30rpx 40rpx;
+  border-radius: 8rpx;
+  font-size: 26rpx;
+  color: #333;
+}
+
+/* 校验结果样式 */
+.verify-result {
+  margin-top: 30rpx;
+  padding: 20rpx;
+  background: #f8f9fa;
+  border-radius: 8rpx;
+}
+
+.result-header {
+  margin-bottom: 20rpx;
+}
+
+.result-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #333;
+}
+
+.result-summary {
+  margin-bottom: 20rpx;
+}
+
+.result-text {
+  display: block;
+  font-size: 26rpx;
+  margin-bottom: 10rpx;
+}
+
+.result-text.success {
+  color: #28a745;
+}
+
+.result-text.error {
+  color: #dc3545;
+}
+
+.result-text.warning {
+  color: #ffc107;
+}
+</style>

+ 519 - 0
src/pages/door/index.js

@@ -0,0 +1,519 @@
+import tab from "@/plugins/tab.plugins.js";
+import permission from "@/plugins/permission.plugins.js";
+import modal from "@/plugins/modal.plugins.js";
+import sysPlugins from "@/plugins/device/sys.plugins";
+import config from "@/config";
+import { doorApi, egDeviceHeartbeat } from "@/api/business/door.js";
+import { meetingDeviceHeartbeat } from "@/api/business/meeting.js";
+import time from "@/plugins/time.plugins.js";
+
+/** 门禁相关子页路径 */
+export const DoorRoutes = {
+    faceStorage: "/pages/door/faceStorage/index",
+    setting: "/pages/door/setting/index",
+};
+
+/**
+ * 门禁相关常量
+ */
+export const DoorArr = {
+    workStatusData: [
+        { label: "办公", value: 1, class: 'workRed' },
+        { label: "会客", value: 2, class: 'workRed' },
+        { label: "外出", value: 3, class: 'workGreen' },
+        { label: "勿扰", value: 4, class: 'workRed' },
+    ],
+    timerId: null,
+    doorList: [],
+    isClicked: false,
+    doorInter: {
+        doorDom: null,
+        egEscalation: null,
+        ipTimer: null,
+        meetingEscalation: null,
+        meeting: null,
+    },
+    /** 门禁页:表单与左下角展示用字段(index.nvue 初始化时拷贝,避免与单例共用引用) */
+    form: {
+        door: {
+            id: undefined,
+            name: undefined,
+        },
+        meetingId: undefined,
+        meetingName: undefined,
+    },
+    ipAddress: "",
+    deviceSerial: "",
+};
+
+/**
+ * 同步设备序列号到 DoorArr.deviceSerial(左下角 SN 展示)
+ */
+export function syncDeviceSerial() {
+    try {
+        const info = sysPlugins.getDeviceInfo && sysPlugins.getDeviceInfo();
+        DoorArr.deviceSerial = info && info.serial != null ? String(info.serial) : "";
+    } catch (e) {
+        DoorArr.deviceSerial = "";
+    }
+}
+
+/**
+ * 门禁开门方法
+ */
+export const DoorOpenFunc = {
+    click(vm, event) {
+        const ev = event || {};
+        if (!DoorArr.form || !DoorArr.form.door) {
+            modal.msg("请先绑定门禁!");
+            return;
+        }
+        if (!DoorArr.form.door.id) {
+            modal.msg("请先绑定门禁!");
+            return;
+        }
+        if (DoorArr.isClicked) {
+            modal.msg("请勿重复点击!");
+            return;
+        }
+        DoorArr.isClicked = true;
+
+        doorApi()
+            .control({
+                skipCheck: true,
+                userId: ev.userId ? ev.userId : undefined,
+                userName: ev.userName ? ev.userName : undefined,
+                passType: 1, // 1: 人脸 2: 刷卡 3: 手机
+                productCode: "502_USKY",
+                deviceUuid: DoorArr.form.door.deviceUuid,
+                commandCode: "door_onoff",
+                commandValue: 1,
+            })
+            .then((item) => {
+                if (item.status == "success") {
+                    modal.msg("开门成功");
+                } else {
+                    modal.msg("开门失败");
+                }
+                setTimeout(() => {
+                    DoorArr.isClicked = false;
+                }, 2000);
+            })
+            .catch(() => {
+                setTimeout(() => {
+                    DoorArr.isClicked = false;
+                }, 2000);
+            });
+    },
+    localOpen(vm) {
+        if (DoorArr.isClicked) {
+            modal.msg("请勿重复点击!");
+            return;
+        }
+        sysPlugins.openDoor(1, 0);
+        DoorArr.isClicked = true;
+    },
+};
+
+/**
+ * 相机相关
+ */
+export const cameraFunc = {
+    /** 取页面 doorCam 原生组件实例 */
+    getRef(vm) {
+        const cam = vm && vm.$refs ? vm.$refs.doorCam : null;
+        return cam || null;
+    },
+    /** 假隐藏控制:仅控制预览显示,不影响分析 */
+    setFakeHidden(vm, enabled) {
+        // #ifdef APP-PLUS
+        const cam = this.getRef(vm);
+        if (!cam || typeof cam.setFakeHidden !== "function") return;
+        cam.setFakeHidden(enabled != null && enabled);
+        // #endif
+    },
+    /** 语音播报(TTS) */
+    speak(vm, text) {
+        // #ifdef APP-PLUS
+        const cam = this.getRef(vm);
+        if (!cam || typeof cam.speak !== "function") return;
+        if (!vm || !vm.thresholds || vm.thresholds.ttsEnabled !== true) return;
+        const t = (text || "").toString();
+        if (!t.trim()) return;
+        cam.speak(t);
+        // #endif
+    },
+    /** 申请相机权限后启动门禁识别(含 setConfig) */
+    async start(vm) {
+        // #ifdef APP-PLUS
+        const ok = await permission.getPermisson("camera", true).catch(() => null);
+        if (!ok) return;
+
+        const cam = this.getRef(vm);
+        if (!cam || typeof cam.start !== "function") return;
+
+        if (typeof cam.setConfig === "function") {
+            cam.setConfig({ ...vm.thresholds, autoStart: true });
+        }
+        cam.start();
+        // #endif
+    },
+    /** 停止门禁相机/分析 */
+    stop(vm) {
+        // #ifdef APP-PLUS
+        const cam = this.getRef(vm);
+        if (cam && typeof cam.stop === "function") {
+            cam.stop();
+        }
+        // #endif
+    },
+    /** door-camera-x:状态回调 */
+    onState(vm, e) {
+        const d = e && e.detail ? e.detail : {};
+        if (d && d.state === "error") {
+            // 启动/运行失败:由页面生命周期或用户操作决定是否重试
+        }
+    },
+    /** door-camera-x:识别结果 */
+    onResult(vm, e) {
+        const d = (e && (e.detail?.detail || e.detail || e)) || {};
+
+        if (d.code == 1) {
+            sysPlugins.openDoor(1, 0);
+            FaceVerifyFunc.show(vm, d);
+        } else if (d.hasFace === true) {
+            FaceVerifyFunc.show(vm, d);
+        }
+    },
+};
+
+/**
+ * 门禁页底部按钮:远程开门 / 密码面板
+ */
+export const doorPageUi = {
+    parentMessage(vm, type) {
+        if (type === "点击开门") {
+            DoorOpenFunc.click(vm, {
+                userId: "",
+                userName: "快捷方式开门",
+            });
+            return;
+        }
+        if (type === "密码") {
+            cameraFunc.stop(vm);
+            vm.popup.show = true;
+            return;
+        }
+        uni.showToast({ title: type, icon: "none" });
+    },
+};
+
+/**
+ * 人脸识别结果弹窗(成功 / 库比对未命中)
+ */
+export const FaceVerifyFunc = {
+    show(vm, detail) {
+        if (!vm) return;
+        const code = Number(detail && detail.code);
+        const name = String((detail && (detail.matchedFaceName || detail.faceName)) || "").trim();
+        const msg = String((detail && detail.msg) || "").trim();
+        const avatarSrc = String((detail && (detail.avatarSrc || detail.capturePath)) || "").trim();
+
+        if (!vm.faceVerifyPopup) {
+            vm.faceVerifyPopup = {
+                show: false,
+                success: false,
+                faceName: "",
+                failMessage: "",
+                avatarSrc: "",
+            };
+        }
+
+        if (code === 1) {
+            vm.faceNotFoundStreak = 0;
+            if (vm.thresholds?.ttsEnabled) {
+                cameraFunc.speak(vm, "验证成功");
+            }
+            vm.faceVerifyPopup.success = true;
+            vm.faceVerifyPopup.faceName = name;
+            vm.faceVerifyPopup.failMessage = "";
+            vm.faceVerifyPopup.avatarSrc = avatarSrc;
+            vm.faceVerifyPopup.show = true;
+            return;
+        }
+
+        const streak = (vm.faceNotFoundStreak || 0) + 1;
+        vm.faceNotFoundStreak = streak;
+        if (streak < 3) {
+            return;
+        }
+        vm.faceNotFoundStreak = 0;
+
+        if (vm.thresholds?.ttsEnabled) {
+            cameraFunc.speak(vm, "验证失败");
+        }
+        vm.faceVerifyPopup.success = false;
+        vm.faceVerifyPopup.faceName = "";
+        vm.faceVerifyPopup.failMessage = "陌生人";
+        vm.faceVerifyPopup.avatarSrc = avatarSrc;
+        vm.faceVerifyPopup.show = true;
+    },
+    close(vm) {
+        if (!vm || !vm.faceVerifyPopup) return;
+        vm.faceVerifyPopup.show = false;
+    },
+};
+
+/**
+ * 按路由 key 跳转
+ */
+export function navigateByKey(vm, key) {
+    const url = DoorRoutes[key];
+    if (!url) return;
+
+    if (key === "faceStorage" || key === "setting") {
+        if (vm && typeof vm.stop === "function") {
+            vm.stop();
+        }
+    }
+
+    tab.navigateTo(url);
+}
+
+/**
+ * 时钟方法
+ */
+export const clockFunc = {
+    start(vm) {
+        if (!vm || DoorArr.timerId) return;
+        this.tick(vm);
+        DoorArr.timerId = setInterval(() => this.tick(vm), 1000);
+    },
+    stop(vm) {
+        if (!DoorArr.timerId) return;
+        clearInterval(DoorArr.timerId);
+        DoorArr.timerId = null;
+    },
+    tick(vm) {
+        if (!vm || !vm.state) return;
+        const d = new Date();
+        const pad2 = (n) => (n < 10 ? "0" + n : "" + n);
+        const yyyy = d.getFullYear();
+        const mm = pad2(d.getMonth() + 1);
+        const dd = pad2(d.getDate());
+        const hh = pad2(d.getHours());
+        const mi = pad2(d.getMinutes());
+        vm.state.date = `${yyyy}/${mm}/${dd}`;
+        vm.state.dateTime = `${hh}:${mi}`;
+    },
+};
+
+/**
+ * 密码面板
+ */
+export const onDoorPass = {
+    /** 密码键盘提交:校验、关弹层、恢复相机 */
+    change(vm, event) {
+        if (event == DoorArr.form.door?.password) {
+            vm.popup.show = false;
+            DoorOpenFunc.click(vm);
+        } else {
+            vm.popup.show = false;
+            modal.msg("密码错误");
+        }
+        vm.$nextTick(() => {
+            vm.$nextTick(() => {
+                cameraFunc.start(vm);
+            });
+        });
+    },
+    /** 密码面板关闭:同步显隐并恢复预览 */
+    close(vm, event) {
+        vm.popup.show = event;
+        vm.$nextTick(() => {
+            vm.$nextTick(() => {
+                cameraFunc.start(vm);
+            });
+        });
+    },
+};
+
+/**
+ * 移除指定字符串
+ */
+export function removeSegmentWithTarget(originalStr, targetStr) {
+    if (!originalStr || typeof originalStr !== "string") return originalStr;
+    if (originalStr.includes(targetStr)) {
+        const regex = new RegExp(`\\d*${targetStr}\\d*`, "g");
+        return originalStr.replace(regex, "");
+    }
+    return originalStr;
+}
+
+/**
+ * 将 form.door 同步到页面 state
+ */
+export function syncDoorUiFromForm(vm) {
+    const d = DoorArr.form && DoorArr.form.door;
+    if (!d || !vm.state) return;
+    if (d.deviceName != null) vm.state.doorName = d.deviceName;
+    else if (d.name != null) vm.state.doorName = d.name;
+    if (d.imgPath != null) vm.state.imgPath = d.imgPath;
+    if (d.openMode != null) vm.state.openMode = d.openMode;
+    if (d.remark != null) vm.state.remark = d.remark;
+    if (d.workStatus != null) {
+        const workStatusItem = DoorArr.workStatusData.find(item => item.value == d.workStatus);
+        if (workStatusItem) {
+            vm.state.workName = workStatusItem.label;
+            vm.state.workClass = workStatusItem.class;
+        } else {
+            vm.state.workName = '';
+            vm.state.workClass = '';
+        }
+    }
+}
+
+/**
+ * 从本地 storage_face 恢复表单
+ */
+export function initDoorData(vm) {
+    const storage = uni.getStorageSync("storage_face");
+    if (!storage) return;
+
+    if (config.appInfo.appid === "__UNI__F3963F8") {
+        DoorArr.form.meetingId = storage.meetingId || undefined;
+        DoorArr.form.meetingName = storage.meetingName || undefined;
+    } else if (config.appInfo.appid === "__UNI__8D6E9FD") {
+        DoorArr.form.door = {
+            ...DoorArr.form.door,
+            id: storage.door && storage.door.id != null ? storage.door.id : undefined,
+            name: storage.door && storage.door.name != null ? storage.door.name : undefined,
+            ...(storage.door || {}),
+        };
+        syncDoorUiFromForm(vm);
+    }
+}
+
+/**
+ * 网络请求方法
+ */
+export const apiRequest = {
+    /**
+     * 设备心跳上报
+     */
+    initDoorEscalation(vm, type) {
+        if (!sysPlugins.getDeviceInfo().serial) return;
+        sysPlugins.getIpAddress({
+            success: (res) => {
+                const param = {
+                    deviceCode: sysPlugins.getDeviceInfo().serial,
+                    ipAddr: res,
+                    deviceType: 1,
+                    model: sysPlugins.getDeviceInfo().model,
+                    manuFacturer: sysPlugins.getDeviceInfo().manufacturer,
+                    version: sysPlugins.getDeviceInfo().version,
+                    sdk: sysPlugins.getDeviceInfo().Sdk,
+                    deviceStatus: type === "eg" ? 1 : undefined,
+                };
+                if (type === "meeting") {
+                    meetingDeviceHeartbeat(param);
+                } else if (type === "eg") {
+                    egDeviceHeartbeat(param);
+                }
+            },
+        });
+    },
+    /**
+     * 获取门禁列表
+     */
+    getDoorList(vm) {
+        DoorArr.doorList.length = 0;
+        return doorApi()
+            .Select({
+                current: 1,
+                size: 2000,
+                deviceCode: sysPlugins.getDeviceInfo().serial || "NTECVSG3PL",
+            })
+            .then((requset) => {
+                if (!requset.data.records || requset.data.records.length <= 0) return;
+
+                let data = requset.data.records[0];
+                if (!time.isInRange(8, 18)) {
+                    data = { ...data, openMode: removeSegmentWithTarget(data.openMode, "点击开门") };
+                }
+
+                const openModeStr = typeof data.openMode === "string" ? data.openMode : "";
+                const silentFace = openModeStr.includes("静默人脸");
+                cameraFunc.setFakeHidden(vm, silentFace);
+
+                Object.assign(DoorArr.form.door, data);
+                uni.setStorageSync("storage_face", DoorArr.form);
+                syncDoorUiFromForm(vm);
+            })
+            .catch(() => { });
+    }
+}
+
+/**
+ * 门禁页定时器
+ */
+export const IntervalFunc = {
+    /**
+     * 开启定时器
+     */
+    open(vm, type) {
+        if (type === "ipAddress") {
+            if (DoorArr.doorInter.ipTimer) return;
+            DoorArr.doorInter.ipTimer = setInterval(() => {
+                sysPlugins.getIpAddress({
+                    success: (res) => {
+                        DoorArr.ipAddress = res;
+                    },
+                    error: () => {
+                        DoorArr.ipAddress = "";
+                    },
+                });
+            }, 1000);
+            return;
+        }
+
+        if (type === "door") {
+            if (DoorArr.doorInter.doorDom) return;
+
+            apiRequest.initDoorEscalation(vm, "eg");
+            DoorArr.doorInter.egEscalation = setInterval(() => {
+                apiRequest.initDoorEscalation(vm, "eg");
+            }, 1000 * 10);
+
+            apiRequest.getDoorList(vm);
+            DoorArr.doorInter.doorDom = setInterval(() => {
+                apiRequest.getDoorList(vm);
+            }, 1000 * 3);
+        }
+    },
+
+    /** 清理定时器 */
+    clear(vm) {
+        if (!vm) return;
+        if (DoorArr.doorInter.doorDom) {
+            clearInterval(DoorArr.doorInter.doorDom);
+            DoorArr.doorInter.doorDom = null;
+        }
+        if (DoorArr.doorInter.egEscalation) {
+            clearInterval(DoorArr.doorInter.egEscalation);
+            DoorArr.doorInter.egEscalation = null;
+        }
+        if (DoorArr.doorInter.meetingEscalation) {
+            clearInterval(DoorArr.doorInter.meetingEscalation);
+            DoorArr.doorInter.meetingEscalation = null;
+        }
+        if (DoorArr.doorInter.meeting) {
+            clearInterval(DoorArr.doorInter.meeting);
+            DoorArr.doorInter.meeting = null;
+        }
+        if (DoorArr.doorInter.ipTimer) {
+            clearInterval(DoorArr.doorInter.ipTimer);
+            DoorArr.doorInter.ipTimer = null;
+        }
+    },
+};

+ 325 - 0
src/pages/door/index.nvue

@@ -0,0 +1,325 @@
+<template>
+  <view class="pageRoot">
+    <image class="bg" :src="state.imgPath || defaultBg" mode="aspectFill"></image>
+
+    <view class="homeCard">
+      <view class="homeTop" @longpress="navigateByKey(this,'setting')">
+        <view class="dateArea">
+          <text class="time1">{{ state.dateTime }}</text>
+          <text class="time2">{{ state.date }}</text>
+        </view>
+        <text class="doorTitle" v-if="state.openMode?.includes('人脸') && !state.openMode?.includes('静默人脸')">{{ state.doorName || "未绑定门禁" }}</text>
+      </view>
+
+      <view class="homeCenter">
+        <view class="centerInfo" v-if="!state.openMode?.includes('人脸') || state.openMode?.includes('静默人脸')" @longpress="navigateByKey(this,'setting')">
+          <text class="infoTitle">{{ state.doorName || "未绑定门禁" }}</text>
+          <text class="remark" v-if="state.remark">{{ state.remark }}</text>
+          <text class="workStatus" v-if="state.workName" :class="[state.workClass]">{{ state.workName }}</text>
+        </view>
+
+        <view class="faceArea" v-if="state.openMode?.includes('人脸')">
+          <view class="faceRing">
+            <door-camera-x
+              ref="doorCam"
+              class="camera"
+              @onResult="cameraFunc.onResult(this, $event)"
+              @result="cameraFunc.onResult(this, $event)"
+              @on-result="cameraFunc.onResult(this, $event)"
+              @onState="cameraFunc.onState(this, $event)"
+              @state="cameraFunc.onState(this, $event)"
+              @on-state="cameraFunc.onState(this, $event)"
+            ></door-camera-x>
+          </view>
+        </view>
+      </view>
+
+      <view class="homeFooter">
+        <view class="btnArea">
+          <text class="iconfont" @click="doorPageUi.parentMessage(this, '点击开门')" v-if="state.openMode?.includes('点击开门')">{{ icons.openDoor }}</text>
+          <text class="iconfont" @click="doorPageUi.parentMessage(this, '密码')" v-if="state.openMode?.includes('密码')">{{ icons.password }}</text>
+        </view>
+      </view>
+    </view>
+
+    <view v-if="popup.show" class="passwordLayer">
+      <oaPassBody :show="popup.show" @change="onDoorPass.change(this, $event)" @close="onDoorPass.close(this, $event)"></oaPassBody>
+    </view>
+
+    <face-verify-popup
+      :show="faceVerifyPopup.show"
+      :success="faceVerifyPopup.success"
+      :face-name="faceVerifyPopup.faceName"
+      :fail-message="faceVerifyPopup.failMessage"
+      :avatar-src="faceVerifyPopup.avatarSrc"
+      @close="FaceVerifyFunc.close(this)"
+    ></face-verify-popup>
+
+    <view class="cornerMeta" v-if="DoorArr.ipAddress || DoorArr.deviceSerial">
+      <text class="cornerText cornerIp" v-if="DoorArr.ipAddress">IP:{{ DoorArr.ipAddress }}</text>
+      <text class="cornerText cornerSn" v-if="DoorArr.deviceSerial">SN:{{ DoorArr.deviceSerial }}</text>
+    </view>
+  </view>
+</template>
+
+<script>
+import oaPassBody from "@/components/oa-passBody/index.vue";
+import {
+  navigateByKey,
+  cameraFunc,
+  onDoorPass,
+  initDoorData,
+  IntervalFunc,
+  clockFunc,
+  FaceVerifyFunc,
+  doorPageUi,
+  syncDeviceSerial,
+  DoorArr,
+} from "./index.js";
+import FaceVerifyPopup from "./components/face-verify-popup.nvue";
+
+const domModule = weex.requireModule('dom');
+domModule .addRule('fontFace', {
+    fontFamily: 'iconfont',
+    src: "url('https://at.alicdn.com/t/c/font_4400427_u9biyws6c8.ttf?t=1776693398678')"
+});
+
+export default {
+  components: {
+    oaPassBody,
+    FaceVerifyPopup,
+  },
+  data() {
+    return {
+      cameraFunc,
+      onDoorPass,
+      FaceVerifyFunc,
+      doorPageUi,
+      DoorArr,
+      popup: {
+        show: false,
+      },
+      faceVerifyPopup: {
+        show: false,
+        success: false,
+        faceName: "",
+        failMessage: "",
+        avatarSrc: "",
+      },
+      defaultBg: "/static/face/img/face_bg.png",
+      thresholds: {
+        strongThreshold: 0.73, // 强阈值:高置信通过
+        weakThreshold: 0.68, // 弱阈值:疑似通过下限
+        minGap: 0.04, // 最小间隔:结果节流
+        analyzeIntervalMs: 500, // 分析间隔(ms):降低占用
+        showFaceBox: true, // 显示人脸框:绘制检测框
+        stopOnSuccess: false, // 成功即停止:命中后停相机
+        previewShape: "circle", // circle / square:原生预览裁剪形状
+        overlayEnabled: true, // 原生叠加层开关(覆盖在相机预览上)
+        overlayStyle: "gif", // gif / ring / none:叠加层样式
+        overlayGifPath: "auto",
+        ttsEnabled: true, // 语音播报总开关(原生)
+        ttsVolume: 100, // 语音播报音量:1-100
+      },
+      state: {
+        dateTime: "",
+        date: "",
+        doorName: "",
+        imgPath: "",
+        openMode: "人脸,点击开门,密码",
+        remark: "",
+        workName: "",
+        workClass: "",
+      },
+      icons: {
+        openDoor: "\ue62c",
+        password: "\ue8b2",
+        setting: "\ue626",
+      },
+    };
+  },
+  onReady() {
+    syncDeviceSerial();
+    clockFunc.start(this);
+    initDoorData(this);
+    IntervalFunc.open(this, "ipAddress");
+    IntervalFunc.open(this, "door");
+    this.$nextTick(() => {
+      cameraFunc.start(this);
+    });
+  },
+  onShow() {
+    syncDeviceSerial();
+    clockFunc.start(this);
+    IntervalFunc.open(this, "ipAddress");
+    IntervalFunc.open(this, "door");
+    this.$nextTick(() => {
+      cameraFunc.start(this);
+    });
+  },
+  onHide() {
+    FaceVerifyFunc.close(this);
+    clockFunc.stop(this);
+    IntervalFunc.clear(this);
+    cameraFunc.stop(this);
+  },
+  methods: {
+    navigateByKey,
+  },
+};
+</script>
+
+<style scoped>
+.pageRoot {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: #0b1020;
+}
+.bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+.homeCard {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  flex-direction: column;
+  justify-content: space-between;
+  padding: 24px;
+}
+.homeTop {
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: flex-start;
+  padding: 10px 10px;
+}
+.dateArea {
+  flex-direction: row;
+  align-items: flex-end;
+}
+.time1 {
+  color: #ffffff;
+  font-size: 50px;
+  font-weight: 700;
+  margin-right: 15px;
+}
+.time2 {
+  color: rgba(255, 255, 255, 0.9);
+  font-size: 22px;
+  padding-bottom: 8px;
+}
+.doorTitle {
+  color: rgba(255, 255, 255, 0.92);
+  font-size: 25px;
+  font-weight: 600;
+  padding-top: 20px;
+}
+.homeCenter {
+  flex: 1;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+.centerInfo {
+  flex-direction: column;
+  align-items: center;
+}
+.infoTitle {
+  color: #fff;
+  font-size: 40px;
+  font-weight: 700;
+  margin-bottom: 30px;
+}
+.remark {
+  color: rgba(255, 255, 255, 0.88);
+  font-size: 25px;
+  text-align: center;
+  margin-bottom: 30px;
+}
+.workStatus {
+  color: #fff;
+  font-size: 28px;
+  padding: 10px 26px;
+  border-radius: 14px;
+}
+.workRed {
+  background-color: #f11e16;
+}
+.workYellow {
+  background-color: #e6a23c;
+}
+.workGreen {
+  background-color: #67c23a;
+}
+.faceArea {
+  flex-direction: row;
+  justify-content: center;
+  align-items: center;
+  margin-top: -180px;
+}
+.faceRing {
+  position: relative;
+  width: 300px;
+  height: 300px;
+  overflow: hidden;
+}
+.camera {
+  width: 300px;
+  height: 300px;
+  border-radius: 150px;
+}
+.homeFooter {
+  flex-direction: row;
+  justify-content: center;
+  padding: 18px 22px;
+}
+.btnArea {
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+}
+.iconfont {
+  font-family: iconfont;
+  font-size: 55px;
+  color: #fff;
+}
+.iconfont+.iconfont{
+  margin-left: 26rpx;
+}
+
+.passwordLayer {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background-color: #474747;
+  z-index: 100074;
+}
+
+.cornerMeta {
+  position: absolute;
+  left: 18px;
+  bottom: 14px;
+  flex-direction: row;
+  align-items: center;
+  flex-wrap: nowrap;
+}
+
+.cornerText {
+  font-size: 18px;
+  color: rgba(255, 255, 255, 0.25);
+}
+
+.cornerIp {
+  margin-right: 14px;
+}
+</style>

+ 1 - 0
src/pages/door/index.vue → src/pages/door/index4.vue

@@ -42,6 +42,7 @@ const { version, webviewStyles } = toRefs(state);
 
 // 初始化
 function init() {
+  controlStore.openInterval("ipAddress"); //定时获取IP地址
   controlStore.initCamera(); //初始化摄像头
   // controlStore.initNfc();//初始化NFC
   controlStore.initData(); //初始化数据

+ 2 - 1
src/pages/door/setting/index.scss

@@ -1,3 +1,4 @@
+.faceStorage-container,
 .doorSetting-container,
 .doorSettingOther-container,
 .doorSettingServe-container,
@@ -70,7 +71,7 @@
 }
 
 @media (min-width: 500px) {
-
+    .faceStorage-container,
     .doorSetting-container,
     .doorSettingOther-container,
     .doorSettingServe-container,

+ 9 - 22
src/pages/door/setting/index.vue

@@ -19,17 +19,9 @@
       <text class="iconfont oaIcon-exit" @click="handleExit()"></text>
 
       <view class="Grid">
-        <view class="Grid-item" @click="handle('serve')">
-          <image class="Grid-item-image" src="@/static/face/img/serveSetting.png"></image>
-          <view class="Grid-item-lable">服务器配置</view>
-        </view>
-        <view class="Grid-item" @click="handle('other')">
-          <image class="Grid-item-image" src="@/static/face/img/otherSetting.png"></image>
-          <view class="Grid-item-lable">门禁配置</view>
-        </view>
         <view class="Grid-item" @click="handle('sysetm')">
           <image class="Grid-item-image" src="@/static/face/img/sysetmSetting.png"></image>
-          <view class="Grid-item-lable">更多配置</view>
+          <view class="Grid-item-lable">系统配置</view>
         </view>
         <view class="Grid-item" @click="handle('public')">
           <image class="Grid-item-image" src="@/static/face/img/sysetmSetting.png"></image>
@@ -39,6 +31,10 @@
           <image class="Grid-item-image" src="@/static/face/img/sysetmSetting.png"></image>
           <view class="Grid-item-lable">测试</view>
         </view>
+        <view class="Grid-item" @click="handle('faceStorage')">
+          <image class="Grid-item-image" src="@/static/face/img/sysetmSetting.png"></image>
+          <view class="Grid-item-lable">人脸数据管理</view>
+        </view>
       </view>
     </template>
   </oa-scroll>
@@ -61,18 +57,12 @@ const state = reactive({});
 const {} = toRefs(state);
 
 function handle(type) {
-  if (type == "serve") {
-    proxy.$tab.navigateTo("/pages/door/setting/serve/index");
-  } else if (type == "other") {
-    if (!controlStore.form.linkUrl) {
-      proxy.$modal.msg("请先配置服务器信息!");
-      return;
-    }
-    proxy.$tab.navigateTo("/pages/door/setting/other/index");
-  } else if (type == "public") {
+  if (type == "public") {
     proxy.$tab.navigateTo("/pages/door/setting/public/index");
   } else if (type == "sysetm") {
     proxy.$tab.navigateTo("/pages/door/setting/system/index");
+  } else if (type == "faceStorage") {
+    proxy.$tab.navigateTo("/pages/door/faceStorage/index");
   }
 }
 
@@ -90,12 +80,9 @@ function startActivity() {
 }
 
 onLoad((options) => {
-  controlStore.initData(); //初始化数据
 });
 
-onShow(() => {
-  controlStore.getDoorList();
-});
+onShow(() => {});
 </script>
 <style lang="scss">
 @import "./index.scss";

+ 0 - 96
src/pages/door/setting/other/index.vue

@@ -1,96 +0,0 @@
-<template>
-  <oa-scroll
-    customClass="doorSettingOther-container scroll-height"
-    :customStyle="{
-      //#ifdef APP-PLUS || MP-WEIXIN
-      height: `calc(100vh - (0px))`,
-      //#endif
-      //#ifdef H5
-      height: `calc(100vh - (0px))`,
-      //#endif
-    }"
-    :refresherLoad="false"
-    :refresherEnabled="false"
-    :refresherDefaultStyle="'none'"
-    :refresherBackground="'#f5f6f7'"
-    :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
-  >
-    <template #default>
-      <text class="iconfont oaIcon-left" @click="handleExit()"></text>
-
-      <view class="mb10">绑定门禁</view>
-      <view class="flex">
-        <uni-data-select
-          v-model="controlStore.form.door.id"
-          :localdata="controlStore.doorList"
-          placeholder="门禁(必选)"
-          mode="none"
-          :clear="false"
-          @change="(e) => controlStore.handleSelectChange({ value: e, type: '绑定门禁' })"
-        >
-        </uni-data-select>
-      </view>
-    </template>
-  </oa-scroll>
-</template>
-<script setup>
-/*----------------------------------依赖引入-----------------------------------*/
-import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
-import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
-/*----------------------------------接口引入-----------------------------------*/
-/*----------------------------------组件引入-----------------------------------*/
-/*----------------------------------store引入-----------------------------------*/
-import { controlStores } from "@/store/modules/index";
-/*----------------------------------公共方法引入-----------------------------------*/
-const { proxy } = getCurrentInstance();
-const controlStore = controlStores();
-/*----------------------------------公共变量-----------------------------------*/
-const state = reactive({});
-const {} = toRefs(state);
-
-function handleExit() {
-  if (controlStore.isDataChange) {
-    proxy.$modal.loading("保存中");
-    uni.setStorageSync("storage_face", controlStore.form);
-    controlStore.initData(); //初始化数据
-    setTimeout(() => {
-      proxy.$tab.navigateBack(1);
-      proxy.$modal.closeLoading();
-    }, 1000);
-  } else {
-    proxy.$tab.navigateBack(1);
-  }
-}
-
-onLoad((options) => {
-  controlStore.initData(); //初始化数据
-});
-
-onShow(() => {
-  controlStore.getDoorList();
-});
-</script>
-<style lang="scss">
-@import "../index.scss";
-
-:deep() {
-  .uni-stat-box {
-    background-color: transparent !important;
-    color: black !important;
-
-    .uni-select {
-      padding-left: 0px !important;
-      padding-right: 0px !important;
-
-      &__input-text {
-        color: #ffffff !important;
-      }
-
-      &__input-placeholder {
-        font-size: 15px !important;
-        color: #c0c4cc !important;
-      }
-    }
-  }
-}
-</style>

+ 2 - 41
src/pages/door/setting/public/index.vue

@@ -17,56 +17,17 @@
   >
     <template #default>
       <text class="iconfont oaIcon-left" @click="handleExit()"></text>
-      <u-cell-group>
-        <!-- #ifdef APP-PLUS -->
-        <u-cell title="WiFi管理" :value="1">
-          <template #value> <view class="u-cell__value">点击设置</view> <u-icon class="iconfont" name="arrow-right"></u-icon> </template>
-        </u-cell>
-        <u-cell title="IP地址">
-          <template #value> </template>
-        </u-cell>
-        <!-- #endif -->
-      </u-cell-group>
     </template>
   </oa-scroll>
-
-  <oa-upgrade ref="oaUpgradeRef" :themesColor="proxy.$settingStore.themeColor.color" />
 </template>
 <script setup>
-/*----------------------------------依赖引入-----------------------------------*/
-import config from "@/config";
-import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
-import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
-/*----------------------------------接口引入-----------------------------------*/
-/*----------------------------------组件引入-----------------------------------*/
-/*----------------------------------store引入-----------------------------------*/
-import { controlStores, commonStores } from "@/store/modules/index";
-/*----------------------------------公共方法引入-----------------------------------*/
-const { proxy } = getCurrentInstance();
-const controlStore = controlStores();
-const commonStore = commonStores();
-/*----------------------------------公共变量-----------------------------------*/
-const state = reactive({
-  version: computed(() => {
-    return config.appInfo.version;
-  }),
-});
-const { version } = toRefs(state);
+import { getCurrentInstance } from "vue";
 
-// 按钮点击事件
-function handleToSetting(type) {
-  if (type == "senior") {
-    proxy.$tab.navigateTo("/pages/door/setting/system/senior");
-  }
-}
+const { proxy } = getCurrentInstance();
 
 function handleExit() {
   proxy.$tab.navigateBack(1);
 }
-
-onLoad((options) => {
-  controlStore.initData(); //初始化数据
-});
 </script>
 <style lang="scss" scoped>
 @import "../index.scss";

+ 0 - 71
src/pages/door/setting/serve/index.vue

@@ -1,71 +0,0 @@
-<template>
-  <oa-scroll
-    customClass="doorSettingServe-container scroll-height"
-    :customStyle="{
-      //#ifdef APP-PLUS || MP-WEIXIN
-      height: `calc(100vh - (0px))`,
-      //#endif
-      //#ifdef H5
-      height: `calc(100vh - (0px))`,
-      //#endif
-    }"
-    :refresherLoad="false"
-    :refresherEnabled="false"
-    :refresherDefaultStyle="'none'"
-    :refresherBackground="'#f5f6f7'"
-    :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
-  >
-    <template #default>
-      <text class="iconfont oaIcon-left" @click="handleExit()"></text>
-
-      <view class="mb10 required">服务器地址</view>
-      <view class="mb20">
-        <u-input v-model="controlStore.form.linkUrl" placeholder="服务器地址(必填)" border="bottom" color="white" @change="handleChange" style="padding: 6px 0px" />
-      </view>
-
-      <view class="mb10">服务器端口</view>
-      <view class="mb20">
-        <u-input v-model="controlStore.form.port" placeholder="服务器端口(非必填)" border="bottom" color="white" @change="handleChange" style="padding: 6px 0px" />
-      </view>
-    </template>
-  </oa-scroll>
-</template>
-<script setup>
-/*----------------------------------依赖引入-----------------------------------*/
-import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
-import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
-/*----------------------------------接口引入-----------------------------------*/
-/*----------------------------------组件引入-----------------------------------*/
-/*----------------------------------store引入-----------------------------------*/
-import { controlStores } from "@/store/modules/index";
-/*----------------------------------公共方法引入-----------------------------------*/
-const { proxy } = getCurrentInstance();
-const controlStore = controlStores();
-/*----------------------------------公共变量-----------------------------------*/
-const state = reactive({});
-const {} = toRefs(state);
-
-function handleChange(e) {
-  controlStore.isDataChange = true;
-}
-
-function handleExit() {
-  if (controlStore.isDataChange) {
-    proxy.$modal.loading("保存中");
-    controlStore.serveChange();
-    setTimeout(() => {
-      proxy.$tab.navigateBack(1);
-      proxy.$modal.closeLoading();
-    }, 1000);
-  } else {
-    proxy.$tab.navigateBack(1);
-  }
-}
-
-onLoad((options) => {
-  controlStore.initData(); //初始化数据
-});
-</script>
-<style lang="scss">
-@import "../index.scss";
-</style>

+ 54 - 10
src/pages/door/setting/system/index.vue

@@ -21,34 +21,77 @@
         <!-- #ifdef APP-PLUS || H5 -->
         <u-cell title="软件版本号" :value="version"></u-cell>
         <u-cell title="清除缓存" @click="proxy.$setting.clearCache()">
-          <template #value> <view class="iconfont oaIcon-qingchu"></view> </template>
+          <template #value>
+            <view class="iconfont oaIcon-qingchu"></view>
+          </template>
         </u-cell>
         <u-cell title="检查更新" @click="handleToUpgrade()">
-          <template #value> <view class="iconfont oaIcon-jianchagengxin"></view> </template>
+          <template #value>
+            <view class="iconfont oaIcon-jianchagengxin"></view>
+          </template>
         </u-cell>
         <!-- #endif -->
         <!-- #ifdef APP-PLUS -->
         <u-cell title="设备型号" :value="proxy.$sys.getModel()"></u-cell>
         <u-cell title="系统版本" :value="proxy.$sys.getVersion()"></u-cell>
         <u-cell title="设备序列号" :value="proxy.$sys.getSerial()"></u-cell>
+        <u-cell title="网络" @click="handleToSetting('network')">
+          <template #value>
+            <view class="u-cell__value">点击设置</view>
+            <u-icon class="iconfont" name="arrow-right"></u-icon>
+          </template>
+        </u-cell>
         <u-cell title="高级" @click="handleToSetting('senior')">
-          <template #value> <view class="u-cell__value">点击设置</view> <u-icon class="iconfont" name="arrow-right"></u-icon> </template>
+          <template #value>
+            <view class="u-cell__value">点击设置</view>
+            <u-icon class="iconfont" name="arrow-right"></u-icon>
+          </template>
         </u-cell>
-        <u-cell title="设备重启" @click="proxy.$ph.reboot()">
-          <template #value> <view class="iconfont oaIcon-zhongqi1"></view> </template>
+        <u-cell
+          title="设备重启"
+          @click="
+            proxy.$modal.confirm('是否重启设备?').then((e) => {
+              proxy.$sys.reboot();
+            })
+          "
+        >
+          <template #value>
+            <view class="iconfont oaIcon-zhongqi1"></view>
+          </template>
         </u-cell>
         <!-- #endif -->
       </u-cell-group>
     </template>
   </oa-scroll>
 
-  <oa-upgrade ref="oaUpgradeRef" :themesColor="proxy.$settingStore.themeColor.color" />
+  <oa-upgrade
+    ref="oaUpgradeRef"
+    :themesColor="proxy.$settingStore.themeColor.color"
+  />
 </template>
 <script setup>
 /*----------------------------------依赖引入-----------------------------------*/
 import config from "@/config";
-import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
-import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
+import {
+  onLoad,
+  onShow,
+  onReady,
+  onHide,
+  onLaunch,
+  onUnload,
+  onNavigationBarButtonTap,
+  onPageScroll,
+} from "@dcloudio/uni-app";
+import {
+  ref,
+  reactive,
+  computed,
+  getCurrentInstance,
+  toRefs,
+  inject,
+  nextTick,
+  watch,
+} from "vue";
 /*----------------------------------接口引入-----------------------------------*/
 /*----------------------------------组件引入-----------------------------------*/
 /*----------------------------------store引入-----------------------------------*/
@@ -80,7 +123,9 @@ function handleToUpgrade() {
 
 // 按钮点击事件
 function handleToSetting(type) {
-  if (type == "senior") {
+  if (type == "network") {
+    proxy.$tab.navigateTo("/pages/door/setting/system/network");
+  } else if (type == "senior") {
     proxy.$tab.navigateTo("/pages/door/setting/system/senior");
   }
 }
@@ -90,7 +135,6 @@ function handleExit() {
 }
 
 onLoad((options) => {
-  controlStore.initData(); //初始化数据
 });
 </script>
 <style lang="scss" scoped>

+ 76 - 0
src/pages/door/setting/system/network.vue

@@ -0,0 +1,76 @@
+<template>
+  <oa-scroll
+    customClass="doorSettingSystem-container scroll-height"
+    :customStyle="{
+      //#ifdef APP-PLUS || MP-WEIXIN
+      height: `calc(100vh - (0px))`,
+      //#endif
+      //#ifdef H5
+      height: `calc(100vh - (0px))`,
+      //#endif
+    }"
+    :refresherLoad="false"
+    :refresherEnabled="false"
+    :refresherDefaultStyle="'none'"
+    :refresherBackground="'#f5f6f7'"
+    :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
+  >
+    <template #default>
+      <text class="iconfont oaIcon-left" @click="handleExit()"></text>
+      <u-cell-group>
+        <!-- #ifdef APP-PLUS -->
+        <u-cell title="网络设置" :value="1">
+          <template #value>
+            <view class="u-cell__value" @click="proxy.$settingStore.openSystemNetwork()">点击设置</view>
+            <u-icon class="iconfont" name="arrow-right"></u-icon>
+          </template>
+        </u-cell>
+        <u-cell title="IP地址" :value="ipAddress || '-'"></u-cell>
+        <!-- #endif -->
+      </u-cell-group>
+    </template>
+  </oa-scroll>
+
+  <oa-upgrade ref="oaUpgradeRef" :themesColor="proxy.$settingStore.themeColor.color" />
+</template>
+<script setup>
+/*----------------------------------依赖引入-----------------------------------*/
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import { reactive, getCurrentInstance, toRefs } from "vue";
+/*----------------------------------接口引入-----------------------------------*/
+/*----------------------------------组件引入-----------------------------------*/
+/*----------------------------------store引入-----------------------------------*/
+/*----------------------------------公共方法引入-----------------------------------*/
+const { proxy } = getCurrentInstance();
+/*----------------------------------公共变量-----------------------------------*/
+const state = reactive({
+  ipAddress: "",
+});
+const { ipAddress } = toRefs(state);
+
+function refreshIpAddress() {
+  proxy.$sys.getIpAddress({
+    success: (res) => {
+      state.ipAddress = res;
+    },
+    error: () => {
+      state.ipAddress = "";
+    },
+  });
+}
+
+function handleExit() {
+  proxy.$tab.navigateBack(1);
+}
+
+onLoad(() => {
+  refreshIpAddress();
+});
+
+onShow(() => {
+  refreshIpAddress();
+});
+</script>
+<style lang="scss" scoped>
+@import "../index.scss";
+</style>

+ 17 - 7
src/pages/door/setting/system/senior.vue

@@ -21,22 +21,22 @@
         <u-cell title="测试内置硬件" @click="text()"></u-cell>
         <u-cell title="继电器">
           <template #value>
-            <u-switch v-model="commonStore.doorArray.systemSeeting.relayControl" size="15" @change="proxy.$ph.relayControl"></u-switch>
+            <u-switch v-model="commonStore.doorArray.systemSeeting.relayControl" size="15" @change="proxy.$sys.relayControl"></u-switch>
           </template>
         </u-cell>
         <u-cell title="隐藏导航栏">
           <template #value>
-            <u-switch v-model="commonStore.doorArray.systemSeeting.navBarNew" size="15" @change="proxy.$ph.navigationBar"></u-switch>
+            <u-switch v-model="commonStore.doorArray.systemSeeting.navBarNew" size="15" @change="proxy.$sys.navigationBar"></u-switch>
           </template>
         </u-cell>
         <u-cell title="隐藏状态栏">
           <template #value>
-            <u-switch v-model="commonStore.doorArray.systemSeeting.statusBar" size="15" @change="proxy.$ph.statusBar"></u-switch>
+            <u-switch v-model="commonStore.doorArray.systemSeeting.statusBar" size="15" @change="proxy.$sys.statusBar('set', $event)"></u-switch>
           </template>
         </u-cell>
         <u-cell title="禁止状态栏下拉">
           <template #value>
-            <u-switch v-model="commonStore.doorArray.systemSeeting.statusBarDrop" size="15" @change="proxy.$ph.statusBarDrop"></u-switch>
+            <u-switch v-model="commonStore.doorArray.systemSeeting.statusBarDrop" size="15" @change="proxy.$sys.statusBarDrop"></u-switch>
           </template>
         </u-cell>
         <u-cell title="退出应用" @click="Cancel()">
@@ -49,7 +49,7 @@
 <script setup>
 /*----------------------------------依赖引入-----------------------------------*/
 import config from "@/config";
-import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
+import { onLoad, onShow } from "@dcloudio/uni-app";
 import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
 /*----------------------------------接口引入-----------------------------------*/
 /*----------------------------------组件引入-----------------------------------*/
@@ -83,8 +83,18 @@ function Cancel() {
   //#endif
 }
 
-onLoad((options) => {
-  controlStore.initData(); //初始化数据
+/** 从系统读取状态栏是否可见,同步「隐藏状态栏」开关(可见则关隐藏,不可见则开隐藏) */
+function syncStatusBarSwitchFromDevice() {
+  //#ifdef APP-PLUS
+  const visible = proxy.$sys.statusBar("get");
+  if (typeof visible === "boolean") {
+    commonStore.doorArray.systemSeeting.statusBar = !visible;
+  }
+  //#endif
+}
+
+onShow(() => {
+  syncStatusBarSwitchFromDevice();
 });
 </script>
 <style lang="scss" scoped>

+ 2 - 4
src/pages/meeting/index.vue

@@ -3,7 +3,6 @@
 </template>
 <script setup>
 /*----------------------------------依赖引入-----------------------------------*/
-import config from "@/config";
 import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
 import { ref, reactive, computed, getCurrentInstance, toRefs, inject, nextTick, watch } from "vue";
 /*----------------------------------接口引入-----------------------------------*/
@@ -25,13 +24,12 @@ const { webviewStyles } = toRefs(state);
 // 初始化
 function init() {
   controlStore.openInterval("ipAddress"); //定时获取IP地址
-  controlStore.pageFunction = ["会议"];
   controlStore.initCamera(); //初始化摄像头
-  // controlStore.initNfc();
+  controlStore.initNfc(); //初始化NFC
   controlStore.initData(); //初始化数据
   controlStore.openInterval("meeting"); //定时获取会议信息
 
-  controlStore.doorControl(false); //关闭门禁
+  proxy.$sys.relayControl(false); // 关闭门禁(继电器)
 }
 
 /**

+ 12 - 2
src/pages/meeting/setting/index.vue

@@ -25,7 +25,7 @@
         <u-cell-group>
           <u-cell title="门禁开关">
             <template #value>
-              <u-switch v-model="setting.doorStatus" size="15" @change="controlStore.doorControl"></u-switch>
+              <u-switch v-model="setting.doorStatus" size="15" @change="proxy.$sys.relayControl"></u-switch>
             </template>
           </u-cell>
           <u-cell title="导航栏显示">
@@ -33,6 +33,8 @@
               <u-switch v-model="setting.navBarNew" size="15" @change="navBarNewChange"></u-switch>
             </template>
           </u-cell>
+          <u-cell title="串口通讯" @click="SerialPortPage()"></u-cell>
+          <u-cell title="M11读卡器测试" @click="CardReaderTestPage()"></u-cell>
           <u-cell title="软件版本号" :value="version"></u-cell>
           <u-cell title="IP" :value="controlStore.ipAddress || '-'"></u-cell>
           <u-cell title="设备型号" :value="sysPlugins.getDeviceInfo().model || '-'"></u-cell>
@@ -42,7 +44,7 @@
               <view class="iconfont oaIcon-jianchagengxin menu-item-icon mr2" style="color: #2979ff"></view>
             </template>
           </u-cell>
-          <u-cell title="设备重启" @click="proxy.$yx.rebootNow()">
+          <u-cell title="设备重启" @click="proxy.$modal.confirm('是否重启设备?').then((e) => { proxy.$sys.reboot() })">
             <template #value>
               <u-icon name="reload" color="#2979ff" size="20"></u-icon>
             </template>
@@ -82,6 +84,14 @@ const state = reactive({
 });
 const { version, setting } = toRefs(state);
 
+function SerialPortPage() {
+  proxy.$tab.navigateTo("/pages/meeting/setting/SerialPort");
+}
+
+function CardReaderTestPage() {
+  proxy.$tab.navigateTo("/pages/meeting/setting/CardReaderTest");
+}
+
 /**
  * @退出
  */

+ 1 - 55
src/plugins/device/ph.plugins.js

@@ -1,58 +1,4 @@
-import modal from "../modal.plugins";
-
 /**
  * @海清硬件api
  */
-export default {
-    /**
-     * @继电器控制
-     * @param {状态值} status true/false
-     */
-    relayControl(status) {
-        //#ifdef APP-PLUS
-        const phPlugin = uni.requireNativePlugin("phPlugin");
-        phPlugin.relay_Control(status);
-        //#endif
-    },
-    /**
-     * @导航栏显示隐藏
-     * @param {状态值} status true/false
-     */
-    navigationBar(status) {
-        //#ifdef APP-PLUS
-        const phPlugin = uni.requireNativePlugin("phPlugin");
-        phPlugin.navigationBar(status);
-        //#endif
-    },
-    /**
-     * @状态显示隐藏控制
-     * @param {状态值} status true/false
-     */
-    statusBar(status) {
-        //#ifdef APP-PLUS
-        const phPlugin = uni.requireNativePlugin("phPlugin");
-        phPlugin.statusBar(status);
-        //#endif
-    },
-    /**
-     * @状态面板下拉控制
-     * @param {状态值} status true/false
-     */
-    statusBarDrop(status) {
-        //#ifdef APP-PLUS
-        const phPlugin = uni.requireNativePlugin("phPlugin");
-        phPlugin.statusBarDrop(status);
-        //#endif
-    },
-    /**
-    * @设备重启
-    */
-    reboot() {
-        //#ifdef APP-PLUS
-        modal.confirm("是否重启设备?").then((e) => {
-            const phPlugin = uni.requireNativePlugin("phPlugin");
-            phPlugin.reboot();
-        })
-        //#endif
-    },
-};
+export default {};

+ 106 - 18
src/plugins/device/sys.plugins.js

@@ -10,9 +10,23 @@ export default {
      * @isOpen  开关门(1开、2常闭、3常开)
      */
     openDoor(isOpen, timeout) {
-        // 智能会议
-        if (config.appInfo.appid === "__UNI__F3963F8") {
-            //#ifdef APP-PLUS
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (sysPlugin.getManufacturer() == "rockchip") {
+            // 海清设备
+            const phPlugin = uni.requireNativePlugin("phPlugin");
+            if (isOpen == 1) {
+                phPlugin.relay_Control(true);
+                setTimeout(() => {
+                    phPlugin.relay_Control(false);
+                }, timeout);
+            } else if (isOpen == 2) {
+                phPlugin.relay_Control(false);
+            } else if (isOpen == 3) {
+                phPlugin.relay_Control(true);
+            }
+        } else if (sysPlugin.getManufacturer() == "yuxian") {
+            // 武汉智企
             const yxPlugin = uni.requireNativePlugin("yxPlugin");
             if (isOpen == 1) {
                 yxPlugin.setDoor("开");
@@ -24,24 +38,98 @@ export default {
             } else if (isOpen == 3) {
                 yxPlugin.setDoor("开");
             }
-            //#endif
+        } else {
+            return
         }
-        // 智能门禁
-        else if (config.appInfo.appid === "__UNI__8D6E9FD") {
-            //#ifdef APP-PLUS
+        //#endif
+    },
+    /**
+     * @继电器控制
+     * @param {状态值} status true/false
+     */
+    relayControl(status) {
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (sysPlugin.getManufacturer() == "rockchip") {
+            // 海清设备
             const phPlugin = uni.requireNativePlugin("phPlugin");
-            if (isOpen == 1) {
-                phPlugin.relay_Control(true);
-                setTimeout(() => {
-                    phPlugin.relay_Control(false);
-                }, timeout);
-            } else if (isOpen == 2) {
-                phPlugin.relay_Control(false);
-            } else if (isOpen == 3) {
-                phPlugin.relay_Control(true);
-            }
-            //#endif
+            phPlugin.relay_Control(status);
+        } else if (sysPlugin.getManufacturer() == "yuxian") {
+            // 武汉智企
+            const yxPlugin = uni.requireNativePlugin("yxPlugin");
+            yxPlugin.setDoor(status == false ? "关" : "开");
+        } else {
+            return
         }
+        //#endif
+    },
+    /**
+     * @导航栏显示隐藏
+     * @param {状态值} status true/false
+     */
+    navigationBar(status) {
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (sysPlugin.getManufacturer() == "rockchip") {
+            // 海清设备
+            const phPlugin = uni.requireNativePlugin("phPlugin");
+            phPlugin.navigationBar(status);
+        } else if (sysPlugin.getManufacturer() == "yuxian") {
+            // 武汉智企
+            const yxPlugin = uni.requireNativePlugin("yxPlugin");
+            yxPlugin.setNavBarNew(!status);
+        } else {
+            return
+        }
+        //#endif
+    },
+    /**
+     * @设置状态栏显示隐藏
+     * @param {类型} type set:设置 get:获取
+     * @param {状态值} status true/false
+     */
+    statusBar(type, status) {
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (type == "set") {
+            sysPlugin.setStaBar(!status);
+        } else if (type == "get") {
+            return sysPlugin.getStaBarVisible();
+        }
+        //#endif
+    },
+    /**
+     * @状态面板下拉控制
+     * @param {状态值} status true/false
+     */
+    statusBarDrop(status) {
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (sysPlugin.getManufacturer() == "rockchip") {
+            // 海清设备
+            const phPlugin = uni.requireNativePlugin("phPlugin");
+            phPlugin.statusBarDrop(status);
+        } else if (sysPlugin.getManufacturer() == "yuxian") {
+            // 武汉智企
+        } else {
+            return
+        }
+        //#endif
+    },
+    /**
+     * @设备重启 
+    */
+    reboot() {
+        //#ifdef APP-PLUS
+        const sysPlugin = uni.requireNativePlugin("sysPlugin");
+        if (sysPlugin.getManufacturer() == "rockchip") {
+            const phPlugin = uni.requireNativePlugin("phPlugin");
+            phPlugin.reboot();
+        } else if (sysPlugin.getManufacturer() == "yuxian") {
+            const yxPlugin = uni.requireNativePlugin("yxPlugin");
+            yxPlugin.rebootNow();
+        }
+        //#endif
     },
     /**
      * @获取IP地址

+ 0 - 9
src/plugins/device/yx.plugins.js

@@ -21,15 +21,6 @@ export default {
         yxPlugin.setLed(value);
         //#endif
     },
-    /**
-     * @设备重启 
-    */
-    rebootNow() {
-        //#ifdef APP-PLUS
-        const yxPlugin = uni.requireNativePlugin("yxPlugin");
-        yxPlugin.rebootNow();
-        //#endif
-    },
     /**
      * @隐藏导航栏
      */

+ 28 - 10
src/static/face/door.html

@@ -4,6 +4,18 @@
 <head>
     <meta charset="utf-8">
     <title>人脸识别</title>
+    <!-- 按当前 HTML 所在目录设置 base,避免 web-view 下 ./js 解析到错误路径导致 face.js 未执行 -->
+    <script>
+        (function () {
+            try {
+                var p = window.location.pathname || "";
+                var i = p.lastIndexOf("/");
+                if (i >= 0) {
+                    document.write('<base href="' + p.substring(0, i + 1).replace(/"/g, "") + '">');
+                }
+            } catch (e) {}
+        })();
+    </script>
     <script type="text/javascript" src="./js/tracking.js"></script>
     <script type="text/javascript" src="./js/face_data/face.js"></script>
     <script type="text/javascript" src="./js/face_data/eye.js"></script>
@@ -128,7 +140,7 @@
     <div id="face-container" class="face-container home-card">
         <!-- 背景图片 -->
         <div class="home-card-image"
-            :style="{background: `url(${state.imgPath ? state.imgPath :'img/face_bg.png'}) no-repeat`,backgroundSize: '100% 100%'}">
+            :style="{backgroundImage: `url('${state.imgPath || 'img/face_bg.png'}')`, backgroundSize: '100% 100%', backgroundRepeat: 'no-repeat'}">
         </div>
         <!-- 顶部内容区域 -->
         <div class="home-card-top">
@@ -136,16 +148,16 @@
                 <span class="time1">{{ state.dateTime }}</span>
                 <span class="time2">{{ state.date }}</span>
             </div>
-            <div class="title" v-if="state.openMode.includes('人脸')">{{ state.doorName || '未绑定门禁' }}</div>
+            <div class="title" v-if="state.openMode && state.openMode.includes('人脸')">{{ state.doorName || '未绑定门禁' }}</div>
         </div>
         <!-- 人脸内容区域 -->
         <div class="home-card-center">
-            <div class="date" id="configDialog1" v-if="!state.openMode.includes('人脸')">
+            <div class="date" id="configDialog1" v-if="!state.openMode || !state.openMode.includes('人脸')">
                 <div class="title">{{ state.doorName || '未绑定门禁' }}</div>
                 <div class="remark" v-if="state.remark">{{ state.remark }}</div>
-                <div class="workStatus" :class="state.workClass">{{ state.workName }}</div>
+                <div class="workStatus" :class="state.workClass" v-if="state.workName">{{ state.workName }}</div>
             </div>
-            <div class="face" v-if="state.openMode.includes('人脸')">
+            <div class="face" v-if="state.openMode && state.openMode.includes('人脸')">
                 <!-- height="1564" -->
                 <video id="video" width="300" height="300" style="width:40vh;height:40vh" preload autoplay loop
                     muted></video>
@@ -157,8 +169,8 @@
         <!-- 底部内容区域 -->
         <div class="home-card-footer">
             <div class="btnArea">
-                <i class="iconfont oa-dianji" @click="parentMessage('点击开门')" v-if="state.openMode.includes('点击开门')"></i>
-                <i class="iconfont oa-mima" @click="parentMessage('密码')" v-if="state.openMode.includes('密码')"></i>
+                <i class="iconfont oa-dianji" @click="parentMessage('点击开门')" v-if="state.openMode && state.openMode.includes('点击开门')"></i>
+                <i class="iconfont oa-mima" @click="parentMessage('密码')" v-if="state.openMode && state.openMode.includes('密码')"></i>
             </div>
         </div>
     </div>
@@ -205,10 +217,16 @@
                     that.state.imgPath = event.imgPath
                     that.state.openMode = event.openMode
                     that.state.remark = event.remark
-                    that.state.workName = that.workStatusData.filter(item => item.value == event.workStatus)[0].label;
-                    that.state.workClass = that.workStatusData.filter(item => item.value == event.workStatus)[0].class;
+                    var workStatusItem = that.workStatusData.find(item => item.value == event.workStatus);
+                    if (workStatusItem) {
+                        that.state.workName = workStatusItem.label;
+                        that.state.workClass = workStatusItem.class;
+                    } else {
+                        that.state.workName = '';
+                        that.state.workClass = '';
+                    }
 
-                    if (event.openMode.includes("人脸")) {
+                    if (event.openMode && event.openMode.includes("人脸")) {
                         that.tracker == null ? that.initVido() : undefined
                     } else {
                         that.tracker != null ? that.closeFace() : undefined

+ 0 - 360
src/static/face/door1.html

@@ -1,360 +0,0 @@
-<!doctype html>
-<html>
-
-<head>
-    <meta charset="utf-8">
-    <title>人脸识别</title>
-    <script type="text/javascript" src="./js/tracking.js"></script>
-    <script type="text/javascript" src="./js/face_data/face.js"></script>
-    <script type="text/javascript" src="./js/face_data/eye.js"></script>
-    <script type="text/javascript" src="./js/face_data/mouth.js"></script>
-    <script type="text/javascript" src="./js/jquery-2.2.1.min.js"></script>
-    <!-- VUE3 的 SDK -->
-    <script type="text/javascript" src="./js/vue.global.prod.js"></script>
-    <!-- uni 的 SDK -->
-    <script type="text/javascript" src="./js/uni.webview.1.5.4.js"></script>
-    <!-- 全局区域样式 -->
-    <link rel="stylesheet" href="./css/door_homeCard.css">
-    <!-- 中心区域样式 -->
-    <link rel="stylesheet" href="./css/door_homeCardCenter.css">
-    <!-- 底部区域样式 -->
-    <link rel="stylesheet" href="./css/door_homeCardFooter.css">
-    <style>
-        @media (min-width: 768px) {
-            .home-card-center>.date {
-                font-size: 4rem;
-            }
-
-            .home-card-footer {
-                font-size: 2.5rem !important;
-                margin-bottom: 3rem !important;
-            }
-
-            .home-card-footer .date .time1 {
-                font-size: 3rem !important;
-                margin-right: 2rem !important;
-            }
-
-            .home-card-footer .date .time2 {
-                font-size: 2rem !important;
-            }
-
-            .home-card-footer .date .title {
-                margin-top: 1rem !important;
-            }
-        }
-    </style>
-</head>
-
-<body>
-    <div id="face-container" class="face-container home-card">
-        <!-- 背景图片 -->
-        <div class="home-card-image"
-            :style="{background: `url(${state.imgPath ? state.imgPath :'img/face_bg.png'}) no-repeat`,backgroundSize: '100% 100%'}">
-        </div>
-
-        <!-- 人脸内容区域 -->
-        <div class="home-card-center" id="home-card-center">
-            <div class="date" id="configDialog1" style="display: none;">
-                <div class="title">{{ state.doorName || '未绑定门禁' }}</div>
-            </div>
-            <div class="face">
-                <!-- height="1564" -->
-                <video id="video" width="300" height="300" style="width:40vh;height:40vh" preload autoplay loop
-                    muted></video>
-                <canvas id="myCanvas" width="300" height="300" style="width:40vh;height:40vh"></canvas>
-                <!-- 人脸特效区域 -->
-                <div id="specialEffects" class="specialEffects"></div>
-            </div>
-        </div>
-        <!-- 底部内容区域 -->
-        <div class="home-card-footer">
-            <div class="date" id="configDialog2">
-                <span class="time1">{{ state.dateTime }}</span>
-                <span class="time2">{{ state.date }}</span>
-                <div class="title">{{ state.doorName || '未绑定门禁' }}</div>
-            </div>
-            <div class="qrCode">
-                <!-- <div class="buttom">打开二维码</div> -->
-                <div class="buttom" @click="parentMessage('点击开门')">点击开门</div>
-            </div>
-        </div>
-    </div>
-    <script>
-        // 创建Vue实例
-        Vue.createApp({
-            components: {},
-            emits: [],
-            props: {},
-            data() {
-                return {
-                    flag: true,
-                    time: 1000,
-                    tracker: null,
-                    trackerTask: null,
-                    state: {
-                        date: null,
-                        dateTime: null,
-                        doorName: null,
-                        imgPath: null,
-                        openMode: null,
-                        remark: null,
-                    },
-                    timeOutEvent: 0,
-                    inter: {
-                        dateDom: null
-                    },
-                };
-            },
-            computed: {},
-            methods: {
-                // 初始化数据
-                initData(event) {
-                    var that = this;
-                    that.state.doorName = event.deviceName
-                    that.state.imgPath = event.imgPath
-                    that.state.openMode = event.openMode
-                    that.state.remark = event.remark
-
-                    if (event.openMode.includes("人脸")) {
-                        $('.home-card-center .face').css('display', 'block')
-                        $('.home-card-center .date').css('display', 'none')
-                        $('.home-card-footer .date .title').css('display', 'block')
-                        that.tracker == null ? that.initVido() : undefined
-                    } else {
-                        $('.home-card-center .face').css('display', 'none')
-                        $('.home-card-center .date').css('display', 'block')
-                        $('.home-card-footer .date .title').css('display', 'none')
-                        that.tracker != null ? that.closeFace() : undefined
-                    }
-
-                    if (event.openMode.includes("点击开门")) {
-                        $('.home-card-footer .qrCode').css('display', 'block')
-                    } else {
-                        $('.home-card-footer .qrCode').css('display', 'none')
-                    }
-                },
-                // 初始化事件
-                initHandle() {
-                    var that = this;
-
-                    $("#configDialog1,#configDialog2").on({
-                        touchstart: function (e) {
-                            that.timeOutEvent = setTimeout(() => {
-                                that.longPress()
-                            }, 1000);
-                            e.preventDefault();
-                        },
-                        touchmove: function () {
-                            clearTimeout(that.timeOutEvent);
-                            that.timeOutEvent = 0;
-                        },
-                        touchend: function () {
-                            clearTimeout(that.timeOutEvent);
-                            if (that.timeOutEvent != 0) {
-                                console.log("你这是点击,不是长按");
-                            }
-                            return false;
-                        }
-                    })
-                },
-                // 初始化摄像头
-                initVido() {
-                    var that = this;
-
-                    var video = document.getElementById("video");//视频dom
-                    video.style.transform = 'scaleX(-1)';//视频翻转(1.水平翻转-scaleX(-1) 2.垂直翻转-scaleY(-1))
-                    var canvas = document.getElementById('myCanvas');//画布dom
-                    canvas.style.transform = 'scaleX(-1)';//画布翻转(1.水平翻转-scaleX(-1) 2.垂直翻转-scaleY(-1))
-                    var context = canvas.getContext('2d');
-                    that.tracker = new tracking.ObjectTracker(['face']);//'face', 'eye', 'mouth'
-                    that.tracker.setInitialScale(4); //设置识别的放大比例
-                    that.tracker.setStepSize(2);//设置步长
-                    that.tracker.setEdgesDensity(0.1);//边缘密度
-                    //启动摄像头,并且识别视频内容
-                    that.trackerTask = tracking.track('#video', that.tracker, {
-                        camera: true,
-                    });
-
-                    that.tracker.on('track', function (event) {
-                        // console.log(event.data.length)
-                        if (that.flag) {
-                            // console.log("拍照");
-                            that.state.faceImgState = false;
-                            context.drawImage(video, 0, 0, video.width, video.height);
-                            that.saveAsLocalImage()
-                            // that.capturePartialImage(rect.x, rect.y, rect.width, rect.height);
-                            context.clearRect(0, 0, canvas.width, canvas.height);
-                            that.flag = false;
-                        } else {
-                            //console.log("冷却中");
-                        }
-
-                        if (event.data.length === 0) {
-                            // console.log('未检测到人脸')
-                            context.clearRect(0, 0, canvas.width, canvas.height);
-                        } else if (event.data.length > 1) {
-                            // console.log('检测到多张人脸')
-                            context.clearRect(0, 0, canvas.width, canvas.height);
-                        } else {
-                            context.clearRect(0, 0, canvas.width, canvas.height);
-                            event.data.forEach(function (rect) {
-                                context.strokeStyle = '#409eff';
-                                context.strokeRect(rect.x, rect.y, rect.width, rect.height);
-                                context.fillStyle = "#409eff";
-                                context.lineWidth = 1.5;
-                            });
-                        }
-                    });
-                },
-                // 向父页面推送数据
-                parentMessage(type, data) {
-                    var message = {
-                        funcName: type,
-                        data: data,
-                    };
-
-                    //APP-PLUS
-                    uni.postMessage({
-                        data: message
-                    });
-
-                    //H5
-                    if (window.parent) {
-                        window.parent.postMessage(message, '*');
-                    }
-                },
-                // 当需要抓拍部分画布时
-                capturePartialImage(x, y, width, height) {
-                    // 创建一个新的canvas,用于抓拍部分画布
-                    const canvas = document.getElementById('myCanvas');//画布dom
-                    const croppedCanvas = document.createElement('canvas');
-                    croppedCanvas.width = width;
-                    croppedCanvas.height = height;
-                    const croppedCtx = croppedCanvas.getContext('2d');
-
-                    // 只抓取需要的部分
-                    croppedCtx.drawImage(canvas, x, y, width, height, 0, 0, width, height);
-                    var image = croppedCanvas.toDataURL("image/png")
-                    that.parentMessage('人脸识别', { imageBase: image })
-                },
-                // 获取图片bold
-                saveAsLocalImage() {
-                    var that = this
-                    // var myCanvas = document.getElementById("myCanvas");
-                    // var image = myCanvas.toDataURL("image/png")
-                    // that.parentMessage('人脸识别', { imageBase: image })
-
-                    // 创建一个新的canvas,用于抓拍部分画布
-                    const canvas = document.getElementById('myCanvas');//画布dom
-                    const croppedCanvas = document.createElement('canvas');
-                    croppedCanvas.width = 200;
-                    croppedCanvas.height = 200;
-                    const croppedCtx = croppedCanvas.getContext('2d');
-
-                    // 只抓取需要的部分
-                    croppedCtx.drawImage(canvas, 0, 0, 150, 150);
-                    var image = croppedCanvas.toDataURL("image/png");
-                    that.parentMessage('人脸识别', { imageBase: image })
-                },
-                // 人脸冷却
-                faceCooling() {
-                    var that = this
-                    setTimeout(() => {
-                        that.flag = true
-                        that.state.faceImgState = false;
-                    }, that.time);
-                },
-                // 解析数据
-                analysisData(event) {
-                    console.log(event.funcName)
-                    if ("funcName" in event) {
-                        if (event.funcName == "初始化数据") {
-                            this.initData(JSON.parse(event.data));
-                        } else if (event.funcName == "初始化事件") {
-                            this.initHandle()
-                        } else if (event.funcName == "开启摄像头") {
-                            this.initVido();//调用初始化摄像头
-                        } else if (event.funcName == "关闭摄像头") {
-                            this.closeFace();
-                        } else if (event.funcName == "人脸冷却") {
-                            this.faceCooling();
-                        }
-                    }
-                },
-                // 长按事件
-                longPress() {
-                    this.parentMessage('打开配置')
-                    this.timeOutEvent = 0
-                },
-                // 监听页面是否隐藏
-                handleVisibilityChange() {
-                    if (document.visibilityState === 'visible') {
-                        // 页面变为可见时的处理逻辑
-                        console.log('页面变为可见');
-                        this.tracker == null ? this.initVido() : undefined
-                    } else if (document.visibilityState === 'hidden') {
-                        // 页面变为不可见时的处理逻辑
-                        console.log('页面变为不可见');
-                        this.tracker != null ? this.closeFace() : undefined
-                    }
-                },
-                // 关闭摄像头
-                closeFace() {
-                    try {
-                        this.tracker = null
-                        // 关闭摄像头
-                        let video = document.getElementById('video')
-                        video.srcObject.getTracks()[0].stop()
-                        // 停止侦测
-                        this.trackerTask.stop()
-                    } catch (error) { }
-                },
-                /**
-                * @获取年月日时分
-                * @returns
-                */
-                getFormatterDate(time3) {
-                    var date = new Date(time3);
-                    var Y = date.getFullYear() + "/";
-                    var M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "/";
-                    var D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
-
-                    var h = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
-                    var m = (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes())
-                    var strDate = Y + M + D + h + m;
-
-                    return strDate;
-                },
-            },
-            created() {
-                var that = this
-                // APP-PLUS || H5(接收父页面传过来的值)
-                window.receiveData = (msg) => {
-                    that.analysisData(msg)
-                }
-                window.addEventListener("message", function (event) {
-                    that.analysisData(event.data)
-                });
-            },
-            mounted() {
-                document.addEventListener('visibilitychange', this.handleVisibilityChange);
-
-                if (!this.inter.dateDom) {
-                    this.inter.dateDom = setInterval(() => {
-                        this.state.date = this.getFormatterDate(new Date()).split(' ')[0]
-                        this.state.dateTime = this.getFormatterDate(new Date()).split(' ')[1]
-                    }, 1000);
-                }
-            },
-            beforeDestroy() {
-                // 移除window方法
-                window.receiveData = null;
-                clearInterval(inter.dateDom); //销毁之前定时器
-            },
-            watch: {},
-        }).mount('#face-container');
-    </script>
-</body>
-
-</html>

+ 7 - 3
src/static/face/js/meeting-page.js

@@ -121,6 +121,10 @@
                     if (!canvas) return;
                     canvas.style.transform = 'scaleX(-1)'; // 水平翻转
                     var context = canvas.getContext('2d');
+                    if (!tracking || !tracking.ViolaJones || !tracking.ViolaJones.classifiers || !tracking.ViolaJones.classifiers.face) {
+                        console.error('人脸 Haar 分类器未加载,请确认已引入 face-min.js / face.js 且在 tracking 之后');
+                        return;
+                    }
                     that.tracker = new tracking.ObjectTracker('face');
                     that.tracker.setInitialScale(4); // 识别放大比例
                     that.tracker.setStepSize(2); // 步长
@@ -252,14 +256,14 @@
                     }
 
                     if (this.state.meetingTemplate && event.id == this.state.meetingTemplate.id) {
-                        this.state.meetingTemplate = event
                         return;
                     } else {
                         this.state.meetingTemplate = event
+                        this.initVido(); // 调用初始化摄像头
                     }
 
-                    var s1Con = this.state.meetingTemplate.s1Con ? JSON.parse(this.state.meetingTemplate.s1Con) : []
-                    if (!s1Con) return
+                    var s1Con = this.state.meetingTemplate.s1Con && this.state.meetingTemplate.s1Con.includes("[{") ? JSON.parse(this.state.meetingTemplate.s1Con) : [];
+                    if (s1Con.length <= 0) return
 
                     var stage = document.getElementById(options.containerId);
                     if (!stage) return

+ 11 - 2
src/static/face/meeting.html

@@ -4,6 +4,17 @@
 <head>
     <meta charset="utf-8">
     <title>人脸识别</title>
+    <script>
+        (function () {
+            try {
+                var p = window.location.pathname || "";
+                var i = p.lastIndexOf("/");
+                if (i >= 0) {
+                    document.write('<base href="' + p.substring(0, i + 1).replace(/"/g, "") + '">');
+                }
+            } catch (e) {}
+        })();
+    </script>
     <script type="text/javascript" src="./js/tracking-min.js"></script>
     <script type="text/javascript" src="./js/face_data/face-min.js"></script>
     <script type="text/javascript" src="./js/jquery-2.2.1.min.js"></script>
@@ -240,8 +251,6 @@
                     <span style="padding: 0px 5px; border-right: 1px #fff solid">PM2.5:10μg/m3</span>
                     <span style="padding: 0 0 0 5px">甲醛:0ppm</span>
                 </div>
-                <div class="home-card-right-header-title">{{state.thisVenueData ? "&nbsp;&nbsp;会议进行中" :
-                    "&nbsp;"}}</div>
             </div>
             <div class="home-card-right-content">
                 <div style="font-size: 20px; margin-bottom: 15px;">{{state.thisVenueData?.meetingName || "空闲中"}}

+ 11 - 5
src/static/face/meeting_template_preview.html

@@ -4,6 +4,17 @@
 <head>
     <meta charset="utf-8" />
     <title>会议模板预览</title>
+    <script>
+        (function () {
+            try {
+                var p = window.location.pathname || "";
+                var i = p.lastIndexOf("/");
+                if (i >= 0) {
+                    document.write('<base href="' + p.substring(0, i + 1).replace(/"/g, "") + '">');
+                }
+            } catch (e) {}
+        })();
+    </script>
     <script type="text/javascript" src="./js/tracking-min.js"></script>
     <script type="text/javascript" src="./js/face_data/face-min.js"></script>
     <script type="text/javascript" src="./js/jquery-2.2.1.min.js"></script>
@@ -72,9 +83,6 @@
         .image-item {
             position: absolute;
             overflow: hidden;
-            border-radius: 12px;
-            /* border: 2px dotted #c7c7c7; */
-            /* background: #f7f8fa; */
             display: flex;
             align-items: center;
             justify-content: center;
@@ -88,8 +96,6 @@
 
         .carousel {
             position: absolute;
-            /* border: 2px dotted #c7c7c7; */
-            /* border-radius: 12px; */
             overflow: hidden;
             background: #f6f6f6;
             display: flex;

BIN
src/static/iconfont/iconfont.ttf


BIN
src/static/iconfont/iconfont.woff


BIN
src/static/iconfont/iconfont.woff2


+ 80 - 167
src/store/modules/control.js

@@ -1,7 +1,7 @@
 import { defineStore } from "pinia";
-import { doorApi } from "@/api/business/door.js";
+import { doorApi, egDeviceHeartbeat } from "@/api/business/door.js";
 import { faceApi } from "@/api/business/face.js";
-import { deviceApi, meetingApi, signOnOut, escalation } from "@/api/business/meeting.js";
+import { deviceApi, meetingApi, signOnOut, meetingDeviceHeartbeat, } from "@/api/business/meeting.js";
 import { getToken, setToken, removeToken } from "@/utils/auth";
 import dayjs from 'dayjs'
 import config from "@/config";
@@ -18,13 +18,9 @@ import yxPlugins from "@/plugins/device/yx.plugins";
 const controlStore = defineStore("control", {
     state: () => ({
         ipAddress: "",//设备IP地址
-        pageFunction: [], //被包含的功能
         isClicked: false, //按钮是否被点击
         isDataChange: false,//数据是否改变
         form: {
-            linkUrl: "",
-            port: "",
-            domain: undefined,
             door: {
                 id: undefined,
                 name: undefined,
@@ -33,9 +29,6 @@ const controlStore = defineStore("control", {
         popup: {
             show: false,
         },
-        modal: {
-            show: false,
-        },
         doorList: [],
         meetingDoorList: [],//会议门禁列表数据
         meetingRoomList: [],//会议室列表数据
@@ -53,6 +46,7 @@ const controlStore = defineStore("control", {
         inter: {
             doorDom: null,
             meeting: null,
+            egEscalation: null,
             meetingEscalation: null,
             rebootNow: null
         },
@@ -73,13 +67,9 @@ const controlStore = defineStore("control", {
             }
             // 智能门禁
             else if (config.appInfo.appid === "__UNI__8D6E9FD") {
-                config.baseUrl = "http://" + storage.domain + "/prod-api";
-                that.form.domain = storage.domain;
-                that.form.linkUrl = storage.linkUrl.indexOf(":") != -1 ? storage.linkUrl.split(":")[0] : storage.linkUrl;
-                that.form.port = storage.port ? storage.port : "";
                 that.form.door = {
-                    id: storage.door.id || undefined,
-                    name: storage.door.name || undefined,
+                    id: storage.door?.id || undefined,
+                    name: storage.door?.name || undefined,
                 }
             }
         },
@@ -103,34 +93,14 @@ const controlStore = defineStore("control", {
             var that = this
             //#ifdef APP-PLUS
             nfc.initNFC();
-            nfc.readNFC().then((e) => {
-                that.openDoor();
-                that.initNfc();
-            });
-            //#endif
-        },
-        /**
-         * @服务器配置保存事件
-         */
-        serveChange() {
-            if (this.form.linkUrl) {
-                if (!/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}(?:\.[a-zA-Z0-9]{2,})+$/.test(this.form.linkUrl)) {
-                    modal.msg("请输入正确的链接地址");
-                    return;
-                }
+            // nfc.readNFC().then((e) => {
+            //     console.log(e)
 
-                var domain = "";
-                if (this.form.linkUrl) {
-                    domain = this.form.linkUrl;
-                    if (this.form.port) {
-                        domain += ":" + this.form.port;
-                    }
-                }
+            //     that.openDoor();
+            //     that.initNfc();
+            // });
 
-                this.form.domain = domain;
-                config.baseUrl = "http://" + this.form.domain + "/prod-api";
-            }
-            uni.setStorageSync("storage_face", this.form);
+            //#endif
         },
         /**
          * @开启定时任务
@@ -152,17 +122,21 @@ const controlStore = defineStore("control", {
             }
             //门禁
             else if (type == "door") {
-                if (this.inter.doorDom) return;
-                this.getDoorList("updateData");
+                this.initEscalation("eg");//调用初始化会议心跳方法
+                this.inter.egEscalation = setInterval(() => {
+                    this.initEscalation("eg");//调用初始化会议心跳方法
+                }, 1000 * 10)
+
+                this.getDoorList();
                 this.inter.doorDom = setInterval(() => {
-                    this.getDoorList("updateData");
+                    this.getDoorList();
                 }, 1000 * 3);
             }
             // 会议
             else if (type == "meeting") {
-                this.initEscalation();//调用初始化会议心跳方法
+                this.initEscalation("meeting");//调用初始化会议心跳方法
                 this.inter.meetingEscalation = setInterval(() => {
-                    this.initEscalation();//调用初始化会议心跳方法
+                    this.initEscalation("meeting");//调用初始化会议心跳方法
                 }, 1000 * 10)
 
                 this.getMeetingDeviceList()
@@ -183,44 +157,10 @@ const controlStore = defineStore("control", {
                 this.inter.meeting = null;
             }
         },
-        /**
-         * @弹窗事件
-         * @Confirm 确定
-         * @Cancel 退出应用
-         * @Close 关闭
-         */
-        handleModal(type) {
-            if (type == "Confirm") {
-                uni.setStorageSync("storage_face", this.form);
-            } else if (type == 'Cancel') {
-                //#ifdef APP-PLUS
-                keyListen.quitApp();
-                //#endif
-            } else if (type == "Close") {
-
-            }
-
-            this.handleChildren({ funcName: "开启摄像头", data: {} });
-            this.modal.show = false;
-
-        },
-        /**
-         * @Select下拉框回调事件
-         */
-        handleSelectChange(e) {
-            if (e.type === "绑定门禁") {
-                const match = this.doorList.find(item => item.value === e.value);
-                if (match) {
-                    this.form.door.id = match.value;
-                    this.form.door.name = match.name;
-                }
-            }
-            this.isDataChange = true;
-        },
         /**
          * @初始化设备心跳数据
          */
-        initEscalation() {
+        initEscalation(type) {
             if (!sysPlugins.getDeviceInfo().serial) return;
             sysPlugins.getIpAddress({
                 success: (res) => {
@@ -231,10 +171,15 @@ const controlStore = defineStore("control", {
                         "model": sysPlugins.getDeviceInfo().model,
                         "manuFacturer": sysPlugins.getDeviceInfo().manufacturer,
                         "version": sysPlugins.getDeviceInfo().version,
-                        "sdk": sysPlugins.getDeviceInfo().Sdk
+                        "sdk": sysPlugins.getDeviceInfo().Sdk,
+                        "deviceStatus": type == "eg" ? 1 : undefined,
                     }
 
-                    escalation(param)
+                    if (type == "meeting") {
+                        meetingDeviceHeartbeat(param)
+                    } else if (type == "eg") {
+                        egDeviceHeartbeat(param)
+                    }
                 }
             });
         },
@@ -265,7 +210,7 @@ const controlStore = defineStore("control", {
 
             deviceApi()
                 .Select({
-                    deviceCode: sysPlugins.getDeviceInfo().serial || "NTECVSG3PL",
+                    deviceCode: sysPlugins.getDeviceInfo().serial || "",
                     current: 1,
                     size: 10
                 })
@@ -275,15 +220,16 @@ const controlStore = defineStore("control", {
                         this.form.meetingName = requset.data.records[0].meetingRoom.roomName
                         this.meetingTemplateList = requset.data.records[0].meetingTemplate
 
-                        if (this.meetingTemplateList && this.meetingTemplateList?.type == 1) {
-                            this.meetingTemplateSrc = `/static/face/${this.meetingTemplateList.s1Con}`
-                        } else {
-                            this.meetingTemplateSrc = "/static/face/meeting_template_preview.html"
-                            this.handleChildren({
-                                funcName: "初始化模板",
-                                data: JSON.stringify(this.meetingTemplateList || {}),
-                            });
-                        }
+                        // 根据模板类型设置模板路径
+                        this.meetingTemplateSrc = (this.meetingTemplateList && this.meetingTemplateList?.type == 1)
+                            ? `/static/face/${this.meetingTemplateList.s1Con}`
+                            : "/static/face/meeting_template_preview.html";
+
+                        // 初始化模板数据
+                        this.handleChildren({
+                            funcName: "初始化模板",
+                            data: JSON.stringify(this.meetingTemplateList || {}),
+                        });
 
                         this.getMeetingRoomReservationList();
                     } else {
@@ -405,28 +351,27 @@ const controlStore = defineStore("control", {
          */
         faceVerify(imageBase) {
             var that = this
+            console.log(1)
+
             faceApi()
-                .faceVef({
-                    deviceCode: sysPlugins.getDeviceInfo().serial,
-                    imageBase: imageBase,
+                .facePerson({
+                    faceBase: imageBase,
                 })
-                .then((item) => {
-                    if (item.data.code === 200 || item.data.code === 201) {
-                        item.data.userName = item.data.faceName;
-                        if (that.pageFunction.includes('会议')) {
-                            that.meetingVerify(item.data);
-                        } else {
-                            that.openDoor(item.data);
+                .then((res) => {
+                    console.log(res)
+
+                    if ((res.code == '0' || res.code == 200) && res.data.success) {
+                        res.data.userName = res.data.faceName;
+                        if (that.inter.doorDom != null) {
+                            // that.openDoor(res.data);
+                            sysPlugins.openDoor(1, 0);
+                        } else if (that.inter.meeting != null) {
+                            that.meetingVerify(res.data);
                         }
                     }
 
-                    if (item.data.msg != "人脸验证接口返回异常") {
-                        modal.msg(item.data.msg);
-                    }
-
                     that.handleChildren({ funcName: "人脸冷却", data: {} });
-                })
-                .catch((err) => {
+                }).catch((err) => {
                     that.handleChildren({ funcName: "人脸冷却", data: {} });
                 });
         },
@@ -465,48 +410,32 @@ const controlStore = defineStore("control", {
             }).then((item) => { });
         },
         /**
-         * @门禁下拉列表
+         * @门禁列表
          */
-        getDoorList(type) {
+        getDoorList() {
             this.doorList = [];
-
-            if (!this.form.domain) return;
-            if (type == 'updateData' && !this.form.door.id) return;
-
-
             doorApi()
                 .Select({
                     current: 1, //页数
                     size: 2000, //条数
-                    domain: this.form.domain, //域名
-                    deviceUuid: type == 'updateData' ? this.form.door.id : undefined
+                    deviceCode: sysPlugins.getDeviceInfo().serial || "NTECVSG3PL",
                 })
                 .then((requset) => {
                     if (requset.data.records.length <= 0) return;
 
-                    if (type == "updateData") {
-                        let data = requset.data.records[0]
-                        if (!time.isInRange(8, 18)) {
-                            data.openMode = this.removeSegmentWithTarget(data.openMode, "点击开门")
-                        }
-
-                        this.handleChildren({
-                            funcName: "初始化数据",
-                            data: JSON.stringify(data),
-                        });
+                    let data = requset.data.records[0];
 
-                        delete data.id
-                        Object.assign(this.form.door, data)
-                        uni.setStorageSync("storage_face", this.form);
-                    } else {
-                        requset.data.records.forEach((e) => {
-                            this.doorList.push({
-                                value: e.deviceUuid,
-                                name: e.deviceName,
-                                text: e.deviceName,
-                            });
-                        });
+                    if (!time.isInRange(8, 18)) {
+                        data.openMode = this.removeSegmentWithTarget(data.openMode, "点击开门")
                     }
+
+                    this.handleChildren({
+                        funcName: "初始化数据",
+                        data: JSON.stringify(data),
+                    });
+
+                    Object.assign(this.form.door, data)
+                    uni.setStorageSync("storage_face", this.form);
                 });
         },
         /**
@@ -529,52 +458,36 @@ const controlStore = defineStore("control", {
 
             doorApi()
                 .control({
-                    domain: !getToken() ? this.form.domain : undefined, //域名
+                    skipCheck: true,
                     userId: !getToken() ? event.userId : undefined,
                     userName: !getToken() ? event.userName : undefined,
                     productCode: "502_USKY",
-                    deviceUuid: !getToken() ? this.form.door.id : event.deviceUuid,
+                    deviceUuid: this.form.door.deviceUuid,
                     commandCode: "door_onoff",
                     commandValue: 1,
                 })
                 .then((item) => {
-                    modal.msg("开门成功");
+                    if (item.status == "success") {
+                        modal.msg("开门成功");
+                    } else {
+                        modal.msg("开门失败");
+                    }
                     setTimeout(() => {
                         this.isClicked = false;
                     }, 2000);
-                    that.insertDoorRecord(event, "成功");
                 })
                 .catch((err) => {
                     setTimeout(() => {
                         this.isClicked = false;
                     }, 2000);
-                    that.insertDoorRecord(event, "失败:" + err);
-                });
-        },
-        /**
-         * @新增开门记录
-         */
-        insertDoorRecord(event, msg) {
-            doorApi()
-                .RecordInsert({
-                    domain: !getToken() ? this.form.domain : undefined, //域名
-                    userName: event.userName, //用户姓名
-                    deviceUuid: !getToken() ? this.form.door.id : event.deviceUuid,//设备Uuid
-                    passType: 3, //通行方式(1、人脸 2、刷卡 3、手机)
-                    passTime: dayjs().format("YYYY-MM-DDTHH:mm:ss"), //通行时间
-                    passResult: msg, //通行结果
-                })
-                .then((item) => {
-                    console.log(msg);
-                })
-                .catch((err) => {
-                    console.log(err);
                 });
         },
         /**
          * @解析父页面传回的数据
          */
         analysisData(event) {
+            var that = this
+
             if ("funcName" in event) {
                 if (event.funcName == "打开门禁配置") {
                     this.handleChildren({ funcName: "关闭摄像头", data: {} });
@@ -587,8 +500,8 @@ const controlStore = defineStore("control", {
                     this.faceVerify(event.data.imageBase);
                 } else if (event.funcName == "点击开门") {
                     this.openDoor({
-                        userId: 99,
-                        userName: "方惠圣",
+                        userId: "",
+                        userName: "快捷方式开门",
                     });
                 } else if (event.funcName == "密码") {
                     this.handleChildren({ funcName: "关闭摄像头", data: {} });
@@ -675,7 +588,7 @@ const controlStore = defineStore("control", {
 
                 // 比较当前时间是否等于早上6点
                 if (now.getTime() === targetTime.getTime()) {
-                    yxPlugins.rebootNow();
+                    sysPlugins.reboot();
                 }
             }
         },

+ 37 - 0
src/store/modules/setting.js

@@ -214,6 +214,43 @@ const settingStores = defineStore("storage-setting", {
                 }
             }, 0);
         },
+
+        /**
+         * @打开系统网络设置页面
+         */
+        openSystemNetwork() {
+            let main = plus.android.runtimeMainActivity();
+            let Intent = plus.android.importClass("android.content.Intent");
+            let mIntent = new Intent('android.settings.WIRELESS_SETTINGS');
+            main.startActivity(mIntent);
+        },
+        /**
+         * @打开系统WiFi设置页面
+         */
+        openSystemWifi() {
+            uni.getNetworkType({
+                success: function (res) {
+                    const networkType = res.networkType;
+                    if (networkType === 'none') {
+                        // 没有网络,跳转到系统网络设置
+                        uni.showToast({
+                            title: '当前无网络,请检查网络设置',
+                            icon: 'none'
+                        });
+                        let main = plus.android.runtimeMainActivity();
+                        let Intent = plus.android.importClass("android.content.Intent");
+                        let mIntent = new Intent('android.settings.WIFI_SETTINGS');
+                        main.startActivity(mIntent);
+                    } else {
+                        // 有网络,可以继续你的业务逻辑
+                        let main = plus.android.runtimeMainActivity();
+                        let Intent = plus.android.importClass("android.content.Intent");
+                        let mIntent = new Intent('android.settings.WIFI_SETTINGS');
+                        main.startActivity(mIntent);
+                    }
+                }
+            })
+        },
         SET_FINGERPRINT(array) {
             this.fingerprintUserList = array;
             storage.set("fingerprintUserList", array);

+ 0 - 226
src/uni_modules/lime-echart/changelog.md

@@ -1,226 +0,0 @@
-## 2.0.3(2025-12-04)
-- feat: autoHideTooltip默认为false
-## 2.0.2(2025-11-24)
-- feat: 增加`autoHideTooltip`属性
-## 2.0.1(2025-10-28)
-- chore: 更新文档
-## 2.0.0(2025-10-28)
-- feat: 基于 Vue 3 Composition API 重构 uni-app 端组件,提升代码可维护性和性能
-- feat: 升级内置 ECharts 至 v6 版本,支持最新图表特性和性能优化
-## 1.0.4(2025-05-16)
-- fix: 修复uniappx ios尺寸
-## 1.0.3(2025-05-10)
-- fix: 修复nvue缺少`isDisposed`
-## 1.0.2(2025-03-21)
-- fix: 修复词云无法设置字体大小的问题
-## 1.0.1(2025-03-14)
-- fix: 修复抖音小程序不显示问题
-## 1.0.0(2025-02-27)
-- fix: 修复uniappx微信小程序不显示问题
-## 0.9.9(2025-02-24)
-- feat: 更新v4
-## 0.9.8(2024-12-20)
-- fix: 修复 APP 无法放大问题
-## 0.9.7(2024-12-02)
-- feat: uniapp 增加`landscape`,当`landscape`为`true`时旋转90deg达到横屏效果。
-- feat: 支持uniapp x 微信小程序
-## 0.9.6(2024-07-23)
-- fix: 修复 uni is not defined
-## 0.9.5(2024-07-19)
-- chore: 鸿蒙`measureText`为异步,异步字体不正常,使用模拟方式。
-## 0.9.4(2024-07-18)
-- chore: 更新文档
-## 0.9.3(2024-07-16)
-- feat: 鸿蒙 canvas 事件缺失,待官方修复,如何在鸿蒙使用请看文档`常见问题 vue3` 
-## 0.9.2(2024-07-12)
-- chore: 删除多余文件
-## 0.9.1(2024-07-12)
-- fix: 修复 安卓5不显示图表问题
-## 0.9.0(2024-06-13)
-- chore: 合并nvue和uvue
-## 0.8.9(2024-05-19)
-- chore: 更新文档
-## 0.8.8(2024-05-13)
-- chore: 更新文档和uvue示例
-## 0.8.7(2024-04-26)
-- fix: uniapp x需要HBX 4.13以上
-## 0.8.6(2024-04-10)
-- feat: 支持 uniapp x ios
-## 0.8.5(2024-04-03)
-- fix: 修复 nvue `reset`传值不生效问题
-- feat: 支持 uniapp x web
-## 0.8.4(2024-01-27)
-- chore: 更新文档
-## 0.8.3(2024-01-21)
-- chore: 更新文档
-## 0.8.2(2024-01-21)
-- feat: 支持 `uvue`
-## 0.8.1(2023-08-24)
-- fix: app 的`touch`事件为`object` 导致无法显示 `tooltip`
-## 0.8.0(2023-08-22)
-- fix: 离屏 报错问题
-- fix: 微信小程序PC无法使用事件
-- chore: 更新文档
-## 0.7.9(2023-07-29)
-- chore: 更新文档
-## 0.7.8(2023-07-29)
-- fix: 离屏 报错问题
-## 0.7.7(2023-07-27)
-- chore: 更新文档
-- chore: lime-echart 里的示例使用自定tooltips
-- feat: 对支持离屏的使用离屏创建(微信、字节、支付宝)
-## 0.7.6(2023-06-30)
-- fix: vue3 报`width`的错
-## 0.7.5(2023-05-25)
-- chore: 更新文档 和 demo, 使用`lime-echart`这个标签即可查看示例
-## 0.7.4(2023-05-22)
-- chore: 增加关于钉钉小程序上传时提示安全问题的说明及修改建议
-## 0.7.3(2023-05-16)
-- chore: 更新 vue3 非微信小程序平台可能缺少`wx`的说明
-## 0.7.2(2023-05-16)
-- chore: 更新 vue3 非微信小程序平台的可以缺少`wx`的说明
-## 0.7.1(2023-04-26)
-- chore: 更新demo,使用`lime-echart`这个标签即可查看示例
-- chore:微信小程序的`tooltip`文字有阴影,怀疑是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
-## 0.7.0(2023-04-24)
-- fix: 修复`setAttribute is not a function`
-## 0.6.9(2023-04-15)
-- chore: 更新文档,vue3请使用echarts esm的包
-## 0.6.8(2023-03-22)
-- feat: mac pc无法使用canvas 2d
-## 0.6.7(2023-03-17)
-- feat: 更新文档
-## 0.6.6(2023-03-17)
-- feat: 微信小程序PC已经支持canvas 2d,故去掉判断PC
-## 0.6.5(2022-11-03)
-- fix: 某些手机touches为对象,导致无法交互。
-## 0.6.4(2022-10-28)
-- fix: 优化点击事件的触发条件
-## 0.6.3(2022-10-26)
-- fix: 修复 dataZoom 拖动问题
-## 0.6.2(2022-10-23)
-- fix: 修复 飞书小程序 尺寸问题
-## 0.6.1(2022-10-19)
-- fix: 修复 PC mousewheel 事件 鼠标位置不准确的BUG,不兼容火狐!
-- feat: showLoading 增加传参
-## 0.6.0(2022-09-16)
-- feat: 增加PC的mousewheel事件
-## 0.5.4(2022-09-16)
-- fix: 修复 nvue 动态数据不显示问题
-## 0.5.3(2022-09-16)
-- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
-- chore: 更新文档
-## 0.5.2(2022-09-16)
-- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
-## 0.5.1(2022-09-16)
-- fix: 修复nvue报错
-## 0.5.0(2022-09-15)
-- feat: init(echarts, theme?:string, opts?:{}, callback: function(chart))
-## 0.4.8(2022-09-11)
-- feat: 增加 @finished
-## 0.4.7(2022-08-24)
-- chore: 去掉 stylus
-## 0.4.6(2022-08-24)
-- feat: 增加 beforeDelay
-## 0.4.5(2022-08-12)
-- chore: 更新文档
-## 0.4.4(2022-08-12)
-- fix: 修复 resize 无参数时报错
-## 0.4.3(2022-08-07)
-# 评论有说本插件对新手不友好,让我做不好就不要发出来。 还有的说跟官网一样,发出来做什么,给我整无语了。
-# 所以在此提醒一下准备要下载的你,如果你从未使用过 echarts 请不要下载 或 谨慎下载。
-# 如果你确认要下载,麻烦看完文档。还有请注意插件是让echarts在uniapp能运行,API 配置请自行去官网查阅!
-# 如果你不会echarts 但又需要图表,市场上有个很优秀的图表插件 uchart 你可以去使用这款插件,uchart的作者人很好,也热情。
-# 每个人都有自己的本职工作,如果你能力强可以自行兼容,如果使用了他人的插件也麻烦尊重他人的成果和劳动时间。谢谢。
-# 为了心情愉悦,本人已经使用插件屏蔽差评。
-- chore: 更新文档
-## 0.4.2(2022-07-20)
-- feat: 增加 resize
-## 0.4.1(2022-06-07)
-- fix: 修复 canvasToTempFilePath 不生效问题
-## 0.4.0(2022-06-04)
-- chore 为了词云 增加一个canvas 标签
-- 词云下载地址[echart-wordcloud](https://ext.dcloud.net.cn/plugin?id=8430)
-## 0.3.9(2022-06-02)
-- chore: 更新文档
-- tips: lines 不支持 `trailLength`
-## 0.3.8(2022-05-31)
-- fix: 修复 因mouse事件冲突tooltip跳动问题
-## 0.3.7(2022-05-26)
-- chore: 更新文档
-- chore: 设置默认宽高300px
-- fix: 修复 vue3 微信小程序 拖影BUG
-- chore: 支持PC
-## 0.3.5(2022-04-28)
-- chore: 更新使用方式
-- 🔔 必须使用hbuilderx 3.4.8-alpha以上
-## 0.3.4(2021-08-03)
-- chore: 增加 setOption的参数值
-## 0.3.3(2021-07-22)
-- fix: 修复 径向渐变报错的问题
-## 0.3.2(2021-07-09)
-- chore: 统一命名规范,无须主动引入组件
-## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
-## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.3.1(2021-06-21)
-- fix: 修复 app-nvue ios is-enable 无效的问题
-## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
-## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.3.0(2021-06-14)
-- fix: 修复 头条系小程序 2d 报 JSON.stringify 的问题
-- 目前 头条系小程序 2d 无法在开发工具上预览,划动图表页面无法滚动,axisLabel 字体颜色无法更改,建议使用非2d。
-## 0.2.9(2021-06-06)
-- fix: 修复 头条系小程序 2d 放大的BUG 
-- 头条系小程序 2d 无法在开发工具上预览,也存在划动图表页面无法滚动的问题。
-## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.2.8(2021-05-19)
-- fix: 修复 微信小程序 PC 显示过大的问题
-## 0.2.7(2021-05-19)
-- fix: 修复 微信小程序 PC 不显示问题
-## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.2.6(2021-05-14)
-- feat: 支持 `image`
-- feat: props 增加 `ec.clear`,更新时是否先删除图表样式 
-- feat: props 增加 `isDisableScroll` ,触摸图表时是否禁止页面滚动
-- feat: props 增加 `webviewStyles` ,webview 的样式, 仅nvue有效
-## 0.2.5(2021-05-13)
-- docs: 插件用到了css 预编译器 [stylus](https://ext.dcloud.net.cn/plugin?name=compile-stylus) 请安装它
-## 0.2.4(2021-05-12)
-- fix: 修复 百度平台 多个图表ctx 和 渐变色 bug
-- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.2.3(2021-05-10)
-- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
-```js
-this.$refs.chart.canvasToTempFilePath({success: (res) => {
-	console.log('tempFilePath:', res.tempFilePath)
-}})
-```
-## 0.2.2(2021-05-10)
-- feat: 增加 `dispose` 方法,用于销毁实例
-- feat: 增加 `isClickable` 是否派发点击
-- feat: 实验性的支持 `nvue` 使用要慎重考虑
-- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.2.1(2021-05-06)
-- fix:修复 微信小程序 json 报错
-- chore: `reset` 更改为 `setChart`
-- feat: 增加 `isEnable` 开启初始化 启用这个后 无须再使用`init`方法
-```html
-<l-echart ref="chart" is-enable />
-```
-```js
-// 显示加载
-this.$refs.chart.showLoading()
-// 使用实例回调
-this.$refs.chart.setChart(chart => ...code)
-// 直接设置图表配置
-this.$refs.chart.setOption(data)
-```
-## 0.2.0(2021-05-05)
-- fix:修复 头条 百度 偏移的问题
-- docs: 更新文档
-## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
-## 0.1.0(2021-05-02)
-- chore:  第一次上传,基本全端兼容,使用方法与官网一致。
-- 已知BUG:非2d 无法使用背景色,已反馈官方
-- 已知BUG:头条 百度 有许些偏移
-- 后期计划:兼容nvue

+ 0 - 399
src/uni_modules/lime-echart/components/l-echart/canvas.js

@@ -1,399 +0,0 @@
-import {getDeviceInfo} from './utils';
-
-const cacheChart = {}
-const fontSizeReg = /([\d\.]+)px/;
-class EventEmit {
-	constructor() {
-		this.__events = {};
-	}
-	on(type, listener) {
-		if (!type || !listener) {
-			return;
-		}
-		const events = this.__events[type] || [];
-		events.push(listener);
-		this.__events[type] = events;
-	}
-	emit(type, e) {
-		if (type.constructor === Object) {
-			e = type;
-			type = e && e.type;
-		}
-		if (!type) {
-			return;
-		}
-		const events = this.__events[type];
-		if (!events || !events.length) {
-			return;
-		}
-		events.forEach((listener) => {
-			listener.call(this, e);
-		});
-	}
-	off(type, listener) {
-		const __events = this.__events;
-		const events = __events[type];
-		if (!events || !events.length) {
-			return;
-		}
-		if (!listener) {
-			delete __events[type];
-			return;
-		}
-		for (let i = 0, len = events.length; i < len; i++) {
-			if (events[i] === listener) {
-				events.splice(i, 1);
-				i--;
-			}
-		}
-	}
-}
-class Image {
-	constructor() {
-		this.currentSrc = null
-		this.naturalHeight = 0
-		this.naturalWidth = 0
-		this.width = 0
-		this.height = 0
-		this.tagName = 'IMG'
-	}
-	set src(src) {
-		this.currentSrc = src
-		uni.getImageInfo({
-			src,
-			success: (res) => {
-				this.naturalWidth = this.width = res.width
-				this.naturalHeight = this.height = res.height
-				this.onload()
-			},
-			fail: () => {
-				this.onerror()
-			}
-		})
-	}
-	get src() {
-		return this.currentSrc
-	}
-}
-class OffscreenCanvas {
-	constructor(ctx, com, canvasId) {
-		this.tagName = 'canvas'
-		this.com = com
-		this.canvasId = canvasId
-		this.ctx = ctx
-	}
-	set width(w) {
-		this.com.offscreenWidth = w
-	}
-	set height(h) {
-		this.com.offscreenHeight = h
-	}
-	get width() {
-		return this.com.offscreenWidth || 0
-	}
-	get height() {
-		return this.com.offscreenHeight || 0
-	}
-	getContext(type) {
-		return this.ctx
-	}
-	getImageData() {
-		return new Promise((resolve, reject) => {
-			this.com.$nextTick(() => {
-				uni.canvasGetImageData({
-					x:0,
-					y:0,
-					width: this.com.offscreenWidth,
-					height: this.com.offscreenHeight,
-					canvasId: this.canvasId,
-					success: (res) => {
-						resolve(res)
-					},
-					fail: (err) => {
-						reject(err)
-					},
-				}, this.com)
-			})
-		})
-	}
-}
-export class Canvas {
-	constructor(ctx, com, isNew, canvasNode={}) {
-		cacheChart[com.canvasId] = {ctx}
-		this.canvasId = com.canvasId;
-		this.chart = null;
-		this.isNew = isNew
-		this.tagName = 'canvas'
-		this.canvasNode = canvasNode;
-		this.com = com;
-		if (!isNew) {
-			this._initStyle(ctx)
-		}
-		this._initEvent();
-		this._ee = new EventEmit()
-	}
-	getContext(type) {
-		if (type === '2d') {
-			return this.ctx;
-		}
-	}
-	setAttribute(key, value) {
-		if(key === 'aria-label') {
-			this.com['ariaLabel'] = value
-		}
-	}
-	setChart(chart) {
-		this.chart = chart;
-	}
-	createOffscreenCanvas(param){
-		if(!this.children) {
-			// this.com.isOffscreenCanvas = true
-			// this.com.offscreenWidth = param.width||300
-			// this.com.offscreenHeight = param.height||300
-			// const com = this.com
-			// const canvasId = this.com.offscreenCanvasId
-			// const context = uni.createCanvasContext(canvasId, this.com)
-			// this._initStyle(context)
-			// this.children = new OffscreenCanvas(context, com, canvasId)
-		} 
-		return this.children
-	}
-	appendChild(child) {
-		console.log('child', child)
-	}
-	dispatchEvent(type, e) {
-		if(typeof type == 'object') {
-			this._ee.emit(type.type, type);
-		} else {
-			this._ee.emit(type, e);
-		}
-		return true
-	}
-	attachEvent() {
-	}
-	detachEvent() {
-	}
-	addEventListener(type, listener) {
-		this._ee.on(type, listener)
-	}
-	removeEventListener(type, listener) {
-		this._ee.off(type, listener)
-	}
-	_initCanvas(zrender, ctx) {
-		// zrender.util.getContext = function() {
-		// 	return ctx;
-		// };
-		// zrender.util.$override('measureText', function(text, font) {
-		// 	ctx.font = font || '12px sans-serif';
-		// 	return ctx.measureText(text, font);
-		// });
-	}
-	_initStyle(ctx, child) {
-		const styles = [
-			'fillStyle',
-			'strokeStyle',
-			'fontSize',
-			'globalAlpha',
-			'opacity',
-			'textAlign',
-			'textBaseline',
-			'shadow',
-			'lineWidth',
-			'lineCap',
-			'lineJoin',
-			'lineDash',
-			'miterLimit',
-			// #ifdef H5 || APP
-			'font',
-			// #endif
-		];
-		const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
-		styles.forEach(style => {
-			Object.defineProperty(ctx, style, {
-				set: value => {
-					// #ifdef H5 || APP
-					if (style === 'font' && fontSizeReg.test(value)) {
-						const match = fontSizeReg.exec(value);
-						ctx.setFontSize(match[1]);
-						return;
-					}
-					// #endif
-					
-					if (style === 'opacity') {
-						ctx.setGlobalAlpha(value)
-						return;
-					}
-					if (style !== 'fillStyle' && style !== 'strokeStyle' || value !== 'none' && value !== null) {
-						// #ifdef H5 || APP-PLUS || MP-BAIDU
-						if(typeof value == 'object') {
-							if (value.hasOwnProperty('colorStop') || value.hasOwnProperty('colors')) {
-								ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
-							}
-							return
-						} 
-						// #endif
-						// #ifdef MP-TOUTIAO
-						if(colorReg.test(value)) {
-							value = value.replace(colorReg, '#$1$1$2$2$3$3')
-						}
-						// #endif
-						ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
-					}
-				}
-			});
-		});
-		if(!this.isNew && !child) {
-			ctx.uniDrawImage = ctx.drawImage
-			ctx.drawImage = (...a) => {
-				a[0] = a[0].src
-				ctx.uniDrawImage(...a)
-			}
-		}
-		if(!ctx.createRadialGradient) {
-			ctx.createRadialGradient = function() {
-				return ctx.createCircularGradient(...[...arguments].slice(-3))
-			};
-		}
-		// 字节不支持
-		if (!ctx.strokeText) {
-			ctx.strokeText = (...a) => {
-				ctx.fillText(...a)
-			}
-		}
-		
-		// 钉钉不支持 , 鸿蒙是异步
-		if (!ctx.measureText || getDeviceInfo().osName == 'harmonyos') {
-			ctx._measureText = ctx.measureText
-			const strLen = (str) => {
-				let len = 0;
-				for (let i = 0; i < str.length; i++) {
-					if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
-						len++;
-					} else {
-						len += 2;
-					}
-				}
-				return len;
-			}
-			ctx.measureText = (text, font) => {
-				let fontSize = ctx?.state?.fontSize || 12;
-				if (font) {
-					fontSize = parseInt(font.match(/([\d\.]+)px/)[1])
-				}
-				fontSize /= 2;
-				let isBold = fontSize >= 16;
-				const widthFactor = isBold ? 1.3 : 1;
-				// ctx._measureText(text, (res) => {})
-				return {
-					width: strLen(text) * fontSize * widthFactor
-				};
-			}
-		}
-	}
-
-	_initEvent(e) {
-		this.event = {};
-		const eventNames = [{
-			wxName: 'touchStart',
-			ecName: 'mousedown'
-		}, {
-			wxName: 'touchMove',
-			ecName: 'mousemove'
-		}, {
-			wxName: 'touchEnd',
-			ecName: 'mouseup'
-		}, {
-			wxName: 'touchEnd',
-			ecName: 'click'
-		}];
-
-		eventNames.forEach(name => {
-			this.event[name.wxName] = e => {
-				const touch = e.touches[0];
-				this.chart.getZr().handler.dispatch(name.ecName, {
-					zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
-					zrY: name.wxName === 'tap' ? touch.clientY : touch.y
-				});
-			};
-		});
-	}
-
-	set width(w) {
-		this.canvasNode.width = w
-	}
-	set height(h) {
-		this.canvasNode.height = h
-	}
-
-	get width() {
-		return this.canvasNode.width || 0
-	}
-	get height() {
-		return this.canvasNode.height || 0
-	}
-	get ctx() {
-		return cacheChart[this.canvasId]['ctx'] || null
-	}
-	set chart(chart) {
-		cacheChart[this.canvasId]['chart'] = chart
-	}
-	get chart() {
-		return cacheChart[this.canvasId]['chart'] || null
-	}
-}
-
-export function dispatch(name, {x,y, wheelDelta}) {
-	this.dispatch(name, {
-		zrX: x,
-		zrY: y,
-		zrDelta: wheelDelta,
-		preventDefault: () => {},
-		stopPropagation: () =>{}
-	});
-}
-export function setCanvasCreator(echarts, {canvas, node}) {
-	if(echarts && !echarts.registerPreprocessor) {
-		return console.warn('echarts 版本不对或未传入echarts,vue3请使用esm格式')
-	}
-	echarts.registerPreprocessor(option => {
-		if (option && option.series) {
-			if (option.series.length > 0) {
-				option.series.forEach(series => {
-					series.progressive = 0;
-				});
-			} else if (typeof option.series === 'object') {
-				option.series.progressive = 0;
-			}
-		}
-	});
-	function loadImage(src, onload, onerror) {
-		let img = null
-		if(node && node.createImage) {
-			img = node.createImage()
-			img.onload = onload.bind(img);
-			img.onerror = onerror.bind(img);
-			img.src = src;
-			return img
-		} else {
-			img = new Image()
-			img.onload = onload.bind(img)
-			img.onerror = onerror.bind(img);
-			img.src = src
-			return img
-		}
-	}
-	if(echarts.setPlatformAPI) {
-		echarts.setPlatformAPI({
-			loadImage: canvas.setChart ? loadImage : null,
-			createCanvas(){
-				const key = 'createOffscreenCanvas'
-				return uni.canIUse(key) && uni[key] ? uni[key]({type: '2d'}) : canvas
-			}
-		})
-	} else if(echarts.setCanvasCreator) {
-		echarts.setCanvasCreator(() => {
-		    return canvas;
-		});
-	}
-	
-}

+ 0 - 323
src/uni_modules/lime-echart/components/l-echart/l-echart.uvue

@@ -1,323 +0,0 @@
-<template>
-	<!-- #ifdef APP -->
-	<web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[lStyle]" :webview-styles="[webviewStyles]"
-		src="/uni_modules/lime-echart/static/app/uvue.html?v=10112">
-	</web-view>
-	<!-- #endif -->
-	<!-- #ifdef WEB -->
-	<div class="lime-echart" ref="chartRef"></div>
-	<!-- #endif -->
-	<!-- #ifndef WEB || APP-->
-	<view  class="lime-echart">
-		<canvas style="width:100%; height:100%" v-if="canvasid" :id="canvasid" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
-	</view>
-	<!-- #endif -->
-</template>
-
-<script lang="uts" setup>
-	// @ts-nocheck
-	import { echartsProps } from './type';
-	import { Echarts } from './uvue';
-	// #ifdef WEB
-	import { dispatch } from './canvas';
-	import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
-	// #endif
-	// #ifndef APP || WEB
-	import { Canvas, setCanvasCreator, dispatch } from './canvas';
-	import { wrapTouch, convertTouchesToArray, devicePixelRatio, sleep, canIUseCanvas2d, getRect } from './utils';
-	// #endif
-	type EChartsResolveCallback = (value : Echarts) => void
-	
-	const emits = defineEmits(['finished'])
-	const props = withDefaults(defineProps<echartsProps>(), {
-		isDisableScroll: false,
-		isClickable: true,
-		autoHideTooltip: false,
-		enableHover: false,
-		landscape: false,
-		beforeDelay: 30,
-	}) 
-	const instance = getCurrentInstance()!;
-	const canvasid = `lime-echart-${instance.uid}`
-	const finished = ref(false)
-	const initializationQueue = [] as EChartsResolveCallback[]
-	const callbackQueue = [] as EChartsResolveCallback[]
-	// let context = null as UniWebViewElement | null
-	let chartInstance = null as Echarts | null
-	let chartRef = ref<UniWebViewElement | null>(null)
-	let canvasNode:any|null = null
-	const processInitializationQueue = () => {
-		// #ifdef APP
-		if (finished.value) {
-			if (chartInstance == null) {
-				chartInstance = new Echarts(chartRef.value!)
-			}
-			while (initializationQueue.length > 0) {
-				const resolve = initializationQueue.pop() as EChartsResolveCallback
-				resolve(chartInstance!)
-			}
-		}
-		// #endif
-		// #ifndef APP
-		while (initializationQueue.length > 0) {
-			if (chartInstance != null) {
-				const resolve = initializationQueue.pop() as EChartsResolveCallback
-				resolve(chartInstance!)
-			}
-		}
-		// #endif
-
-		if (chartInstance != null) {
-			while (callbackQueue.length > 0) {
-				const callback = callbackQueue.pop() as EChartsResolveCallback
-				callback(chartInstance!)
-			}
-		}
-	}
-
-	// #ifdef APP
-	const loaded = (event : UniWebViewLoadEvent) => {
-		event.stopPropagation()
-		event.preventDefault()
-		nextTick(()=> {
-			chartRef.value?.getBoundingClientRectAsync()?.then(res => {
-				if(res.width > 0 && res.height > 0) {
-					finished.value = true
-					processInitializationQueue()
-					emits('finished')
-				} else {
-					console.warn('【lime-echart】获取尺寸失败,请检查代码样式')
-				}
-			})
-		})
-	}
-	// #endif
-
-
-	const checkInitialization = () : boolean => {
-		if (chartInstance == null) {
-			console.warn(`组件还未初始化,请先使用 init`)
-			return true
-		}
-		return false
-	}
-	const setOption = (option : UTSJSONObject) => {
-		if (checkInitialization()) return
-		chartInstance!.setOption(option);
-	}
-	const showLoading = () => {
-		if (checkInitialization()) return
-		chartInstance!.showLoading();
-	}
-	const hideLoading = () => {
-		if (checkInitialization()) return
-		chartInstance!.hideLoading();
-	}
-	const clear = () => {
-		if (checkInitialization()) return
-		chartInstance!.clear();
-	}
-	const dispose = () => {
-		if (checkInitialization()) return
-		chartInstance!.dispose();
-	}
-	const resize = (size : UTSJSONObject) => {
-		if (checkInitialization()) return
-		chartInstance!.resize(size);
-	}
-	const canvasToTempFilePath = (opt : UTSJSONObject) => {
-		if (checkInitialization()) return
-		// #ifdef APP
-		chartInstance!.canvasToTempFilePath(opt);
-		// #endif
-		// #ifdef WEB
-		options.success?.({
-			tempFilePath: chartInstance._api.getDataURL()
-		}) 
-		// #endif
-		// #ifndef WEB || APP
-		if(canvasNode) {
-			options.success?.({
-				tempFilePath: canvasNode.toDataURL()
-			}) 
-		} else {
-			uni.canvasToTempFilePath({
-				...options,
-				canvasId
-			}, instance.proxy);
-		}
-		// #endif
-	}
-
-	// #ifdef APP
-	function init(callback : ((chartInstance : Echarts) => void) | null) : Promise<Echarts> {
-		if (callback != null) {
-			callbackQueue.push(callback)
-		}
-		return new Promise<Echarts>((resolve) => {
-			initializationQueue.push(resolve)
-			processInitializationQueue()
-		})
-	}
-	// #endif
-	// #ifndef APP 
-	// #ifndef WEB 
-	let use2dCanvas = canIUseCanvas2d()
-	const getContext = async () => {
-		return new Promise((resolve, reject)=>{
-			uni.createCanvasContextAsync({
-				id: canvasid,
-				component: instance.proxy!,
-				success: (context : CanvasContext) => {
-					canvasNode = context
-					const canvasContext = context.getContext('2d')!;
-					const canvas = canvasContext.canvas;
-					let uniCanvas;
-					const width = canvas.offsetWidth
-					const height = canvas.offsetHeight
-					// 处理高清屏逻辑
-					const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
-					canvas.width = canvas.offsetWidth * dpr;
-					canvas.height = canvas.offsetHeight * dpr;
-					canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
-					if(use2dCanvas) {
-						uniCanvas = new Canvas(canvasContext, instance.proxy, true, context);
-					} else {
-						uniCanvas =  new Canvas(canvasContext, instance.proxy, false);
-					}
-					resolve({ canvas: uniCanvas, width, height, devicePixelRatio: 1, node: context});
-				},
-				fail(err) {
-					reject(err)
-					console.log('err', err)
-				}
-			})
-		})
-	}
-	// #endif
-	const getTouch = (e) => {
-		const touches = e.touches[0]
-		// #ifdef WEB
-		const rect = chart!.getZr().dom.getBoundingClientRect();
-		const touch = {
-			x: touches.clientX - rect.left,
-			y: touches.clientY - rect.top
-		}
-		// #endif
-		// #ifndef WEB
-		const touch = {
-			x: touches.x,
-			y: touches.y
-		}
-		// #endif
-		return touch
-	}
-	const touchstart = (e) => {
-		if (chartInstance == null) return
-		const handler = chartInstance.getZr().handler;
-		const touch = getTouch(e)
-		dispatch.call(handler, 'mousedown', touch)
-		dispatch.call(handler, 'click', touch)
-	}
-	const touchmove = (e) => {
-		if (chartInstance == null) return
-		const handler = chartInstance.getZr().handler;
-		const touch = getTouch(e)
-		dispatch.call(handler, 'mousemove', touch)
-	}
-	const touchend = (e) => {
-		if (chartInstance == null || !props.autoHideTooltip) return
-		const handler = chartInstance.getZr().handler;
-
-		const touch = {
-			x: 999999999,
-			y: 999999999
-		}
-
-		dispatch.call(handler, 'mousemove', touch)
-		dispatch.call(handler, 'touchend', touch)
-
-	}
-	async function init(echarts : any, ...args : any[]) : Promise<Echarts> {
-		const library = echarts || echartsLibrary
-		if (library == null) {
-			console.error('请确保已经引入了 ECharts 库');
-			return Promise.reject('请确保已经引入了 ECharts 库');
-		}
-		let theme : string | null = null
-		let opts = {}
-		let callback : Function | null = null;
-
-		args.forEach(item => {
-			if (typeof item === 'function') {
-				callback = item
-			} else if (['string'].includes(typeof item)) {
-				theme = item
-			} else if (typeof item === 'object') {
-				opts = item
-			}
-		})
-
-		// #ifdef WEB
-		library.env.domSupported = true
-		library.env.hasGlobalWindow = true
-		library.env.node = false
-		library.env.pointerEventsSupported = false
-		library.env.svgSupported = true
-		library.env.touchEventsSupported = true
-		library.env.transform3dSupported = true
-		library.env.transformSupported = true
-		library.env.worker = false
-		library.env.wxa = false
-		chartInstance = library.init(chartRef.value, theme, opts)
-		// window.addEventListener('touchstart', touchstart)
-		// window.addEventListener('touchmove', touchmove)
-		// window.addEventListener('touchend', touchend)
-		// #endif
-
-		// #ifndef WEB
-		let config = await getContext();
-		setCanvasCreator(library, config)
-		chartInstance = library.init(config.canvas, theme, Object.assign({}, config, opts))
-		// #endif
-		if (callback != null && typeof callback == 'function') {
-			callbackQueue.push(callback)
-		}
-		return new Promise<Echarts>((resolve) => {
-			initializationQueue.push(resolve)
-			processInitializationQueue()
-		})
-	}
-	onMounted(() => {
-		nextTick(() => {
-			finished.value = true
-			processInitializationQueue()
-			emits('finished')
-		})
-	})
-	onUnmounted(() => {
-		// #ifdef WEB
-		// window.removeEventListener('touchstart', touchstart)
-		// window.removeEventListener('touchmove', touchmove)
-		// window.removeEventListener('touchend', touchend)
-		// #endif
-	})
-	// #endif
-
-	defineExpose({
-		init,
-		setOption,
-		showLoading,
-		hideLoading,
-		clear,
-		dispose,
-		resize,
-		canvasToTempFilePath
-	})
-</script>
-<style lang="scss">
-	.lime-echart {
-		flex: 1;
-		width: 100%;
-	}
-</style>

+ 0 - 484
src/uni_modules/lime-echart/components/l-echart/l-echart.vue

@@ -1,484 +0,0 @@
-<template>
-	<!-- #ifndef APP-NVUE || WEB -->
-	<view class="lime-echart" 
-		:style="[lStyle]" 
-		v-if="canvasId" 
-		ref="chartContainer" 
-		:aria-label="'图表'">
-		<canvas class="lime-echart__canvas" 
-			type="2d" 
-			:style="[styles]"
-			:id="canvasId" 
-			:disable-scroll="isDisableScroll"
-			:canvas-id="canvasId"
-			@touchstart="handleTouchStart" 
-			@touchmove="handleTouchMove"
-			@touchend="handleTouchEnd">
-		</canvas>
-	</view>
-	<!-- #endif -->
-	<!-- #ifdef WEB -->
-	<div class="lime-echart" ref="chartContainer" :style="[styles, lStyle]"></div>
-	<!-- #endif -->
-	<!-- #ifdef APP-NVUE -->
-	<view class="lime-echart" :style="[lStyle]">
-		<web-view class="lime-echart__canvas" 
-			:webview-styles="webviewStyles" 
-			:style="[styles]"
-			ref="chartContainer"
-			src="/uni_modules/lime-echart/static/app/uvue.html?v=1" 
-			@pagefinish="isInitialized = true"
-			@onPostMessage="handleWebviewMessage"></web-view>
-	</view>
-	<!-- #endif -->
-</template>
-
-<script lang="ts">
-	// @ts-nocheck
-	import { defineComponent, getCurrentInstance, ref, onMounted, nextTick, onBeforeUnmount, watch, computed } from './vue'
-	import echartProps from './props'
-	
-	// #ifndef APP-NVUE || WEB
-	import { Canvas, setCanvasCreator, dispatch } from './canvas';
-	import { wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo } from './utils';
-	// #endif
-	// #ifdef APP-NVUE
-	import { base64ToPath, sleep } from './utils';
-	import { Echarts } from './nvue'
-	// #endif
-	// #ifdef WEB
-	import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
-	// #endif
-	
-	// #ifdef APP-VUE
-	import '@/uni_modules/lime-echart/static/app/echarts.min.js';
-	const echartsLibrary = globalThis.echarts
-	// #endif
-	
-	
-	export default defineComponent({
-		props: echartProps,
-		emits: ['finished'],
-		setup(props, { emit, expose }) {
-			// #ifndef APP-NVUE || WEB || APP-VUE
-			let echartsLibrary = null
-			// #endif
-			
-			const instance = getCurrentInstance()!;
-			const canvasId = `lime-echart-${instance.uid}`
-			const isInitialized = ref(false)
-			const chartContainer = ref(null)
-			
-			type ChartOptions = Record<string, any>
-			type EChartsInstance = typeof echartsLibrary
-			type EChartsResolveCallback = (value: EChartsInstance) => void
-			
-			const initializationQueue = [] as EChartsResolveCallback[]
-			const callbackQueue = [] as EChartsResolveCallback[]
-			
-			let chartInstance: null | EChartsInstance = null
-			
-			const styles = computed(()=> {
-				if(props.landscape) {
-					return {
-						transform: 'translate(-50%,-50%) rotate(90deg)', 
-						top: '50%',
-						left: '50%',
-					}
-				}
-				return {}
-			})
-			
-			const checkInitialization = (): boolean => {
-				if(chartInstance) return false
-				console.warn(`组件还未初始化,请先使用 init`)
-				return true
-			}
-			
-			const setOption = (options: ChartOptions) => {
-				if (checkInitialization()) return
-				chartInstance!.setOption(options);
-			}
-			
-			const hideLoading = () => {
-				if (checkInitialization()) return
-				chartInstance!.showLoading();
-			}
-			
-			const showLoading = () => {
-				if (checkInitialization()) return
-				chartInstance!.hideLoading();
-			}
-			
-			const clear = () => {
-				if (checkInitialization()) return
-				chartInstance!.clear();
-			}
-			
-			const dispose = () => {
-				if (checkInitialization()) return
-				chartInstance!.dispose();
-			}
-			const processInitializationQueue = () => {
-				while (initializationQueue.length > 0) {
-					if (chartInstance != null) {
-						const resolve = initializationQueue.pop() as EChartsResolveCallback
-						resolve(chartInstance!)
-					}
-				}
-				
-				if (chartInstance != null) {
-					while (callbackQueue.length > 0) {
-						const callback = callbackQueue.pop() as EChartsResolveCallback
-						callback(chartInstance!)
-					}
-				}
-			}
-			
-			const resize = (dimensions?: { width?: number; height?: number }) => {
-				if (checkInitialization()) return
-				// #ifdef APP-NVUE || WEB
-				chartInstance!.resize(dimensions);
-				// #endif
-				// #ifndef APP-NVUE || WEB
-				getRect(`#${canvasId}`, instance.proxy).then(res => {
-					chartInstance!.resize({width: res.width, height: res.height});
-				})
-				// #endif
-			}
-			
-			// #ifdef APP-NVUE
-			let chartFile = ref(null);
-			const handleWebviewMessage = (e) => {
-				const detail = e?.detail?.data[0] || null;
-				const data = detail?.data
-				const key = detail?.event
-				const options = data?.options
-				const event = data?.event
-				const file = detail?.file
-				if (key == 'log' && data) {
-					console.log(data)
-				}
-				if(event) {
-					chartInstance.dispatchAction(event.replace(/"/g,''), options)
-				}
-				if(file) {
-					chartFile.value = file
-				}
-			}
-			
-			const canvasToTempFilePath = (options: ChartOptions) => {
-				if (checkInitialization()) return
-				chartContainer.value.evalJs(`canvasToTempFilePath()`);
-				watch(chartFile, async (file) =>{
-					if(!file) return
-					const tempFilePath = await base64ToPath(file)
-					options.success({tempFilePath})
-				})
-			}
-			
-			const getContext = () => {
-				if(isInitialized.value) {
-					return Promise.resolve(isInitialized.value)
-				}
-				return new Promise(resolve => {
-					watch(isInitialized, (val) =>{
-						if(!val) return
-						resolve(val)
-					})
-				})
-			}
-			const init = async (echarts, ...args) => {
-				let theme: string | null = null
-				let config:Record<string, any> = {}
-				let callback: Function | null = null;
-							
-				args.forEach(item => {
-					if (typeof item === 'function') {
-						callback = item
-					} else if (typeof item === 'string') {
-						theme = item
-					} else if (typeof item === 'object') {
-						config = item
-					}
-				})
-				if(props.beforeDelay) {
-					await sleep(props.beforeDelay)
-				}
-				await getContext();
-				chartInstance = new Echarts(chartContainer.value)
-				chartContainer.value.evalJs(`init(null, null, ${JSON.stringify(config)}, ${theme})`)
-				if (callback && typeof callback === 'function') {
-					callbackQueue.push(callback)
-				}
-				
-				return new Promise<EChartsInstance>((resolve) => {
-					nextTick(()=>{
-						initializationQueue.push(resolve)
-						processInitializationQueue()
-					})
-				})
-			}
-			
-			// #endif
-			
-			
-			// #ifndef APP-NVUE || WEB
-			let canvasNode;
-			const canvasToTempFilePath = (options: ChartOptions) => {
-				if (checkInitialization()) return
-				if(canvasNode) {
-					options.success?.({
-						tempFilePath: canvasNode.toDataURL()
-					}) 
-				} else {
-					uni.canvasToTempFilePath({
-						...options,
-						canvasId
-					}, instance.proxy);
-				}
-			}
-			
-			const getContext = () => {
-				return getRect(`#${canvasId}`, instance.proxy).then(res => {
-					let dpr = devicePixelRatio
-					let {width, height, node} = res
-					let canvas: Canvas | null = null;
-					if(!(width || height)) {
-						return Promise.reject('no rect')
-					}
-					if(node && node.getContext) {
-						const ctx = node.getContext('2d');
-						canvas = new Canvas(ctx, instance.proxy, true, node);
-						canvasNode = node
-					} else {
-						dpr = 1
-						const ctx = uni.createCanvasContext(canvasId, instance.proxy);
-						canvas = new Canvas(ctx, instance.proxy, false);
-					}
-					return { canvas, width, height, devicePixelRatio: dpr, node }
-				})
-			}
-			const getTouch = (e) => {
-				const touches = e.touches[0]
-				const touch = props.landscape 
-					? 	{
-							x: touches.y,
-							y: touches.x
-						}
-					:  {
-							x: touches.x,
-							y: touches.y
-						}
-				return touch
-			}
-			const handleTouchStart = (e) => {
-				if (chartInstance == null) return
-				const handler = chartInstance.getZr().handler;
-				const touch = getTouch(e)
-				dispatch.call(handler, 'mousedown', touch)
-				dispatch.call(handler, 'click', touch)
-			}
-			const handleTouchMove = (e) => {
-				if (chartInstance == null) return
-				const handler = chartInstance.getZr().handler;
-				const touch = getTouch(e)
-				dispatch.call(handler, 'mousemove', touch)
-			}
-			const handleTouchEnd = (e) => {
-				if (chartInstance == null || !props.autoHideTooltip) return
-				const handler = chartInstance.getZr().handler;
-			
-				const touch = {
-					x: 999999999,
-					y: 999999999
-				}
-			
-				dispatch.call(handler, 'mousemove', touch)
-				dispatch.call(handler, 'touchend', touch)
-			
-			}
-			const init = async (echartsLib: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
-				const library = echartsLib || echartsLibrary
-				if (!library) {
-					console.error('ECharts library is required');
-					return Promise.reject('ECharts library is required');
-				}
-				let theme: string | null = null
-				let config:Record<string, any> = {}
-				let callback: Function | null = null;
-			
-				args.forEach(item => {
-					if (typeof item === 'function') {
-						callback = item
-					} else if (typeof item === 'string') {
-						theme = item
-					} else if (typeof item === 'object') {
-						config = item
-					}
-				})
-				if(props.beforeDelay) {
-					await sleep(props.beforeDelay)
-				}
-				let options = await getContext();
-				setCanvasCreator(library, options)
-				chartInstance = library.init(options.canvas, theme, Object.assign({}, options, config))
-				if (callback && typeof callback === 'function') {
-					callbackQueue.push(callback)
-				}
-				return new Promise<EChartsInstance>((resolve) => {
-					initializationQueue.push(resolve)
-					processInitializationQueue()
-				})
-			}
-			
-			// #endif
-			
-			
-			// #ifdef WEB
-			const canvasToTempFilePath = (options: ChartOptions) => {
-				if (checkInitialization()) return
-				options.success?.({
-					tempFilePath: chartInstance._api.getDataURL()
-				}) 
-			}
-			
-			const init = async (echarts: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
-				const library = echarts || echartsLibrary
-				if (!library) {
-					console.error('ECharts library is required');
-					return Promise.reject('ECharts library is required');
-				}
-				
-				let theme: string | null = null
-				let config = {}
-				let callback: Function | null = null;
-
-				args.forEach(item => {
-					if (typeof item === 'function') {
-						callback = item
-					} else if (typeof item === 'string') {
-						theme = item
-					} else if (typeof item === 'object') {
-						config = item
-					}
-				})
-				
-				// Configure ECharts environment
-				library.env.domSupported = true
-				library.env.hasGlobalWindow = true
-				library.env.node = false
-				library.env.pointerEventsSupported = false
-				library.env.svgSupported = true
-				library.env.touchEventsSupported = true
-				library.env.transform3dSupported = true
-				library.env.transformSupported = true
-				library.env.worker = false
-				library.env.wxa = false
-				
-				chartInstance = library.init(chartContainer.value, theme, config)
-				
-				if (callback != null && typeof callback === 'function') {
-					callbackQueue.push(callback)
-				}
-				
-				return new Promise<EChartsInstance>((resolve) => {
-					initializationQueue.push(resolve)
-					processInitializationQueue()
-				})
-			}
-			// #endif
-			
-			
-			
-			
-			onMounted(() => {
-				nextTick(() => {
-					// #ifndef APP-NVUE
-					isInitialized.value = true
-					// #endif
-					emit('finished')
-					processInitializationQueue()
-				})
-			})
-			onBeforeUnmount(()=> {
-				clear()
-				dispose()
-			})
-			
-			// #ifdef VUE3
-			expose({
-				init,
-				setOption,
-				hideLoading,
-				showLoading,
-				clear,
-				dispose,
-				resize,
-				canvasToTempFilePath
-			})
-			// #endif
-
-			return {
-				canvasId,
-				chartContainer,
-				styles,
-				// #ifndef WEB || APP-NVUE
-				handleTouchStart,
-				handleTouchMove,
-				handleTouchEnd,
-				// #endif
-				
-				// #ifdef APP-NVUE
-				handleWebviewMessage,
-				isInitialized,
-				// #endif
-				
-				// #ifdef VUE2
-				init,
-				setOption,
-				hideLoading,
-				showLoading,
-				clear,
-				dispose,
-				resize,
-				canvasToTempFilePath,
-				// #endif
-			}
-		}
-	})
-</script>
-
-<style>
-	.lime-echart {
-		position: relative;
-		/* #ifndef APP-NVUE */
-		width: 100%;
-		height: 100%;
-		/* #endif */
-		/* #ifdef APP-NVUE */
-		flex: 1;
-		/* #endif */
-	}
-
-	.lime-echart__canvas {
-		/* #ifndef APP-NVUE */
-		width: 100%;
-		height: 100%;
-		/* #endif */
-		/* #ifdef APP-NVUE */
-		flex: 1;
-		/* #endif */
-	}
-
-	/* #ifndef APP-NVUE */
-	.lime-echart__mask {
-		position: absolute;
-		width: 100%;
-		height: 100%;
-		left: 0;
-		top: 0;
-		z-index: 1;
-	}
-	/* #endif */
-</style>

+ 0 - 515
src/uni_modules/lime-echart/components/l-echart/l-echart_old.vue

@@ -1,515 +0,0 @@
-<template>
-	<view class="lime-echart" :style="[customStyle]" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
-		<!-- #ifndef APP-NVUE -->
-		<canvas
-			class="lime-echart__canvas"
-			v-if="use2dCanvas"
-			type="2d"
-			:id="canvasId"
-			:style="canvasStyle"
-			:disable-scroll="isDisableScroll"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd"
-		/>
-		<canvas
-			class="lime-echart__canvas"
-			v-else
-			:width="nodeWidth"
-			:height="nodeHeight"
-			:style="canvasStyle"
-			:canvas-id="canvasId"
-			:id="canvasId"
-			:disable-scroll="isDisableScroll"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd"
-		/>
-		<view class="lime-echart__mask"
-			v-if="isPC"
-			@mousedown="touchStart"
-			@mousemove="touchMove"
-			@mouseup="touchEnd"
-			@touchstart="touchStart"
-			@touchmove="touchMove"
-			@touchend="touchEnd">
-		</view>
-		<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
-		<!-- #endif -->
-		<!-- #ifdef APP-NVUE -->
-		<web-view
-			class="lime-echart__canvas"
-			:id="canvasId"
-			:style="canvasStyle"
-			:webview-styles="webviewStyles"
-			ref="webview"
-			src="/uni_modules/lime-echart/static/uvue.html?v=1"
-			@pagefinish="finished = true"
-			@onPostMessage="onMessage"
-		></web-view>
-		<!-- #endif -->
-	</view>
-</template>
-
-<script>
-// @ts-nocheck
-// #ifndef APP-NVUE
-import {Canvas, setCanvasCreator, dispatch} from './canvas';
-import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo} from './utils';
-// #endif
-// #ifdef APP-NVUE
-import { base64ToPath, sleep } from './utils';
-import {Echarts} from './nvue'
-// #endif
-
-/**
- * LimeChart 图表
- * @description 全端兼容的eCharts
- * @tutorial https://ext.dcloud.net.cn/plugin?id=4899
-
- * @property {String} customStyle 自定义样式
- * @property {String} type 指定 canvas 类型
- * @value 2d 使用canvas 2d,部分小程序支持
- * @value '' 使用原生canvas,会有层级问题
- * @value bottom right	不缩放图片,只显示图片的右下边区域
- * @property {Boolean} isDisableScroll	 
- * @property {number} beforeDelay = [30]  延迟初始化 (毫秒)
- * @property {Boolean} enableHover PC端使用鼠标悬浮
-
- * @event {Function} finished 加载完成触发
- */
-export default {
-	name: 'lime-echart',
-	props: {
-		// #ifdef MP-WEIXIN || MP-TOUTIAO
-		type: {
-			type: String,
-			default: '2d'
-		},
-		// #endif
-		// #ifdef APP-NVUE
-		webviewStyles: Object,
-		// hybrid: Boolean,
-		// #endif
-		customStyle: String,
-		isDisableScroll: Boolean,
-		isClickable: {
-			type: Boolean,
-			default: true
-		},
-		enableHover: Boolean,
-		beforeDelay: {
-			type: Number,
-			default: 30
-		},
-		landscape: Boolean
-	},
-	data() {
-		return {
-			// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-			use2dCanvas: true,
-			// #endif
-			// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-			use2dCanvas: false,
-			// #endif
-			ariaLabel: '图表',
-			width: null,
-			height: null,
-			nodeWidth: null,
-			nodeHeight: null,
-			// canvasNode: null,
-			config: {},
-			inited: false,
-			finished: false,
-			file: '',
-			platform: '',
-			isPC: false,
-			isDown: false,
-			isOffscreenCanvas: false,
-			offscreenWidth: 0,
-			offscreenHeight: 0,
-		};
-	},
-	computed: {
-		rootStyle() {
-			if(this.landscape) {
-				return `transform: translate(-50%,-50%) rotate(90deg); top:50%; left:50%;`
-			}
-		},
-		canvasId() {
-			return `lime-echart${this._ && this._.uid || this._uid}`
-		},
-		offscreenCanvasId() {
-			return `${this.canvasId}_offscreen`
-		},
-		offscreenStyle() {
-			return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
-		},
-		canvasStyle() {
-			return this.rootStyle + (this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : '')
-		}
-	},
-	// #ifndef VUE3
-	beforeDestroy() {
-		this.clear()
-		this.dispose()
-		// #ifdef H5
-		if(this.isPC) {
-			document.removeEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-	},
-	// #endif
-	// #ifdef VUE3
-	beforeUnmount() {
-		this.clear()
-		this.dispose()
-		// #ifdef H5
-		if(this.isPC) {
-			document.removeEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-	},
-	// #endif
-	created() {
-		// #ifdef H5
-		if(!('ontouchstart' in window)) {
-			this.isPC = true
-			document.addEventListener('mousewheel', this.mousewheel)
-		}
-		// #endif
-		// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
-		const { platform } = getDeviceInfo();
-		this.isPC = /windows/i.test(platform)
-		// #endif
-		this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
-	},
-	mounted() {
-		this.$nextTick(() => {
-			this.$emit('finished')
-		})
-	},
-	methods: {
-		// #ifdef APP-NVUE
-		onMessage(e) {
-			const detail = e?.detail?.data[0] || null;
-			const data = detail?.data
-			const key = detail?.event
-			const options = data?.options
-			const event = data?.event
-			const file = detail?.file
-			if (key == 'log' && data) {
-				console.log(data)
-			}
-			if(event) {
-				this.chart.dispatchAction(event.replace(/"/g,''), options)
-			}
-			if(file) {
-				thie.file = file
-			}
-		},
-		// #endif
-		setChart(callback) {
-			if(!this.chart) {
-				console.warn(`组件还未初始化,请先使用 init`)
-				return
-			}
-			if(typeof callback === 'function' && this.chart) {
-				callback(this.chart);
-			}
-			// #ifdef APP-NVUE
-			if(typeof callback === 'function') {
-				this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
-			}
-			// #endif
-		},
-		setOption() {
-			if (!this.chart || !this.chart.setOption) {
-				console.warn(`组件还未初始化,请先使用 init`)
-				return
-			}
-			this.chart.setOption(...arguments);
-		},
-		showLoading() {
-			if(this.chart) {
-				this.chart.showLoading(...arguments)
-			}
-		},
-		hideLoading() {
-			if(this.chart) {
-				this.chart.hideLoading()
-			}
-		},
-		clear() {
-			if(this.chart && !this.chart.isDisposed()) {
-				this.chart.clear()
-			}
-		},
-		dispose() {
-			if(this.chart && !this.chart.isDisposed()) {
-				this.chart.dispose()
-			}
-		},
-		resize(size) {
-			if(size && size.width && size.height) {
-				this.height = size.height
-				this.width = size.width
-				if(this.chart) {this.chart.resize(size)}
-			} else {
-				this.$nextTick(() => {
-					getRect('.lime-echart', this).then(res =>{
-						if (res) {
-							let { width, height } = res;
-							this.width = width = width || 300;
-							this.height = height = height || 300;
-							this.chart.resize({width, height})
-						}
-					})
-				})
-			}
-			
-		},
-		canvasToTempFilePath(args = {}) {
-			// #ifndef APP-NVUE
-			const { use2dCanvas, canvasId } = this;
-			return new Promise((resolve, reject) => {
-				const copyArgs = Object.assign({
-					canvasId,
-					success: resolve,
-					fail: reject
-				}, args);
-				if (use2dCanvas) {
-					delete copyArgs.canvasId;
-					copyArgs.canvas = this.canvasNode;
-				}
-				uni.canvasToTempFilePath(copyArgs, this);
-			});
-			// #endif
-			// #ifdef APP-NVUE
-			this.file = ''
-			this.$refs.webview.evalJs(`canvasToTempFilePath()`);
-			return new Promise((resolve, reject) => {
-				this.$watch('file', async (file) => {
-					if(file) {
-						const tempFilePath = await base64ToPath(file)
-						resolve(args.success({tempFilePath}))
-					} else {
-						reject(args.fail({error: ``}))
-					}
-				})
-			})
-			// #endif
-		},
-		async init(echarts, ...args) {
-			// #ifndef APP-NVUE
-			if(args && args.length == 0 && !echarts) {
-				console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
-				return
-			}
-			// #endif
-			let theme=null,opts={},callback;
-			// Array.from(arguments)
-			args.forEach(item => {
-				if(typeof item === 'function') {
-					callback = item
-				}
-				if(['string'].includes(typeof item)) {
-					theme = item
-				}
-				if(typeof item === 'object') {
-					opts = item
-				}
-			})
-			if(this.beforeDelay) {
-				await sleep(this.beforeDelay)
-			}
-			let config = await this.getContext();
-			// #ifndef APP-NVUE
-			setCanvasCreator(echarts, config)
-			try {
-				this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts || {}))
-				
-				callback?.(this.chart)
-				return this.chart
-			} catch(e) {
-				console.error("【lime-echarts】:", e)
-				return null
-			}
-			// #endif
-			// #ifdef APP-NVUE
-			this.chart = new Echarts(this.$refs.webview)
-			this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
-			callback?.(this.chart)
-			return this.chart
-			// #endif
-		},
-		getContext() {
-			// #ifdef APP-NVUE
-			if(this.finished) {
-				return Promise.resolve(this.finished)
-			}
-			return new Promise(resolve => {
-				this.$watch('finished', (val) => {
-					if(val) {
-						resolve(this.finished)
-					}
-				})
-			})
-			// #endif
-			// #ifndef APP-NVUE
-			return getRect(`#${this.canvasId}`, this, this.use2dCanvas).then(res => {
-				if(res) {
-					let dpr = devicePixelRatio
-					let {width, height, node} = res
-					let canvas;
-					this.width = width = width || 300;
-					this.height = height = height || 300;
-					if(node) {
-						const ctx = node.getContext('2d');
-						canvas = new Canvas(ctx, this, true, node);
-						this.canvasNode = node
-					} else {
-						// #ifdef MP-TOUTIAO
-						dpr = !this.isPC ? devicePixelRatio : 1// 1.25
-						// #endif
-						// #ifndef MP-ALIPAY || MP-TOUTIAO
-						dpr = this.isPC ? devicePixelRatio : 1
-						// #endif
-						// #ifdef MP-ALIPAY || MP-LARK
-						dpr = devicePixelRatio
-						// #endif
-						// #ifdef WEB
-						dpr = 1
-						// #endif
-						this.rect = res
-						this.nodeWidth = width * dpr;
-						this.nodeHeight = height * dpr;
-						const ctx = uni.createCanvasContext(this.canvasId, this);
-						canvas =  new Canvas(ctx, this, false);
-					}
-					
-					return { canvas, width, height, devicePixelRatio: dpr, node };
-				} else {
-					return {}
-				}
-			})
-			// #endif
-		},
-		// #ifndef APP-NVUE
-		getRelative(e, touches) {
-			let { clientX, clientY } = e
-			if(!(clientX && clientY) && touches && touches[0]) {
-				clientX = touches[0].clientX
-				clientY = touches[0].clientY
-			}
-			return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
-		},
-		getTouch(e, touches) {
-			const {x} = touches && touches[0] || {}
-			const touch = x ? touches[0] : this.getRelative(e, touches);
-			if(this.landscape) {
-				[touch.x, touch.y] = [touch.y, this.height - touch.x]
-			}
-			return touch;
-		},
-		touchStart(e) {
-			this.isDown = true
-			const next = () => {
-				const touches = convertTouchesToArray(e.touches)
-				if(this.chart) {
-					const touch = this.getTouch(e, touches)
-					this.startX = touch.x
-					this.startY = touch.y
-					this.startT = new Date()
-					const handler = this.chart.getZr().handler;
-					dispatch.call(handler, 'mousedown', touch)
-					dispatch.call(handler, 'mousemove', touch)
-					handler.processGesture(wrapTouch(e), 'start');
-					clearTimeout(this.endTimer);
-				}
-				
-			}
-			if(this.isPC) {
-				getRect(`#${this.canvasId}`, {context: this}).then(res => {
-					this.rect = res
-					next()
-				})
-				return
-			}
-			next()
-		},
-		touchMove(e) {
-			if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
-			const touches = convertTouchesToArray(e.touches)
-			if (this.chart && this.isDown) {
-				const handler = this.chart.getZr().handler;
-				dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
-				handler.processGesture(wrapTouch(e), 'change');
-			}
-			
-		},
-		touchEnd(e) {
-			this.isDown = false
-			if (this.chart) {
-				const touches = convertTouchesToArray(e.changedTouches)
-				const {x} = touches && touches[0] || {}
-				const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
-				if(this.landscape) {
-					[touch.x, touch.y] = [touch.y,  this.height - touch.x]
-				}
-				const handler = this.chart.getZr().handler;
-				const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
-				dispatch.call(handler, 'mouseup', touch)
-				handler.processGesture(wrapTouch(e), 'end');
-				if(isClick) {
-					dispatch.call(handler, 'click', touch)
-				} else {
-					this.endTimer = setTimeout(() => {
-						dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
-						dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
-					},50)
-				}
-			}
-		},
-		// #endif
-		// #ifdef H5
-		mousewheel(e){
-			if(this.chart) {
-				dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
-			}
-		}
-		// #endif
-	}
-};
-</script>
-<style>	
-.lime-echart {
-	position: relative;
-	/* #ifndef APP-NVUE */
-	width: 100%;
-	height: 100%;
-	/* #endif */
-	/* #ifdef APP-NVUE */
-	flex: 1;
-	/* #endif */
-}
-.lime-echart__canvas {
-	/* #ifndef APP-NVUE */
-	width: 100%;
-	height: 100%;
-	/* #endif */
-	/* #ifdef APP-NVUE */
-	flex: 1;
-	/* #endif */
-}
-/* #ifndef APP-NVUE */
-.lime-echart__mask {
-	position: absolute;
-	width: 100%;
-	height: 100%;
-	left: 0;
-	top: 0;
-	z-index: 1;
-}
-/* #endif */
-</style>

+ 0 - 56
src/uni_modules/lime-echart/components/l-echart/nvue.js

@@ -1,56 +0,0 @@
-export class Echarts {
-	eventMap = new Map()
-	constructor(webview) {
-		this.webview = webview
-		this.options = null
-	}
-	setOption() {
-		this.options = arguments
-		console.log('setOption1')
-		this.webview.evalJs(`setOption(${JSON.stringify(arguments)})`);
-	}
-	getOption() {
-		return this.options
-	}
-	showLoading() {
-		this.webview.evalJs(`showLoading(${JSON.stringify(arguments)})`);
-	}
-	hideLoading() {
-		this.webview.evalJs(`hideLoading()`);
-	}
-	clear() {
-		this.webview.evalJs(`clear()`);
-	}
-	dispose() {
-		this.webview.evalJs(`dispose()`);
-	}
-	resize(size) {
-		if(size) {
-			this.webview.evalJs(`resize(${JSON.stringify(size)})`);
-		} else {
-			this.webview.evalJs(`resize()`);
-		}
-	}
-	on(type, ...args) {
-		const query = args[0]
-		const useQuery = query && typeof query != 'function'
-		const param = useQuery ? [type, query] : [type]
-		const key = `${type}${useQuery ? JSON.stringify(query): '' }`
-		const callback = useQuery ? args[1]: args[0]
-		if(typeof callback == 'function'){
-			this.eventMap.set(key, callback)
-		}
-		this.webview.evalJs(`on(${JSON.stringify(param)})`);
-		console.warn('nvue 暂不支持事件')
-	}
-	dispatchAction(type, options){
-		const handler = this.eventMap.get(type)
-		if(handler){
-			handler(options)
-		}
-	}
-	// 不让报错 无实际作用
-	isDisposed() {
-		return !!this.webview
-	}
-}

+ 0 - 27
src/uni_modules/lime-echart/components/l-echart/props.ts

@@ -1,27 +0,0 @@
-export default {
-	// #ifdef MP-WEIXIN || MP-TOUTIAO
-	type: {
-		type: String,
-		default: '2d'
-	},
-	// #endif
-	// #ifdef APP-NVUE
-	webviewStyles: Object,
-	// #endif
-	lStyle: String,
-	isDisableScroll: Boolean,
-	isClickable: {
-		type: Boolean,
-		default: true
-	},
-	enableHover: Boolean,
-	beforeDelay: {
-		type: Number,
-		default: 30
-	},
-	landscape: Boolean,
-	autoHideTooltip: {
-		type: Boolean,
-		default: false
-	}
-}

+ 0 - 11
src/uni_modules/lime-echart/components/l-echart/type.ts

@@ -1,11 +0,0 @@
-// @ts-nocheck
-export interface echartsProps {
-	webviewStyles?: UTSJSONObject,
-	lStyle?: string | UTSJSONObject
-	isDisableScroll: boolean;
-	isClickable: boolean;
-	enableHover: boolean;
-	beforeDelay: number;
-	landscape: boolean;
-	autoHideTooltip: boolean;
-}

+ 0 - 181
src/uni_modules/lime-echart/components/l-echart/utils.js

@@ -1,181 +0,0 @@
-// @ts-nocheck
-/**
- * 获取设备基础信息
- *
- * @see [uni.getDeviceInfo](https://uniapp.dcloud.net.cn/api/system/getDeviceInfo.html)
- */
-export function getDeviceInfo() {
-	if (uni.getDeviceInfo || uni.canIUse('getDeviceInfo')) {
-		return uni.getDeviceInfo();
-	} else {
-		return uni.getSystemInfoSync();
-	}
-}
-
-/**
- * 获取窗口信息
- *
- * @see [uni.getWindowInfo](https://uniapp.dcloud.net.cn/api/system/getWindowInfo.html)
- */
-export function getWindowInfo() {
-	if (uni.getWindowInfo || uni.canIUse('getWindowInfo')) {
-		return uni.getWindowInfo();
-	} else {
-		return uni.getSystemInfoSync();
-	}
-}
-
-/**
- * 获取APP基础信息
- *
- * @see [uni.getAppBaseInfo](https://uniapp.dcloud.net.cn/api/system/getAppBaseInfo.html)
- */
-export function getAppBaseInfo() {
-	if (uni.getAppBaseInfo || uni.canIUse('getAppBaseInfo')) {
-		return uni.getAppBaseInfo();
-	} else {
-		return uni.getSystemInfoSync();
-	}
-}
-
-
-// #ifndef APP-NVUE
-// 计算版本
-export function compareVersion(v1, v2) {
-	v1 = v1.split('.')
-	v2 = v2.split('.')
-	const len = Math.max(v1.length, v2.length)
-	while (v1.length < len) {
-		v1.push('0')
-	}
-	while (v2.length < len) {
-		v2.push('0')
-	}
-	for (let i = 0; i < len; i++) {
-		const num1 = parseInt(v1[i], 10)
-		const num2 = parseInt(v2[i], 10)
-
-		if (num1 > num2) {
-			return 1
-		} else if (num1 < num2) {
-			return -1
-		}
-	}
-	return 0
-}
-// const systemInfo = uni.getSystemInfoSync();
-
-function gte(version) {
-	// 截止 2023-03-22 mac pc小程序不支持 canvas 2d
-	// let {
-	// 	SDKVersion,
-	// 	platform
-	// } = systemInfo;
-	const { platform } = getDeviceInfo();
-	let { SDKVersion } = getAppBaseInfo();
-	// #ifdef MP-ALIPAY
-	SDKVersion = my.SDKVersion
-	// #endif
-	// #ifdef MP-WEIXIN
-	return platform !== 'mac' && compareVersion(SDKVersion, version) >= 0;
-	// #endif
-	return compareVersion(SDKVersion, version) >= 0;
-}
-
-
-export function canIUseCanvas2d() {
-	// #ifdef MP-WEIXIN
-	return gte('2.9.0');
-	// #endif
-	// #ifdef MP-ALIPAY
-	return gte('2.7.0');
-	// #endif
-	// #ifdef MP-TOUTIAO
-	return gte('1.78.0');
-	// #endif
-	return false
-}
-
-export function convertTouchesToArray(touches) {
-	// 如果 touches 是一个数组,则直接返回它
-	if (Array.isArray(touches)) {
-		return touches;
-	}
-	// 如果touches是一个对象,则转换为数组
-	if (typeof touches === 'object' && touches !== null) {
-		return Object.values(touches);
-	}
-	// 对于其他类型,直接返回它
-	return touches;
-}
-
-export function wrapTouch(event) {
-	event.touches = convertTouchesToArray(event.touches)
-	for (let i = 0; i < event.touches.length; ++i) {
-		const touch = event.touches[i];
-		touch.offsetX = touch.x;
-		touch.offsetY = touch.y;
-	}
-	return event;
-}
-// export const devicePixelRatio = uni.getSystemInfoSync().pixelRatio
-export const devicePixelRatio = getWindowInfo().pixelRatio;
-// #endif
-// #ifdef APP-NVUE
-export function base64ToPath(base64) {
-	return new Promise((resolve, reject) => {
-		const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
-		const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
-		bitmap.loadBase64Data(base64, () => {
-			if (!format) {
-				reject(new Error('ERROR_BASE64SRC_PARSE'))
-			}
-			const time = new Date().getTime();
-			const filePath = `_doc/uniapp_temp/${time}.${format}`
-
-			bitmap.save(filePath, {},
-				() => {
-					bitmap.clear()
-					resolve(filePath)
-				},
-				(error) => {
-					bitmap.clear()
-					console.error(`${JSON.stringify(error)}`)
-					reject(error)
-				})
-		}, (error) => {
-			bitmap.clear()
-			console.error(`${JSON.stringify(error)}`)
-			reject(error)
-		})
-	})
-}
-// #endif
-
-
-export function sleep(time) {
-	return new Promise((resolve) => {
-		setTimeout(() => {
-			resolve(true)
-		}, time)
-	})
-}
-
-
-export function getRect(selector, context) {
-	return new Promise((resolve, reject) => {
-		const dom = uni.createSelectorQuery().in(context).select(selector);
-		const result = (rect) => {
-			if (rect) {
-				resolve(rect)
-			} else {
-				reject()
-			}
-		}
-		dom.fields({
-			node: true,
-			size: true,
-			rect: true
-		}, result).exec()
-	});
-};

+ 0 - 136
src/uni_modules/lime-echart/components/l-echart/uvue.uts

@@ -1,136 +0,0 @@
-// @ts-nocheck
-// #ifdef APP
-type EchartsEventHandler = (event: UTSJSONObject)=>void
-// type EchartsTempResolve = (obj : UTSJSONObject) => void
-// type EchartsTempOptions = UTSJSONObject
-export class Echarts {
-	options: UTSJSONObject = {} as UTSJSONObject
-	context: UniWebViewElement
-	eventMap: Map<string, EchartsEventHandler> = new Map()
-	private temp: UTSJSONObject[] = []
-	constructor(context: UniWebViewElement){
-		this.context = context
-		this.init()
-	}
-	init(){
-		this.context.evalJS(`init(null, null, ${JSON.stringify({})})`)
-		
-		this.context.addEventListener('message', (e : UniWebViewMessageEvent) => {
-			// event.stopPropagation()
-			// event.preventDefault()
-			
-			const detail = e.detail.data[0]
-			const file = detail.getString('file')
-			const data = detail.get('data')
-			const key = detail.getString('event')
-			const options = typeof data == 'object' ? (data as UTSJSONObject).getJSON('options'): null
-			const event = typeof data == 'object' ? (data as UTSJSONObject).getString('event'): null
-			if (key == 'log' && data != null) {
-				console.log(data)
-			}
-			if (event != null && options != null) {
-				this.dispatchAction(event.replace(/"/g,''), options)
-			}
-			if(file != null){
-				while (this.temp.length > 0) {
-					const opt = this.temp.pop()
-					const success = opt?.get('success')
-					if(typeof success == 'function'){
-						success as (res: UTSJSONObject) => void
-						success({tempFilePath: file})
-					}
-				}
-			}
-			
-		})
-	}
-	setOption(option: UTSJSONObject){
-		this.options = option;
-		this.context.evalJS(`setOption(${JSON.stringify([option])})`)
-	}
-	setOption(option: UTSJSONObject, notMerge: boolean = false, lazyUpdate: boolean = false){
-		this.options = option;
-		this.context.evalJS(`setOption(${JSON.stringify([option, notMerge, lazyUpdate])})`)
-	}
-	setOption(option: UTSJSONObject, notMerge: UTSJSONObject){
-		this.options = option;
-		this.context.evalJS(`setOption(${JSON.stringify([option, notMerge])})`)
-	}
-	getOption(): UTSJSONObject {
-		return this.options
-	}
-	showLoading(){
-		this.context.evalJS(`showLoading(${JSON.stringify([] as any[])})`);
-	}
-	showLoading(type: string, opts: UTSJSONObject){
-		this.context.evalJS(`showLoading(${JSON.stringify([type, opts])})`);
-	}
-	hideLoading(){
-		this.context.evalJS(`hideLoading()`);
-	}
-	clear(){
-		this.context.evalJS(`clear()`);
-	}
-	dispose(){
-		this.context.evalJS(`dispose()`);
-	}
-	resize(size:UTSJSONObject){
-		setTimeout(()=>{
-			this.context.evalJS(`resize(${JSON.stringify(size)})`);
-		},0)
-	}
-	resize(){
-		setTimeout(()=>{
-			this.context.evalJS(`resize()`);
-		},10)
-		
-	}
-	on(type:string, query: any, callback: EchartsEventHandler) {
-		const key = `${type}${JSON.stringify(query)}`
-		if(typeof callback == 'function'){
-			this.eventMap.set(key, callback)
-		}
-		this.context.evalJS(`on(${JSON.stringify([type, query])})`);
-		console.warn('uvue 暂不支持事件')
-	}
-	on(type:string, callback: EchartsEventHandler) {
-		const key = `${type}`
-		if(typeof callback == 'function'){
-			this.eventMap.set(key, callback)
-		}
-		this.context.evalJS(`on(${JSON.stringify([type])})`);
-		console.warn('uvue 暂不支持事件')
-	}
-	dispatchAction(type:string, options: UTSJSONObject){
-		const handler = this.eventMap.get(type)
-		if(handler!=null){
-			handler(options)
-		}
-	}
-	canvasToTempFilePath(opt: UTSJSONObject){
-		// this.context.evalJS(`on(${JSON.stringify(opt)})`);
-		this.context.evalJS(`canvasToTempFilePath(${JSON.stringify(opt)})`);
-		this.temp.push(opt)
-	}
-	isDisposed():boolean {
-		return false
-	}
-}
-
-// #endif
-// #ifndef APP
-export class Echarts {
-	constructor() {}
-	setOption(option: UTSJSONObject): void
-	isDisposed(): boolean;
-	clear(): void;
-	resize(size:UTSJSONObject): void;
-	resize(): void;
-	canvasToTempFilePath(opt : UTSJSONObject): void;
-	dispose(): void;
-	showLoading(cfg?: UTSJSONObject): void;
-	showLoading(name?: string, cfg?: UTSJSONObject): void;
-	hideLoading(): void;
-	getZr(): any
-}
-// #endif

+ 0 - 16
src/uni_modules/lime-echart/components/l-echart/vue.ts

@@ -1,16 +0,0 @@
-// @ts-nocheck
-
-// #ifdef VUE3
-export * from 'vue';
-// #endif
-
-// #ifndef VUE3
-export * from '@vue/composition-api';
-
-// #ifdef APP-NVUE
-import Vue from 'vue'
-import VueCompositionAPI from '@vue/composition-api'
-Vue.use(VueCompositionAPI)
-// #endif
-
-// #endif

+ 0 - 0
src/uni_modules/lime-echart/components/lime-echart/index.vue


+ 0 - 227
src/uni_modules/lime-echart/components/lime-echart/lime-echart-old.vue

@@ -1,227 +0,0 @@
-<template>
-  <view>
-    <view style="height: 750rpx; position: relative">
-      <l-echart ref="chart" @finished="init"></l-echart>
-      <view
-        class="customTooltips"
-        :style="{ left: position[0] + 'px', top: position[1] + 'px' }"
-        v-if="params.length && position.length && showTip"
-      >
-        <view>这是个自定的tooltips</view>
-        <view>{{ params[0]['axisValue'] }}</view>
-        <view v-for="item in params">
-          <view>
-            <text>{{ item.seriesName }}</text>
-            <text>{{ item.value }}</text>
-          </view>
-        </view>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script>
-// nvue 不需要引入
-// #ifdef VUE2
-import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
-// #endif
-// #ifdef VUE3
-// #ifdef MP
-// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
-const echarts = require('../../static/echarts.min')
-// #endif
-// #ifndef MP
-// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
-import * as echarts from 'echarts/dist/echarts.esm'
-// #endif
-// #endif
-export default {
-  data() {
-    return {
-      showTip: false,
-      position: [],
-      params: [],
-      option: {
-        tooltip: {
-          trigger: 'axis',
-          // shadowBlur: 0,
-          textStyle: {
-            textShadowBlur: 0,
-          },
-          renderMode: 'richText',
-          position: (point, params, dom, rect, size) => {
-            // 假设自定义的tooltips尺寸
-            const box = [170, 170]
-            // 偏移
-            const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20
-            const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20
-            const x = point[0] + offsetX
-            const y = point[1] + offsetY
-
-            this.position = [x, y]
-            this.params = params
-          },
-          formatter: (params, ticket, callback) => {},
-        },
-        legend: {
-          data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true,
-        },
-        xAxis: {
-          type: 'category',
-          boundaryGap: false,
-          data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
-        },
-        yAxis: {
-          type: 'value',
-        },
-        series: [
-          {
-            name: '邮件营销',
-            type: 'line',
-            stack: '总量',
-            data: [120, 132, 101, 134, 90, 230, 210],
-          },
-          {
-            name: '联盟广告',
-            type: 'line',
-            stack: '总量',
-            data: [220, 182, 191, 234, 290, 330, 310],
-          },
-          {
-            name: '视频广告',
-            type: 'line',
-            stack: '总量',
-            data: [150, 232, 201, 154, 190, 330, 410],
-          },
-          {
-            name: '直接访问',
-            type: 'line',
-            stack: '总量',
-            data: [320, 332, 301, 334, 390, 330, 320],
-          },
-          {
-            name: '搜索引擎',
-            type: 'line',
-            stack: '总量',
-            data: [820, 932, 901, 934, 1290, 1330, 1320],
-          },
-        ],
-      },
-    }
-  },
-
-  methods: {
-    init() {
-      // init(echarts, theme?:string, opts?:{}, chart => {})
-      // echarts 必填, 非nvue必填,nvue不用填
-      // theme 可选,应用的主题,目前只支持名称,如:'dark'
-      // opts = { // 可选
-      //	locale?: string  // 从 `5.0.0` 开始支持
-      // }
-      // chart => {} , callback 返回图表实例
-      // setTimeout(()=>{
-      // 	this.$refs.chart.init(echarts, chart => {
-      // 		chart.setOption(this.option);
-      // 	});
-      // },300)
-      this.$refs.chart.init(echarts, (chart) => {
-        chart.setOption(this.option)
-
-        // 监听tooltip显示事件
-        chart.on('showTip', (params) => {
-          this.showTip = true
-          console.log('showTip::')
-        })
-        chart.on('hideTip', (params) => {
-          setTimeout(() => {
-            this.showTip = false
-          }, 300)
-        })
-
-        setTimeout(() => {
-          const option = {
-            tooltip: {
-              trigger: 'axis',
-              // shadowBlur: 0,
-              textStyle: {
-                textShadowBlur: 0,
-              },
-              renderMode: 'richText',
-            },
-            legend: {
-              data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
-            },
-            grid: {
-              left: '3%',
-              right: '4%',
-              bottom: '3%',
-              containLabel: true,
-            },
-            xAxis: {
-              type: 'category',
-              boundaryGap: false,
-              data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
-            },
-            yAxis: {
-              type: 'value',
-            },
-            series: [
-              {
-                name: '邮件营销',
-                type: 'line',
-                stack: '总量',
-                data: [1120, 132, 101, 134, 90, 230, 210],
-              },
-              {
-                name: '联盟广告',
-                type: 'line',
-                stack: '总量',
-                data: [220, 182, 191, 234, 290, 330, 310],
-              },
-              {
-                name: '视频广告',
-                type: 'line',
-                stack: '总量',
-                data: [150, 632, 201, 154, 190, 330, 410],
-              },
-              {
-                name: '直接访问',
-                type: 'line',
-                stack: '总量',
-                data: [820, 332, 301, 334, 390, 330, 320],
-              },
-              {
-                name: '搜索引擎',
-                type: 'line',
-                stack: '总量',
-                data: [820, 932, 901, 934, 1290, 1330, 1320],
-              },
-            ],
-          }
-          chart.setOption(option)
-        }, 1000)
-      })
-    },
-    save() {
-      this.$refs.chart.canvasToTempFilePath({
-        success(res) {
-          console.log('res::::', res)
-        },
-      })
-    },
-  },
-}
-</script>
-<style>
-.customTooltips {
-  position: absolute;
-  background-color: rgba(255, 255, 255, 0.8);
-  padding: 20rpx;
-}
-</style>

+ 0 - 159
src/uni_modules/lime-echart/components/lime-echart/lime-echart.nvue

@@ -1,159 +0,0 @@
-<template>
-	<view style="width: 100%; height: 408px;">
-		<l-echart ref="chartRef" @finished="init"></l-echart>
-	</view>
-</template>
-
-<script>
-	export default {
-		data() {
-			return {
-				showTip: false,
-				option: {
-					tooltip: {
-						trigger: 'axis',
-						// shadowBlur: 0,
-						textStyle: {
-							textShadowBlur: 0
-						},
-						renderMode: 'richText',
-					},
-					legend: {
-						data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-					},
-					grid: {
-						left: '3%',
-						right: '4%',
-						bottom: '3%',
-						containLabel: true
-					},
-					xAxis: {
-						type: 'category',
-						boundaryGap: false,
-						data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
-					},
-					yAxis: {
-						type: 'value'
-					},
-					series: [
-						{
-							name: '邮件营销',
-							type: 'line',
-							stack: '总量',
-							data: [120, 132, 101, 134, 90, 230, 210]
-						},
-						{
-							name: '联盟广告',
-							type: 'line',
-							stack: '总量',
-							data: [220, 182, 191, 234, 290, 330, 310]
-						},
-						{
-							name: '视频广告',
-							type: 'line',
-							stack: '总量',
-							data: [150, 232, 201, 154, 190, 330, 410]
-						},
-						{
-							name: '直接访问',
-							type: 'line',
-							stack: '总量',
-							data: [320, 332, 301, 334, 390, 330, 320]
-						},
-						{
-							name: '搜索引擎',
-							type: 'line',
-							stack: '总量',
-							data: [820, 932, 901, 934, 1290, 1330, 1320]
-						}
-					]
-				}
-			}
-		},
-		mounted() {
-			console.log('lime echarts nvue')
-		},
-		methods: {
-			init() {
-				const chartRef = this.$refs['chartRef']
-				chartRef.init(chart => {
-					chart.setOption(this.option);
-					
-					
-					setTimeout(()=>{
-						const option = {
-							tooltip: {
-								trigger: 'axis',
-								// shadowBlur: 0,
-								textStyle: {
-									textShadowBlur: 0
-								},
-								renderMode: 'richText',
-							},
-							legend: {
-								data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-							},
-							grid: {
-								left: '3%',
-								right: '4%',
-								bottom: '3%',
-								containLabel: true
-							},
-							xAxis: {
-								type: 'category',
-								boundaryGap: false,
-								data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
-							},
-							yAxis: {
-								type: 'value'
-							},
-							series: [
-								{
-									name: '邮件营销',
-									type: 'line',
-									stack: '总量',
-									data: [120, 132, 101, 134, 90, 230, 210]
-								},
-								{
-									name: '联盟广告',
-									type: 'line',
-									stack: '总量',
-									data: [220, 182, 191, 234, 290, 330, 310]
-								},
-								{
-									name: '视频广告',
-									type: 'line',
-									stack: '总量',
-									data: [150, 232, 201, 154, 190, 330, 410]
-								},
-								{
-									name: '直接访问',
-									type: 'line',
-									stack: '总量',
-									data: [320, 332, 301, 334, 390, 330, 320]
-								},
-								{
-									name: '搜索引擎',
-									type: 'line',
-									stack: '总量',
-									data: [820, 932, 901, 934, 1290, 1330, 1320]
-								}
-							]
-						}
-						chart.setOption(option);
-					},1000)
-				})
-			},
-			save() {
-				// this.$refs.chart.canvasToTempFilePath({
-				// 	success(res) {
-				// 		console.log('res::::', res)
-				// 	}
-				// })
-			}
-		}
-	}
-</script>
-<style>
-
-</style>

+ 0 - 158
src/uni_modules/lime-echart/components/lime-echart/lime-echart.uvue

@@ -1,158 +0,0 @@
-<template>
-	<view style="width: 100%; height: 408px;">
-		<l-echart ref="chartRef" @finished="init"></l-echart>
-	</view>
-</template>
-
-<script lang="uts" setup>
-	// #ifdef MP
-	// 引入小程序依赖包,require只能是当前文件的相对路径
-	const echarts = require('../../../../static/echarts.min.js')
-	// #endif
-	// #ifndef MP
-	// 非小程序不需要引入
-	const echarts = null
-	// #endif
-	const chartRef = ref<LEchartComponentPublicInstance|null>(null)
-	const option = {
-		tooltip: {
-			trigger: 'axis',
-			// shadowBlur: 0,
-			textStyle: {
-				textShadowBlur: 0
-			},
-			renderMode: 'richText',
-		},
-		// formatter: async (params: any) => {
-		// 	console.log('params', params)
-		// 	return 1
-		// },
-		legend: {
-			data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-		},
-		// grid: {
-		// 	left: '3%',
-		// 	right: '4%',
-		// 	bottom: '3%',
-		// 	containLabel: true
-		// },
-		xAxis: {
-			type: 'category',
-			boundaryGap: false,
-			data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
-		},
-		yAxis: {
-			type: 'value'
-		},
-		series: [
-			{
-				name: '邮件营销',
-				type: 'line',
-				stack: '总量',
-				data: [120, 132, 101, 134, 90, 230, 210]
-			},
-			{
-				name: '联盟广告',
-				type: 'line',
-				stack: '总量',
-				data: [220, 182, 191, 234, 290, 330, 310]
-			},
-			{
-				name: '视频广告',
-				type: 'line',
-				stack: '总量',
-				data: [150, 232, 201, 154, 190, 330, 410]
-			},
-			{
-				name: '直接访问',
-				type: 'line',
-				stack: '总量',
-				data: [320, 332, 301, 334, 390, 330, 320]
-			},
-			{
-				name: '搜索引擎',
-				type: 'line',
-				stack: '总量',
-				data: [820, 932, 901, 934, 1290, 1330, 1320]
-			}
-		]
-	}
-
-	const init = async () =>{
-		if(chartRef.value== null) return
-		const chart = await chartRef.value!.init(echarts)
-		chart.setOption(option)
-		// chart.on('mouseover', function (params) {
-		//     console.log('params', params);
-		// });
-		
-		
-		// setTimeout(()=> {
-		// 	const option1 = {
-		// 		tooltip: {
-		// 			trigger: 'axis',
-		// 			// shadowBlur: 0,
-		// 			textStyle: {
-		// 				textShadowBlur: 0
-		// 			},
-		// 			renderMode: 'richText',
-		// 		},
-		// 		legend: {
-		// 			data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
-		// 		},
-		// 		grid: {
-		// 			left: '3%',
-		// 			right: '4%',
-		// 			bottom: '3%',
-		// 			containLabel: true
-		// 		},
-		// 		xAxis: {
-		// 			type: 'category',
-		// 			boundaryGap: false,
-		// 			data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
-		// 		},
-		// 		yAxis: {
-		// 			type: 'value'
-		// 		},
-		// 		series: [
-		// 			{
-		// 				name: '邮件营销',
-		// 				type: 'line',
-		// 				stack: '总量',
-		// 				data: [820, 132, 101, 134, 90, 230, 210]
-		// 			},
-		// 			{
-		// 				name: '联盟广告',
-		// 				type: 'line',
-		// 				stack: '总量',
-		// 				data: [220, 182, 191, 234, 290, 330, 310]
-		// 			},
-		// 			{
-		// 				name: '视频广告',
-		// 				type: 'line',
-		// 				stack: '总量',
-		// 				data: [950, 232, 201, 154, 190, 330, 410]
-		// 			},
-		// 			{
-		// 				name: '直接访问',
-		// 				type: 'line',
-		// 				stack: '总量',
-		// 				data: [320, 332, 301, 334, 390, 330, 320]
-		// 			},
-		// 			{
-		// 				name: '搜索引擎',
-		// 				type: 'line',
-		// 				stack: '总量',
-		// 				data: [820, 932, 901, 934, 1290, 1330, 1320]
-		// 			}
-		// 		]
-		// 	}
-		// 	chart.setOption(option1)
-		// },1000)
-	}
-	
-
-</script>
-<style>
-
-</style>

+ 0 - 152
src/uni_modules/lime-echart/components/lime-echart/lime-echart.vue

@@ -1,152 +0,0 @@
-<template>
-	<view>
-		<view style="height: 750rpx; position: relative">
-			<l-echart ref="chart" @finished="init"></l-echart>
-			<view class="customTooltips" :style="{ left: position[0] + 'px', top: position[1] + 'px' }"
-				v-if="params.length && position.length && showTip">
-				<view>这是个自定的tooltips</view>
-				<view>{{ params[0]['axisValue'] }}</view>
-				<view v-for="item in params">
-					<view>
-						<text>{{ item.seriesName }}</text>
-						<text>{{ item.value }}</text>
-					</view>
-				</view>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	// #ifdef MP
-	// 引入小程序依赖包,require只能是当前文件的相对路径
-	const echarts = require('../../../../static/echarts.min.js');
-	// #endif
-	// #ifndef MP
-	// 非小程序不需要引入
-	const echarts = null
-	// #endif
-	export default {
-		data() {
-			return {
-				showTip: false,
-				position: [],
-				params: [],
-				option: {
-					tooltip: {
-						trigger: 'axis',
-						// shadowBlur: 0,
-						textStyle: {
-							textShadowBlur: 0,
-						},
-						renderMode: 'richText',
-						position: (point, params, dom, rect, size) => {
-							// 假设自定义的tooltips尺寸
-							const box = [170, 170]
-							// 偏移
-							const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20
-							const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20
-							const x = point[0] + offsetX
-							const y = point[1] + offsetY
-
-							this.position = [x, y]
-							this.params = params
-						},
-						formatter: (params, ticket, callback) => {},
-					},
-					legend: {
-						data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
-					},
-					// grid: {
-					// 	left: '3%',
-					// 	right: '4%',
-					// 	bottom: '3%',
-					// 	containLabel: true,
-					// },
-					xAxis: {
-						type: 'category',
-						boundaryGap: false,
-						data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
-					},
-					yAxis: {
-						type: 'value',
-					},
-					series: [{
-							name: '邮件营销',
-							type: 'line',
-							stack: '总量',
-							data: [120, 132, 101, 134, 90, 230, 210],
-						},
-						{
-							name: '联盟广告',
-							type: 'line',
-							stack: '总量',
-							data: [220, 182, 191, 234, 290, 330, 310],
-						},
-						{
-							name: '视频广告',
-							type: 'line',
-							stack: '总量',
-							data: [150, 232, 201, 154, 190, 330, 410],
-						},
-						{
-							name: '直接访问',
-							type: 'line',
-							stack: '总量',
-							data: [320, 332, 301, 334, 390, 330, 320],
-						},
-						{
-							name: '搜索引擎',
-							type: 'line',
-							stack: '总量',
-							data: [820, 932, 901, 934, 1290, 1330, 1320],
-						},
-					],
-				},
-			}
-		},
-
-		methods: {
-			async init() {
-				// init(echarts, theme?:string, opts?:{}, chart => {})
-				// echarts 必填, 非nvue必填,nvue不用填
-				// theme 可选,应用的主题,目前只支持名称,如:'dark'
-				// opts = { // 可选
-				//	locale?: string  // 从 `5.0.0` 开始支持
-				// }
-				// chart => {} , callback 返回图表实例
-				// setTimeout(()=>{
-				// 	this.$refs.chart.init(echarts, chart => {
-				// 		chart.setOption(this.option);
-				// 	});
-				// },300)
-				const chart = await this.$refs.chart.init(echarts)
-				chart.setOption(this.option)
-				// 监听tooltip显示事件
-				chart.on('showTip', (params) => {
-					this.showTip = true
-					console.log('showTip::')
-				})
-				chart.on('hideTip', (params) => {
-					setTimeout(() => {
-						this.showTip = false
-					}, 300)
-				})
-			},
-			save() {
-				this.$refs.chart.canvasToTempFilePath({
-					success(res) {
-						console.log('res::::', res)
-					},
-				})
-			},
-		},
-	}
-</script>
-<style>
-	.customTooltips {
-		position: absolute;
-		background-color: rgba(255, 255, 255, 0.8);
-		padding: 20rpx;
-	}
-</style>

+ 0 - 110
src/uni_modules/lime-echart/package.json

@@ -1,110 +0,0 @@
-{
-  "id": "lime-echart",
-  "displayName": "lime-echart echarts图表",
-  "version": "2.0.3",
-  "description": "lime-echart 为 UniApp 和 UniAppX 提供 ECharts 图表兼容支持, 使 ECharts 图表能在H5、小程序、App中运行",
-  "keywords": [
-    "echarts",
-    "canvas",
-    "图表",
-    "可视化"
-],
-  "repository": "https://gitee.com/liangei/lime-echart",
-  "engines": {
-    "HBuilderX": "^3.6.4",
-    "uni-app": "^4.65",
-    "uni-app-x": "^4.71"
-  },
-  "dcloudext": {
-    "sale": {
-      "regular": {
-        "price": "0.00"
-      },
-      "sourcecode": {
-        "price": "0.00"
-      }
-    },
-    "contact": {
-      "qq": ""
-    },
-    "declaration": {
-      "ads": "无",
-      "data": "无",
-      "permissions": "无"
-    },
-    "npmurl": "",
-    "type": "component-vue",
-    "darkmode": "x",
-    "i18n": "x",
-    "widescreen": "x"
-  },
-  "uni_modules": {
-    "dependencies": [],
-    "encrypt": [],
-    "platforms": {
-      "cloud": {
-        "tcb": "√",
-        "aliyun": "√",
-        "alipay": "x"
-      },
-      "client": {
-        "uni-app": {
-          "vue": {
-            "vue2": "√",
-            "vue3": "√"
-          },
-          "web": {
-            "safari": "√",
-            "chrome": "√"
-          },
-          "app": {
-            "vue": "√",
-            "nvue": "√",
-            "android": {
-                "extVersion": "",
-                "minVersion": "21"
-            },
-            "ios": "√",
-            "harmony": "√"
-          },
-          "mp": {
-            "weixin": "√",
-            "alipay": "√",
-            "toutiao": "√",
-            "baidu": "√",
-            "kuaishou": "√",
-            "jd": "√",
-            "harmony": "-",
-            "qq": "√",
-            "lark": "√"
-          },
-          "quickapp": {
-            "huawei": "-",
-            "union": "-"
-          }
-        },
-        "uni-app-x": {
-          "web": {
-            "safari": "√",
-            "chrome": "√"
-          },
-          "app": {
-            "android": {
-                "extVersion": "",
-                "minVersion": "21"
-            },
-            "ios": "√",
-            "harmony": "√"
-          },
-          "mp": {
-            "weixin": "√"
-          }
-        }
-      }
-    }
-  },
-  "dependencies": {
-    "echarts": "^5.4.1",
-    "zrender": "^5.4.3"
-  }
-}

+ 0 - 499
src/uni_modules/lime-echart/readme.md

@@ -1,499 +0,0 @@
-# lime-echart 📊
-
-为 UniApp 和 UniAppX 提供 ECharts 图表兼容支持,使 ECharts 图表能在 H5、小程序、App 等多端环境中正常运行。
-
-## 特性 ✨
-
-- 📱 **跨平台兼容**:支持 H5、微信小程序、支付宝小程序、App 等多端
-- 🎯 **简单易用**:统一 API,使用方式与原生 ECharts 基本一致
-- ⚡ **性能优化**:针对不同平台进行了渲染优化
-- 🔄 **双框架支持**:同时支持 uni-app 和 uni-app-x
-
-## 文档与示例 📚
-
-更多详细文档与示例:
-- [lime-echart 组件文档](https://limeui.qcoon.cn/#/echart)
-- [在线示例](https://limeui.qcoon.cn/#/echart-example)
-- [ECharts 官方示例](https://echarts.apache.org/examples/zh/index.html)
-- [lime-echart 组件文档2](https://limex.qcoon.cn/components/echart.html) (将来用到,目前未上线)
-
-## 安装方法 📦
-
-### 插件市场安装
-
-1. 在uni-app插件市场中搜索并导入`lime-echart`
-2. 导入后重新编译项目
-3. 在页面中直接使用 `l-echart` 组件
-
-### CLI 项目安装
-
-```bash
-# 下载插件到项目的 src/uni_modules 目录
-mkdir -p src/uni_modules
-# 将插件解压到上述目录
-```
-
-## 前置依赖 ⚙️
-
-### 小程序平台(重点说明)
-
-小程序平台必须下载并引入 ECharts 自定义构建包:
-
-1. 小程序中引入ECharts有两种方式:
-   - **本地构建文件**
-     - 访问 [ECharts 在线构建](https://echarts.apache.org/zh/builder.html) 下载所需图表类型的精简版
-     - 注意:在线构建工具**仅支持生成UMD格式**(默认,`echarts.min.js`),通过 `require` 引入
-   - 建议只勾选项目所需的图表类型和组件,以减小文件体积
-
-2. **文件放置位置**:
-   - 📁 **主包**:将文件放入项目根目录的 `static` 文件夹
-   - 📁 **分包**:将文件放入对应分包的 `static` 文件夹(如 `pagesB/static/`)
-
-3. **相对路径引用示例**:
-   ```js
-   // UMD格式 - 页面位于主包根目录 - 相对路径引用示例(仅在线构建或本地文件使用)
-   // ├─pages
-   // │  └─index
-   // │     └─index.vue
-   // └─static
-   const echarts = require('../../static/echarts.min.js')
-   
-   // UMD格式 - 页面位于主包三层目录 - 相对路径引用示例(仅在线构建或本地文件使用)
-   // ├─pages
-   // │  └─user
-   // │     └─settings
-   // │        └─profile.vue
-   // └─static
-   const echarts = require('../../../static/echarts.min.js')
-   
-   // UMD格式 - 页面位于分包中 - 相对路径引用示例(仅在线构建或本地文件使用)
-   // ├─pagesB (分包)
-   // │  ├─static
-   // │  └─detail
-   // │     └─detail.vue
-   const echarts = require('../static/echarts.min.js')
-   
-   // ES模块格式 
-   import * as echarts from 'echarts'
-   ```
-
-   > 注意:
-   > - `require` 是小程序平台特有的API,仅在小程序环境下使用
-   > - 路径是相对于当前页面文件的路径,请根据实际项目结构调整路径
-
-
-## 使用示例 🎯
-
-### 图表配置项示例
-
-以下是一个柱状图的配置项示例,在后续使用示例中将引用此配置:
-
-```js
-// 图表配置项示例 - 柱状图
-const chartOption = {
-  tooltip: {
-    trigger: 'axis',
-    axisPointer: {
-      type: 'shadow'
-    },
-    confine: true
-  },
-  legend: {
-    data: ['热度', '正面', '负面']
-  },
-  xAxis: [
-    {
-      type: 'value',
-      axisLine: {
-        lineStyle: {
-          color: '#999999'
-        }
-      },
-      axisLabel: {
-        color: '#666666'
-      }
-    }
-  ],
-  yAxis: [
-    {
-      type: 'category',
-      axisTick: { show: false },
-      data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
-      axisLine: {
-        lineStyle: {
-          color: '#999999'
-        }
-      },
-      axisLabel: {
-        color: '#666666'
-      }
-    }
-  ],
-  series: [
-    {
-      name: '热度',
-      type: 'bar',
-      label: {
-        show: true,
-        position: 'inside'
-      },
-      data: [300, 270, 340, 344, 300, 320, 310]
-    },
-    {
-      name: '正面',
-      type: 'bar',
-      stack: '总量',
-      label: {
-        show: true
-      },
-      data: [120, 102, 141, 174, 190, 250, 220]
-    },
-    {
-      name: '负面',
-      type: 'bar',
-      stack: '总量',
-      label: {
-        show: true,
-        position: 'left'
-      },
-      data: [-20, -32, -21, -34, -90, -130, -110]
-    }
-  ]
-}
-```
-
-> **说明**:在实际项目中,可以根据需求修改上述配置项。
-> - 更多配置选项请参考 [ECharts 官方文档](https://echarts.apache.org/zh/option.html)
-> - 查看更多图表样式请访问 [ECharts 官方示例](https://echarts.apache.org/examples/zh/index.html)
-
-### uni-app 使用方式
-
-#### 组合式 API 方式
-
-```html
-<template>
-  <view style="width: 750rpx; height: 750rpx;">
-    <l-echart ref="chartRef" @finished="initChart"></l-echart>
-  </view>
-</template>
-```
-
-```js
-import { ref } from 'vue';
-
-const chartRef = ref(null)
-
-// 仅在小程序环境下引入 ECharts
-// #ifdef MP
-const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
-// #endif
-// #ifndef MP
-const echarts = null // H5 和 App 环境不需要手动引入
-// #endif
-
-// 使用上面定义的图表配置项
-const option = chartOption
-
-// 初始化图表
-const initChart = async () => {
-  if (!chartRef.value) return
-  
-  try {
-    const chart = await chartRef.value.init(echarts)
-    chart.setOption(option)
-  } catch (error) {
-    console.error('图表初始化失败:', error)
-  }
-}
-```
-
-#### 选项式 API 方式
-
-```html
-<template>
-  <view style="width: 750rpx; height: 750rpx;">
-    <l-echart ref="chartRef" @finished="initChart"></l-echart>
-  </view>
-</template>
-```
-
-```js
-// 仅在小程序环境下引入 ECharts
-// #ifdef MP
-const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
-// #endif
-// #ifndef MP
-const echarts = null // H5 和 App 环境不需要手动引入
-// #endif
-
-export default {
-  data() {
-    return {
-      // 使用上面定义的图表配置项
-      option: chartOption,
-      // 图表实例,用于后续操作
-      chartInstance: null,
-    }
-  },
-  methods: {
-    // 初始化图表
-    async initChart() {
-      if (!this.$refs.chartRef) return
-      
-      try {
-        this.chartInstance = await this.$refs.chartRef.init(echarts)
-        this.chartInstance.setOption(this.option)
-      } catch (error) {
-        console.error('图表初始化失败:', error)
-      }
-    },
-    // 更新图表数据
-    updateChart(newOption) {
-      if (this.chartInstance) {
-        this.chartInstance.setOption(newOption)
-      } else if (this.$refs.chartRef) {
-        this.$refs.chartRef.setOption(newOption)
-      }
-    },
-    // 调整图表大小
-    resizeChart() {
-      if (this.$refs.chartRef) {
-        this.$refs.chartRef.resize()
-      }
-    }
-  },
-  // 页面卸载时销毁图表实例
-  beforeUnmount() {
-    if (this.$refs.chartRef) {
-      this.$refs.chartRef.dispose()
-    }
-  }
-}
-```
-
-### uni-app-x 使用方式
-
-```html
-<template>
-  <view style="width: 100%; height: 408px;">
-    <l-echart ref="chartRef" @finished="initChart"></l-echart>
-  </view>
-</template>
-```
-
-```ts
-const chartRef = ref<LEchartComponentPublicInstance | null>(null)
-
-// 仅在小程序环境下引入 ECharts
-// #ifdef MP
-const echarts = require('../../static/echarts.min.js') // 根据实际路径调整
-// #endif
-// #ifndef MP
-const echarts = null
-// #endif
-
-// 使用上面定义的图表配置项
-const option = chartOption
-
-// 初始化图表
-const initChart = async () => {
-  if (chartRef.value === null) return
-  
-  try {
-    const chart = await chartRef.value.init(echarts, null)
-    chart.setOption(option)
-  } catch (error) {
-    console.error('图表初始化失败:', error)
-  }
-}
-```
-
-
-## 高级功能 💪
-
-### 数据更新 🔄
-
-图表支持动态更新数据,有两种常用方式:
-
-#### 方式一:通过组件引用更新
-
-```js
-// Vue 3 Composition API
-chartRef.value?.setOption(newOption)
-
-// Vue 2 Options API
-this.$refs.chart.setOption(newOption)
-```
-
-#### 方式二:通过图表实例更新
-
-```js
-// 在初始化时保存图表实例
-let chartInstance = null
-
-const initChart = async () => {
-  if (!chartRef.value) return
-  chartInstance = await chartRef.value.init(echarts)
-  chartInstance.setOption(option)
-}
-
-// 后续更新数据
-const updateChart = () => {
-  if (chartInstance) {
-    chartInstance.setOption(newData)
-  }
-}
-```
-
-### 图表大小调整 📏
-
-当容器大小改变时,可以调用 `resize` 方法重新调整图表尺寸:
-
-```js
-// 自动适应容器大小
-chartRef.value?.resize()
-
-// 手动指定尺寸
-chartRef.value?.resize({
-  width: 375,  // 像素值
-  height: 375  // 像素值
-})
-```
-
-**💡 提示**:在窗口大小变化或屏幕旋转时,可以监听相应事件并调用 `resize` 方法。
-
-### Vue 2 兼容配置 🔄
-
-如果您的项目使用 Vue 2,需要先安装并引入 Vue Composition API:
-
-```js
-// main.js
-import Vue from 'vue'
-import VueCompositionAPI from '@vue/composition-api'
-Vue.use(VueCompositionAPI)
-```
-
-详细配置请参考:[Vue Composition API 官方文档](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)
-
-### 组件标签说明 🏷️
-
-| 标签名 | 说明 |
-|-------|------|
-| `l-echart` | 正式使用的组件标签 |
-| `lime-echart` | 演示用组件标签 |
-
-### 快速预览 🚀
-
-导入插件后,可以直接使用演示标签查看效果:
-
-```html
-<template>
-  <view style="width: 100%; height: 400px;">
-    <!-- 演示组件 -->
-    <lime-echart />
-  </view>
-</template>
-```
-
-## 常见问题与解决方案 🐛
-
-### 平台特殊问题
-
-#### 微信小程序
-- **画布层级问题**:微信开发工具中 canvas 可能出现层级过高或不跟随页面滚动的情况,真机环境下通常不受影响
-- **Tooltip 阴影**:如需去除文字阴影,可添加配置:`tooltip.shadowBlur = 0`
-
-#### 钉钉小程序
-- **文字测量精度**:由于钉钉小程序没有原生 `measureText`,字体粗细测量可能不够精确
-- **安全扫描警告**:如遇到 `Uint8Clamped` 安全问题,可按以下方式修改 ECharts 文件:
-  ```js
-  // 查找类似代码并修改
-  // 原代码
-  ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
-  // 修改为
-  ["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
-  ```
-
-### 功能限制 ⚠️
-- **Toolbox**:不支持 `saveImage` 功能
-- **Lines 图表**:不支持 `trailLength` 属性,请设置为 `0`
-- **DataZoom**:H5 平台不建议设置 `showDetail` 属性
-- **自定义 Tooltips**:uvue 和 vue 中不支持 DOM 操作相关的自定义 Tooltips
-
-## API 参考 📝
-
-### Props
-
-| 参数 | 说明 | 类型 | 默认值 | 版本 |
-|------|------|------|--------|------|
-| l-style | 自定义样式 | string | - | - |
-| type | 指定 canvas 类型(废除) | string | "2d" | - |
-| is-disable-scroll | 触摸图表时是否禁止页面滚动 | boolean | false | - |
-| beforeDelay | 延迟初始化时间(毫秒) | number | 30 | - |
-| enableHover | PC端是否启用鼠标悬浮效果(废除) | boolean | false | - |
-| landscape | 是否旋转90度,模拟横屏效果 | boolean | false | - |
-| autoHideTooltip | 是否自动隐藏Tooltip | boolean | false | - |
-
-### 组件方法
-
-| 方法名 | 参数 | 返回值 | 说明 |
-|--------|------|--------|------|
-| init | `echarts: Object, config?: Object` | `Promise<ChartInstance>` | 初始化图表实例 |
-| setOption | `option: Object` | `void` | 设置或更新图表配置项 |
-| resize | `size?: {width: number, height: number}` | `void` | 调整图表尺寸 |
-| clear | `-` | `void` | 清空图表内容 |
-| dispose | `-` | `void` | 销毁图表实例 |
-| showLoading | `-` | `void` | 显示加载动画 |
-| hideLoading | `-` | `void` | 隐藏加载动画 |
-| canvasToTempFilePath | `options: Object` | `Promise<Object>` | 生成图表图片,与 uni-app 官方 API 类似,但无需传入 canvasId |
-
-### 事件
-
-| 事件名 | 参数 | 说明 |
-|--------|------|------|
-| finished | 无 | 图表准备就绪时触发,此时可调用 init 方法 |
-
-## 其他平台依赖说明 🌐
-
-### uni-app 非 nvue 端
-
-- **推荐使用 `npm` 安装**
-- 通过 npm 安装可以获得完整的 ES 模块格式支持
-  ```bash
-  npm install echarts --save
-  ```
-- 安装后可直接在代码中通过 `import` 引入
-  ```js
-  import * as echarts from 'echarts'
-  ```
-
-### uni-app-x 非 App 端
-
-- **推荐使用 npm 安装**获取 ES 模块格式
-  ```bash
-  npm install echarts --save
-  ```
-- ES 模块格式具有更好的性能和构建优化支持
-- 通过 `import` 引入使用
-  ```js
-  import * as echarts from 'echarts'
-  ```
-
-> 💡 注意:H5 和 App 原生环境通常不需要手动引入 ECharts,组件会自动处理。只有在需要自定义 ECharts 版本或配置时才需要手动引入。
-
-## 技术支持 🆘
-
-如果您在使用过程中遇到问题,可以通过以下方式获取帮助:
-
-1. 查看 [在线文档](https://limeui.qcoon.cn/#/echart) 获取详细使用说明
-2. 检查 [常见问题](#常见问题与解决方案) 章节查找解决方案
-
-## 贡献与支持 💙
-
-如果您觉得本插件对您有帮助,欢迎给作者点个赞或提供支持:
-
-| 支付宝 | 微信 |
-|--------|------|
-| ![支付宝](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png) | ![微信](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png) |
-
-您的支持是作者持续开发和维护的动力! 🌟

+ 0 - 408
src/uni_modules/lime-echart/readme.old.md

@@ -1,408 +0,0 @@
-# lime-echart
-> 一个基于 JavaScript 的开源可视化图表库   [查看更多](https://limeui.qcoon.cn/#/echart) <br>
-> 基于 echarts 做了兼容处理,更多示例请访问  [uni示例](https://limeui.qcoon.cn/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html)  <br>
-
-
-## 文档链接
-📚 组件详细文档请访问以下站点:
-- [echart组件文档 - 站点1](https://limex.qcoon.cn/components/echart.html)
-- [echart组件文档 - 站点1](https://limeui.qcoon.cn/#/echart)
-- [echart组件文档 - uni示例](https://limeui.qcoon.cn/#/echart-example)
-- [echart组件文档 - 官方示例](https://echarts.apache.org/examples/zh/index.html)
-
-
-
-## 安装
-- 第一步:在市场导入 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899) 
-- 第二步:选择插件依赖:<br>
-  1、可以选插件内的`echarts`包或自定义包,自定义包[下载地址](https://echarts.apache.org/zh/builder.html)<br>
-
-**注意** 
-* 🔔 如果是 `cli` 项目请下载插件到`src`目录下的`uni_modules`,没有这个目录就创建一个
-
-
-## 代码演示
-
-### Vue2
-- 引入依赖,可以是插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html),也可以是`npm`包
-
-```html
-<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef" @finished="init"></l-echart></view>
-```
-
-```js
-// 插件内的 三选一
-import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
-// 自定义的 三选一 下载后放入项目的路径
-import * as echarts from 'xxx/echarts.min'
-// npm包 三选一 需要在控制台 输入命令:npm install echarts
-import * as echarts from 'echarts'
-```
-
-```js
-export default {
-	data() {
-		return {
-			option: {
-				tooltip: {
-					trigger: 'axis',
-					axisPointer: {
-						type: 'shadow' 
-					},
-					confine: true
-				},
-				legend: {
-					data: ['热度', '正面', '负面']
-				},
-				grid: {
-					left: 20,
-					right: 20,
-					bottom: 15,
-					top: 40,
-					containLabel: true
-				},
-				xAxis: [
-					{
-						type: 'value',
-						axisLine: {
-							lineStyle: {
-								color: '#999999'
-							}
-						},
-						axisLabel: {
-							color: '#666666'
-						}
-					}
-				],
-				yAxis: [
-					{
-						type: 'category',
-						axisTick: { show: false },
-						data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
-						axisLine: {
-							lineStyle: {
-								color: '#999999'
-							}
-						},
-						axisLabel: {
-							color: '#666666'
-						}
-					}
-				],
-				series: [
-					{
-						name: '热度',
-						type: 'bar',
-						label: {
-							normal: {
-								show: true,
-								position: 'inside'
-							}
-						},
-						data: [300, 270, 340, 344, 300, 320, 310],
-					},
-					{
-						name: '正面',
-						type: 'bar',
-						stack: '总量',
-						label: {
-							normal: {
-								show: true
-							}
-						},
-						data: [120, 102, 141, 174, 190, 250, 220]
-					},
-					{
-						name: '负面',
-						type: 'bar',
-						stack: '总量',
-						label: {
-							normal: {
-								show: true,
-								position: 'left'
-							}
-						},
-						data: [-20, -32, -21, -34, -90, -130, -110]
-					}
-				]
-			},
-		};
-	},
-	// 组件能被调用必须是组件的节点已经被渲染到页面上
-	methods: {
-		async init() {
-			// chart 图表实例不能存在data里
-			const chart = await this.$refs.chartRef.init(echarts);
-			chart.setOption(this.option)
-		}
-	}
-}
-```
-
-### Vue3
-- 小程序可以使用`require`引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
-- `require`仅支持相对路径,不支持路径别名
-- 非小程序使用 `npm` 包
-
-
-```html
-<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef"></l-echart></view>
-```
-
-```js
-// 小程序 二选一 
-// 插件内的 二选一 
-const echarts = require('../../uni_modules/lime-echart/static/echarts.min');
-// 自定义的 二选一 下载后放入项目的路径
-const echarts = require('xxx/xxx/echarts');
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// 非小程序 
-// 需要在控制台 输入命令:npm install echarts
-import * as echarts from 'echarts'
-```
-
-```js
-
-const chartRef = ref(null)
-const option = {
-	tooltip: {
-		trigger: 'axis',
-		axisPointer: {
-			type: 'shadow' 
-		},
-		confine: true
-	},
-	legend: {
-		data: ['热度', '正面', '负面']
-	},
-	grid: {
-		left: 20,
-		right: 20,
-		bottom: 15,
-		top: 40,
-		containLabel: true
-	},
-	xAxis: [
-		{
-			type: 'value',
-			axisLine: {
-				lineStyle: {
-					color: '#999999'
-				}
-			},
-			axisLabel: {
-				color: '#666666'
-			}
-		}
-	],
-	yAxis: [
-		{
-			type: 'category',
-			axisTick: { show: false },
-			data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
-			axisLine: {
-				lineStyle: {
-					color: '#999999'
-				}
-			},
-			axisLabel: {
-				color: '#666666'
-			}
-		}
-	],
-	series: [
-		{
-			name: '热度',
-			type: 'bar',
-			label: {
-				normal: {
-					show: true,
-					position: 'inside'
-				}
-			},
-			data: [300, 270, 340, 344, 300, 320, 310],
-		},
-		{
-			name: '正面',
-			type: 'bar',
-			stack: '总量',
-			label: {
-				normal: {
-					show: true
-				}
-			},
-			data: [120, 102, 141, 174, 190, 250, 220]
-		},
-		{
-			name: '负面',
-			type: 'bar',
-			stack: '总量',
-			label: {
-				normal: {
-					show: true,
-					position: 'left'
-				}
-			},
-			data: [-20, -32, -21, -34, -90, -130, -110]
-		}
-	]
-};
-
-
-onMounted( ()=>{
-	// 组件能被调用必须是组件的节点已经被渲染到页面上
-	setTimeout(async()=>{
-		if(!chartRef.value) return
-		const myChart = await chartRef.value.init(echarts)
-		myChart.setOption(option)
-	},300)
-})
-
-```
-
-
-### Uvue
-- Uvue和Nvue不需要引入`echarts`,因为它们的实现方式是`webview`
-- uniapp x需要HBX 4.13以上
-
-```html
-<view style="width: 100%; height: 408px;">
-	<l-echart ref="chartRef" @finished="init"></l-echart>
-</view>
-```
-
-```js
-// @ts-nocheck
-// #ifdef H5
-import * as echarts from 'echarts/dist/echarts.esm.js'
-// #endif
-const chartRef = ref<LEchartComponentPublicInstance|null>(null);
-const init = async () => {
-	if(chartRef.value== null) return
-	// #ifdef APP
-	const chart = await chartRef.value!.init(null)
-	// #endif
-	// #ifdef H5
-	const chart = await chartRef.value!.init(echarts, null)
-	// #endif
-	chart.setOption(option)
-}
-```
-
-
-## 数据更新
-- 1、使用 `ref` 可获取`setOption`设置更新
-- 2、也可以拿到图表实例`chart`设置`myChart.setOption(data)`
-
-```js
-// ref
-this.$refs.chart.setOption(data)
-
-// 图表实例
-myChart.setOption(data)
-```
-
-## 图表大小
-- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
-
-```js
-// 默认获取容器尺寸
-this.$refs.chart.resize()
-// 指定尺寸
-this.$refs.chart.resize({width: 375, height: 375})
-```
-
-## 自定义Tooltips
-- uvue\nvue 不支持
-由于除H5之外都不存在dom,但又有tooltips个性化的需求,代码就不贴了,看示例吧
-```
-代码位于/uni_modules/lime-echart/component/lime-echart
-```
-
-
-## 插件标签
-- 默认 l-echart 为 component
-- 默认 lime-echart 为 demo
-```html
- // 在任意地方使用可查看domo, 代码位于/uni_modules/lime-echart/component/lime-echart
-<lime-echart></lime-echart>
-```
-
-
-## 常见问题
-- 钉钉小程序 由于没有`measureText`,模拟的`measureText`又无法得到当前字体的`fontWeight`,故可能存在估计不精细的问题
-- 微信小程序 `2d` 只支持 真机调试2.0
-- 微信开发工具会出现 `canvas` 不跟随页面的情况,真机不影响
-- 微信开发工具会出现 `canvas` 层级过高的问题,真机一般不受影响,可以先测只有两个元素的页面看是否会有层级问题。
-- toolbox 不支持 `saveImage`
-- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
-- dataZoom H5不要设置 `showDetail` 
-- 如果微信小程序的`tooltip`文字有阴影,可能是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
-- 如果钉钉小程序上传时报安全问题`Uint8Clamped`,可以向钉钉反馈是安全代码扫描把Uint8Clamped数组错误识别了,也可以在 echarts 文件修改`Uint8Clamped`
-```js
-// 找到这段代码把代码中`Uint8Clamped`改成`Uint8_Clamped`,再把下划线去掉,不过直接去掉`Uint8Clamped`也是可行的
-// ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
-// 改成如下
-["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
-```
-
-### vue3
-如果您是使用 **vite + vue3** 非微信小程序可能会遇到`echarts`文件缺少`wx`判断导致无法使用或缺少`tooltip`<br>
-
-方式一:可以在`echarts.min.js`文件开头增加以下内容,参考插件内的echart.min.js的做法
-
-```js
-// 某些echarts版本下 uniapp app 需要global,不然会报__ECHARTS__DEFAULT__RENDERER__
-let global = null
-let wx = uni
-```
-
-方式二:在`vite.config.js`的`define`设置环境
-
-```js
-//  或者在`vite.config.js`的`define`设置环境
-import { defineConfig } from 'vite';
-import uni from '@dcloudio/vite-plugin-uni';
-
-const define = {}
-if(!["mp-weixin", "h5", "web"].includes(process.env.UNI_PLATFORM)) {
-	define['global'] =  null
-	define['wx'] =  'uni'
-}
-export default defineConfig({
-	plugins: [uni()],
-	define
-});
-```
-
-
-## Props
-
-| 参数             | 说明                                                            | 类型             | 默认值        | 版本 	|
-| ---------------  | --------                                                        | -------         | ------------ | ----- 	|
-| custom-style     | 自定义样式                                                      |   `string`       | -            | -     	|
-| type             | 指定 canvas 类型                                				 |    `string`      | `2d`         |   	    |
-| is-disable-scroll | 触摸图表时是否禁止页面滚动                                       |    `boolean`     | `false`     |   	    |
-| beforeDelay       |  延迟初始化 (毫秒)                       						|    `number`     | `30`     |   	    |
-| enableHover       |  PC端使用鼠标悬浮                       						|    `boolean`     | `false`     |   	    |
-| landscape       |  是否旋转90deg,模拟横屏效果                       						|    `boolean`     | `false`     |   	    |
-
-## 事件
-
-| 参数                    | 说明                                                                                                             |
-| ---------------        | ---------------                                                                                                  |
-| init(echarts, chart => {})  | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例                                           |  
-| setChart(chart => {})        | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例                  |  
-| setOption(data)        | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option`  |  
-| clear()                | 清空当前实例,会移除实例中所有的组件和图表。  |  
-| dispose()              | 销毁实例  |  
-| showLoading()          | 显示加载  |  
-| hideLoading()          | 隐藏加载  |  
-| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt)  | 用于生成图片,与官方使用方法一致,但不需要传`canvasId`  |  
-
-
-## 打赏
-如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。  
-![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
-![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/app/ecStat.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 34
src/uni_modules/lime-echart/static/app/echarts.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/app/uni.webview.1.5.5.js


+ 0 - 184
src/uni_modules/lime-echart/static/app/uvue.html

@@ -1,184 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh">
-	<head>
-		<meta charset="UTF-8">
-		<meta name="viewport"
-			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
-		<meta http-equiv="X-UA-Compatible" content="ie=edge">
-		<title></title>
-		<style type="text/css">
-			html,
-			body {
-				overflow: hidden;
-				/* 隐藏滚动条 */
-				overscroll-behavior: none;
-				/* 禁止橡皮筋效果 */
-			}
-			html,
-			body,
-			.canvas {
-				padding: 0;
-				margin: 0;
-				overflow-y: hidden;
-				background-color: transparent;
-				width: 100%;
-				height: 100%;
-			}
-		</style>
-	</head>
-	<body>
-		<div class="canvas" id="limeChart"></div>
-		<script type="text/javascript" src="./uni.webview.1.5.5.js"></script>
-		<script type="text/javascript" src="./echarts.min.js"></script>
-		<script type="text/javascript" src="./ecStat.min.js"></script>
-		<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
-		<script>
-			let chart = null;
-			let cache = [];
-			console.log = function() {
-				emit('log', {
-					log: arguments,
-				})
-			}
-
-			function emit(event, data) {
-				postMessage({
-					event,
-					data
-				})
-				cache = []
-			}
-
-			function postMessage(data) {
-				uni.webView.postMessage({
-					data
-				})
-				// window.__uniapp_x_.postMessage(JSON.stringify(data))
-			};
-
-			function stringify(key, value) {
-				if (typeof value === 'object' && value !== null) {
-					if (cache.indexOf(value) !== -1) {
-						return;
-					}
-					cache.push(value);
-				}
-				return value;
-			}
-
-			function parse(name, callback, options) {
-				const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
-				if (optionNameReg.test(callback)) {
-					const optionNames = callback.match(optionNameReg)
-					if (optionNames[1]) {
-						const _this = optionNames[1].split('.')[0]
-						window[_this] = {}
-						window[_this][optionNames[2]] = options
-						return optionNames[2]
-					} else {
-						return null
-					}
-				}
-				return null
-			}
-
-			function init(callback, options, opts, theme) {
-				if (!chart) {
-					chart = echarts.init(document.getElementById('limeChart'), theme, opts)
-
-					if (options) {
-						chart.setOption(options)
-					}
-				}
-			}
-
-			function on(data) {
-				if (chart && data.length > 0) {
-					const [type, query] = data
-					const key = `${type}${JSON.stringify(query||'')}`
-					if (query) {
-						chart.on(type, query, function(options) {
-							var obj = {};
-							Object.keys(options).forEach(function(key) {
-								if (key != 'event') {
-									obj[key] = options[key];
-								}
-							});
-							emit(key, {
-								event: key,
-								options: obj,
-							});
-						});
-					} else {
-						chart.on(type, function(options) {
-							var obj = {};
-							Object.keys(options).forEach(function(key) {
-								if (key != 'event') {
-									obj[key] = options[key];
-								}
-							});
-							emit(key, {
-								event: key,
-								options: obj,
-							});
-						});
-					}
-				}
-
-			}
-
-			function setChart(callback, options) {
-				if (!callback) return
-				if (chart && callback && options) {
-					var r = null
-					const name = parse('r', callback, options)
-					if (name) this[name] = options
-					eval(`r = ${callback};`)
-					if (r) {
-						r(chart)
-					}
-				}
-			}
-
-			function setOption(data) {
-				if (chart) chart.setOption(data[0], data[1])
-			}
-
-			function showLoading(data) {
-				if (chart) chart.showLoading(data[0], data[1])
-			}
-
-			function hideLoading() {
-				if (chart) chart.hideLoading()
-			}
-
-			function clear() {
-				if (chart) chart.clear()
-
-			}
-
-			function dispose() {
-				if (chart) chart.dispose()
-			}
-
-			function resize(size) {
-				if (chart) chart.resize(size)
-			}
-
-			function canvasToTempFilePath(opt) {
-				if (chart) {
-					delete opt.success
-					const src = chart.getDataURL(opt)
-					postMessage({
-						// event: 'file',
-						file: src
-					})
-				}
-			}
-
-			document.addEventListener('touchmove', () => {
-
-			})
-		</script>
-	</body>
-</html>

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/ecStat.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 49
src/uni_modules/lime-echart/static/echarts.min.js


+ 0 - 129
src/uni_modules/lime-echart/static/index.html

@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh">
-	<head>
-		<meta charset="UTF-8">
-		<meta name="viewport"
-			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
-		<meta http-equiv="X-UA-Compatible" content="ie=edge">
-		<title></title>
-		<style type="text/css">
-			html,
-			body,
-			.canvas {
-				padding: 0;
-				margin: 0;
-				overflow-y: hidden;
-				background-color: transparent;
-				width: 100%;
-				height: 100%;
-			}
-		</style>
-	</head>
-	<body>
-		<div class="canvas" id="limeChart"></div>
-		<script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
-		<script type="text/javascript" src="./echarts.min.js"></script>
-		<script type="text/javascript" src="./ecStat.min.js"></script>
-		<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
-		<script>
-			let chart = null;
-			let cache = [];
-			console.log = function(...agrs) {
-				postMessage(agrs)
-			}
-			function emit(event, data) {
-				let dataStr = JSON.stringify(data, stringify)
-				postMessage({
-					event,
-					data: dataStr
-				})
-				cache = []
-			}
-			function postMessage(data) {
-				uni.postMessage({
-					data
-				});
-			}
-			function stringify(key, value) {
-				if (typeof value === 'object' && value !== null) {
-					if (cache.indexOf(value) !== -1) {
-						return;
-					}
-					cache.push(value);
-				}
-				return value;
-			}
-			function parse(name, callback, options) {
-				const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
-				if (optionNameReg.test(callback)) {
-					const optionNames = callback.match(optionNameReg)
-					if(optionNames[1]) {
-						const _this = optionNames[1].split('.')[0]
-						window[_this] = {}
-						window[_this][optionNames[2]] = options
-						return optionNames[2]
-					} else {
-						return null
-					}
-				}
-				return null
-			}
-			function init(callback, options, opts = {}, theme = null) {
-				if(!chart) {
-					chart = echarts.init(document.getElementById('limeChart'), theme, opts)
-					if(options) {
-						chart.setOption(options)
-					}
-					// const name = parse('a', callback, options)
-					// console.log('options::', callback)
-					// if(name) this[name] = options
-					// eval(`a = ${callback};`)
-					// if(a) {a(chart)}
-				}
-			}
-			
-			function setChart(callback, options) {
-				if(!callback) return
-				if(chart && callback && options) {
-					var r = null
-					const name = parse('r', callback, options)
-					if(name) this[name] = options
-					eval(`r = ${callback};`)
-					if(r) {r(chart)}
-				}
-			}
-			function setOption(data) {
-				if (chart) chart.setOption(data[0], data[1])
-			}
-			function showLoading(data) {
-				if (chart) chart.showLoading(data[0], data[1])
-			}
-			
-			function hideLoading() {
-				if (chart) chart.hideLoading()
-			}
-			
-			function clear() {
-				if (chart) chart.clear()
-			
-			}
-			
-			function dispose() {
-				if (chart) chart.dispose()
-			}
-			function resize(size) {
-				if (chart) chart.resize(size)
-			}
-			
-			function canvasToTempFilePath(opt = {}) {
-				if (chart) {
-				  const src = chart.getDataURL(opt)
-				  postMessage({
-					  file: true,
-					  data: src
-				  })
-				}
-			}
-		</script>
-	</body>
-</html>

+ 0 - 177
src/uni_modules/lime-echart/static/nvue.html

@@ -1,177 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh">
-	<head>
-		<meta charset="UTF-8">
-		<meta name="viewport"
-			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
-		<meta http-equiv="X-UA-Compatible" content="ie=edge">
-		<title></title>
-		<style type="text/css">
-			html,
-			body,
-			.canvas {
-				padding: 0;
-				margin: 0;
-				overflow-y: hidden;
-				background-color: transparent;
-				width: 100%;
-				height: 100%;
-			}
-		</style>
-	</head>
-	<body>
-		<div class="canvas" id="limeChart"></div>
-		<script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
-		<script type="text/javascript" src="./echarts.min.js"></script>
-		<script type="text/javascript" src="./ecStat.min.js"></script>
-		<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
-		<script>
-			let chart = null;
-			let cache = [];
-			console.log = function(...agrs) {
-				postMessage(agrs)
-			}
-
-			function emit(event, data) {
-				let dataStr = JSON.stringify(data, stringify)
-				postMessage({
-					event,
-					data: dataStr
-				})
-				cache = []
-			}
-
-			function postMessage(data) {
-				uni.postMessage({
-					data
-				});
-			}
-
-			function stringify(key, value) {
-				if (typeof value === 'object' && value !== null) {
-					if (cache.indexOf(value) !== -1) {
-						return;
-					}
-					cache.push(value);
-				}
-				return value;
-			}
-
-			function parse(name, callback, options) {
-				const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
-				if (optionNameReg.test(callback)) {
-					const optionNames = callback.match(optionNameReg)
-					if (optionNames[1]) {
-						const _this = optionNames[1].split('.')[0]
-						window[_this] = {}
-						window[_this][optionNames[2]] = options
-						return optionNames[2]
-					} else {
-						return null
-					}
-				}
-				return null
-			}
-
-			function init(callback, options, opts = {}, theme = null) {
-				if (!chart) {
-					chart = echarts.init(document.getElementById('limeChart'), theme, opts)
-					if (options) {
-						chart.setOption(options)
-					}
-					// const name = parse('a', callback, options)
-					// console.log('options::', callback)
-					// if(name) this[name] = options
-					// eval(`a = ${callback};`)
-					// if(a) {a(chart)}
-				}
-			}
-
-			function setChart(callback, options) {
-				if (!callback) return
-				if (chart && callback && options) {
-					var r = null
-					const name = parse('r', callback, options)
-					if (name) this[name] = options
-					eval(`r = ${callback};`)
-					if (r) {
-						r(chart)
-					}
-				}
-			}
-
-			function setOption(data) {
-				if (chart) chart.setOption(data[0], data[1])
-			}
-
-			function showLoading(data) {
-				if (chart) chart.showLoading(data[0], data[1])
-			}
-
-			function hideLoading() {
-				if (chart) chart.hideLoading()
-			}
-
-			function clear() {
-				if (chart) chart.clear()
-
-			}
-
-			function dispose() {
-				if (chart) chart.dispose()
-			}
-
-			function resize(size) {
-				if (chart) chart.resize(size)
-			}
-
-			function canvasToTempFilePath(opt = {}) {
-				if (chart) {
-					const src = chart.getDataURL(opt)
-					postMessage({
-						file: true,
-						data: src
-					})
-				}
-			}
-
-			function on(data) {
-				if (chart && data.length > 0) {
-					const [type, query] = data
-					const useQuery = query && typeof query != 'function'
-					const key = `${type}${useQuery ? JSON.stringify(query): '' }`
-					if (query) {
-						chart.on(type, query, (options) => {
-							const obj = {}
-							Object.keys(options).forEach(key => {
-								if (key != 'event') {
-									obj[key] = options[key]
-								}
-							})
-							emit(`@${key}`, {
-								event: key,
-								options: obj
-							})
-						})
-					} else {
-						chart.on(type, (options) => {
-							
-							const obj = {}
-							Object.keys(options).forEach(key => {
-								if (key != 'event') {
-									obj[key] = options[key]
-								}
-
-							})
-							emit(`@${key}`, {
-								event: key,
-								options: obj
-							})
-						})
-					}
-				}
-
-			}
-		</script>
-	</body>
-</html>

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/uni.webview.1.5.3.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/uni_modules/lime-echart/static/uni.webview.1.5.5.js


+ 0 - 173
src/uni_modules/lime-echart/static/uvue.html

@@ -1,173 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh">
-	<head>
-		<meta charset="UTF-8">
-		<meta name="viewport"
-			content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
-		<meta http-equiv="X-UA-Compatible" content="ie=edge">
-		<title></title>
-		<style type="text/css">
-			html,
-			body,
-			.canvas {
-				padding: 0;
-				margin: 0;
-				overflow-y: hidden;
-				background-color: transparent;
-				width: 100%;
-				height: 100%;
-			}
-		</style>
-	</head>
-	<body>
-		<div class="canvas" id="limeChart"></div>
-		<script type="text/javascript" src="./uni.webview.1.5.5.js"></script>
-		<script type="text/javascript" src="./echarts.min.js"></script>
-		<script type="text/javascript" src="./ecStat.min.js"></script>
-		<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
-		<script>
-			let chart = null;
-			let cache = [];
-			console.log = function(...agrs) {
-				emit('log', {
-					log: agrs,
-				})
-			}
-
-			function emit(event, data) {
-				postMessage({
-					// event,
-					data
-				})
-				cache = []
-			}
-
-			function postMessage(data) {
-				window.__uniapp_x_.postMessage(JSON.stringify(data))
-			};
-
-			function stringify(key, value) {
-				if (typeof value === 'object' && value !== null) {
-					if (cache.indexOf(value) !== -1) {
-						return;
-					}
-					cache.push(value);
-				}
-				return value;
-			}
-
-			function parse(name, callback, options) {
-				const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
-				if (optionNameReg.test(callback)) {
-					const optionNames = callback.match(optionNameReg)
-					if (optionNames[1]) {
-						const _this = optionNames[1].split('.')[0]
-						window[_this] = {}
-						window[_this][optionNames[2]] = options
-						return optionNames[2]
-					} else {
-						return null
-					}
-				}
-				return null
-			}
-
-			function init(callback, options, opts = {}, theme = null) {
-				if (!chart) {
-					chart = echarts.init(document.getElementById('limeChart'), theme, opts)
-
-					if (options) {
-						chart.setOption(options)
-					}
-				}
-			}
-
-			function on(data) {
-				if (chart && data.length > 0) {
-					const [type, query] = data
-					const key = `${type}${JSON.stringify(query??'')}`
-					if (query) {
-						chart.on(type, query, (options) => {
-							const obj = {}
-							Object.keys(options).forEach(key => {
-								if (key != 'event') {
-									obj[key] = options[key]
-								}
-
-							})
-							emit(key, {
-								event: key,
-								options: obj
-							})
-						})
-					} else {
-						chart.on(type, (options) => {
-							const obj = {}
-							Object.keys(options).forEach(key => {
-								if (key != 'event') {
-									obj[key] = options[key]
-								}
-
-							})
-							emit(key, {
-								event: key,
-								options: obj
-							})
-						})
-					}
-				}
-
-			}
-
-			function setChart(callback, options) {
-				if (!callback) return
-				if (chart && callback && options) {
-					var r = null
-					const name = parse('r', callback, options)
-					if (name) this[name] = options
-					eval(`r = ${callback};`)
-					if (r) {
-						r(chart)
-					}
-				}
-			}
-
-			function setOption(data) {
-				if (chart) chart.setOption(data[0], data[1])
-			}
-
-			function showLoading(data) {
-				if (chart) chart.showLoading(data[0], data[1])
-			}
-
-			function hideLoading() {
-				if (chart) chart.hideLoading()
-			}
-
-			function clear() {
-				if (chart) chart.clear()
-
-			}
-
-			function dispose() {
-				if (chart) chart.dispose()
-			}
-
-			function resize(size) {
-				if (chart) chart.resize(size)
-			}
-
-			function canvasToTempFilePath(opt = {}) {
-				if (chart) {
-					
-					delete opt.success
-					const src = chart.getDataURL(opt)
-					postMessage({
-						// event: 'file',
-						file: file
-					})
-				}
-			}
-		</script>
-	</body>
-</html>

Разница между файлами не показана из-за своего большого размера
+ 0 - 34
src/uni_modules/lime-echart/static/web/echarts.esm.min.js


Некоторые файлы не были показаны из-за большого количества измененных файлов