hyc 11 mesi fa
parent
commit
08b2f4b3be

+ 16 - 2
css/utils.scss

@@ -102,9 +102,11 @@
 .flex-x-end {
   justify-content: flex-end;
 }
+
 .flex-y-start {
   align-content: flex-start;
 }
+
 .flex-y-center {
   align-items: center;
 }
@@ -136,6 +138,12 @@
   align-items: center;
 }
 
+.flex-start-end {
+  display: flex !important;
+  justify-content: flex-start;
+  align-items: flex-end;
+}
+
 .flex-center-center {
   display: flex !important;
   justify-content: center;
@@ -177,9 +185,11 @@
   justify-content: space-around;
   align-items: center;
 }
-.flex-grow{
-  flex-grow:1,
+
+.flex-grow {
+  flex-grow: 1,
 }
+
 .flex-two {
   box-sizing: border-box;
   flex: 0 0 50%;
@@ -487,9 +497,11 @@
 .m-0-auto {
   margin: 0 auto;
 }
+
 .m-40 {
   margin: 40rpx;
 }
+
 .m-t-4 {
   margin-top: 4rpx;
 }
@@ -769,9 +781,11 @@
 .p-l-40 {
   padding-left: 40rpx;
 }
+
 .p-l-50 {
   padding-left: 50rpx;
 }
+
 .p-r-10 {
   padding-right: 10rpx;
 }

+ 3 - 1
manifest.json

@@ -44,7 +44,9 @@
                     "<uses-feature android:name=\"android.hardware.camera\"/>",
                     "<uses-feature android:name=\"android.hardware.usb.host\"/>",
                     "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
-                    "<uses-permission android:name=\"android.permission.USB_PERMISSION\"/>"
+                    "<uses-permission android:name=\"android.permission.USB_PERMISSION\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>"
                 ]
             },
             /* ios打包配置 */

+ 3 - 0
package.json

@@ -26,5 +26,8 @@
   "devDependencies": {
     "pinia": "^2.1.7",
     "vue": "^3.4.21"
+  },
+  "dependencies": {
+    "dayjs": "^1.11.10"
   }
 }

+ 6 - 6
pages.json

@@ -9,18 +9,18 @@
   "pages": [
     //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
 
+    //    {
+    //      "path": "pages/index/init",
+    //      "style": {
+    //        "navigationStyle": "custom"
+    //      }
+    //    },
     {
       "path": "pages/index/index",
       "style": {
         "navigationStyle": "custom"
       }
     },
-    {
-      "path": "pages/index/init",
-      "style": {
-        "navigationStyle": "custom"
-      }
-    },
     {
       "path": "pages/auth/index",
       "style": {

+ 46 - 89
pages/index/index.vue

@@ -2,60 +2,31 @@
   <view class="window-box">
     <ly-back :showBack="false"/>
     <view class="search w100 h100 flex-center-center main flex-dir-column">
-      <view class="" @click="getListHandle">测验机器</view>
-      <br>
-      <br>
-      <br>
-      <view class="flex-between-center w50">
-        <view class="w50 flex-center-center">
-          <view :class="[machine.scan?'btn-primary':'btn-info']" class="btn">
-            扫码器
-            <uv-icon v-if="machine.scan" color="#FFF" name="checkbox-mark" size="28"/>
-          </view>
-        </view>
-        <view class="w50 flex-center-center">
-          <view :class="[machine.bmi?'btn-primary':'btn-info']" class="btn">
-            体重秤
-            <uv-icon v-if="machine.bmi" color="#FFF" name="checkbox-mark" size="28"/>
-          </view>
-        </view>
-      </view>
-      <br>
-      <br>
-      <view class="flex-start-center">
-        卡号:
-        <view class="col-checked">{{ pD.value1 || '--' }}</view>
-      </view>
-      <br>
-      <view class="flex-start-center">
-        身高:
-        <view class="col-checked">{{ pD.value3 || '0' }}</view>
-        cm
-      </view>
-      <view class="flex-start-center">
-        体重:
-        <view class="col-checked">{{ pD.value2 || '0' }}</view>
-        kg
-      </view>
-
-
-      <!--      <view class="" :class="{'col-green':}"></view>-->
-
       <!--      <view class="w60 h60 bg2 flex-center-center flex-wrap flex-dir-column">-->
       <!--        <view>请将卡片放入感应区</view>-->
-      <!--        <view >-->
-      <!--          <uv-image :src="pD.imgUrl+ '/index-card.png'" width="500px" height="306px"></uv-image>-->
+      <!--        <view>-->
+      <!--          <uv-image :src="pD.imgUrl+ '/index-card.png'" height="306px" width="500px"></uv-image>-->
+      <!--        </view>-->
+      <!--      </view>-->
+      <!--      <view class="flex-start-center" @click="clearList">-->
+      <!--        卡号:-->
+      <!--        &lt;!&ndash;        <view class="col-checked">{{ pD.value1 || '&#45;&#45;' }}</view>&ndash;&gt;-->
+      <!--        <view class="btn btn-danger" @click="clearList">清空</view>-->
+      <!--      </view>-->
+      <!--      <view class="flex-dir-column f-u-21" style="max-height: 50vh;overflow-y: auto">-->
+      <!--        <view v-for="(item,index) in list" :key="index" class="">-->
+      <!--          {{ item.time }}:{{ item.str }}-->
       <!--        </view>-->
       <!--      </view>-->
       <!--      <view class="btn btn-primary" @click="search">扫码</view>-->
       <!--      <view class="btn btn-primary" @click="next">下一页</view>-->
-      <!--      <view class="btn btn-primary" @click="toSelect">手动选择</view>-->
+      <view class="btn btn-primary" @click="toSelect">手动选择</view>
     </view>
   </view>
 </template>
 
 <script setup>
-import {getCurrentInstance, inject, onActivated, onBeforeUnmount, onMounted, reactive} from "vue";
+import {getCurrentInstance, inject, onActivated, onBeforeUnmount, onMounted, reactive, ref} from "vue";
 import {onShow, onHide} from "@dcloudio/uni-app";
 import {navTo, showToast} from "@/utils/app";
 import {cradToStudentInfo} from "@/api/student";
@@ -64,6 +35,7 @@ import {getAllMethods, logs, sleep} from "@/utils/util";
 import * as ASCIIUtils from "@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-ASCIIUtils";
 import * as HexUtils from "@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-HexUtils";
 import {orderToData} from "@/utils/ble/hex";
+import dayjs from "dayjs";
 
 const $machine = inject('$machine')
 
@@ -73,29 +45,31 @@ const pD = reactive({
   selectMax: 1,
   imgUrl: '/static',
   value1: '',
-  value2: '',
-})
-const machine = reactive({
-  scan: false,
-  bmi: false,
 })
 const queryForm = reactive({
   student_id: 0,
 })
-const search = async () => {
-  const {code, msg, data} = await cradToStudentInfo({
-    mac: 'BBBBBBBBBBBB'
-  })
-  if (code === 1) {
-    queryForm.student_id = data.student.id
-    storage.setKey(`student-${data.student.id}`)
-    navTo('pages/task/info', {
-      id: queryForm.student_id,
-    })
-  } else {
-    showToast(msg)
-  }
-  // navTo('pages/task/info')
+const list = ref([])
+const clearList = async () => {
+  list.value = []
+}
+const addList = async (data) => {
+  list.value.push(data)
+}
+const search = async (mac) => {
+  // const {code, msg, data} = await cradToStudentInfo({
+  //   mac
+  // })
+  // if (code === 1) {
+  //   queryForm.student_id = data.student.id
+  //   storage.setKey(`student-${data.student.id}`)
+  //   navTo('pages/task/info', {
+  //     id: queryForm.student_id,
+  //   })
+  // } else {
+  //   showToast(msg)
+  // }
+  navTo('pages/task/info')
 }
 
 const next = () => {
@@ -108,42 +82,27 @@ const toSelect = () => {
   navTo('pages/classes/select')
 }
 
-const getListHandle = () => {
-  // console.log('getListHandle')
-  $machine.getUsbList(true)
-}
-
-const scanWatch = (res) => {
-  console.log('scanWatch123', res)
-  pD.value1 = res.value
-}
-
-const bmiWatch = (res) => {
-  console.log('bmiWatch123', res)
-  pD.value2 = res.kg
-  pD.value3 = res.cm
-}
-
-const notifyMachineUsb = ({id, up}) => {
-  machine[id] = up
+const scanWatch = (value) => {
+  // console.log('scanWatch123', value)
+  // pD.value1 = value
+  // search(value)
+  addList({
+    time: dayjs().format('YYYY-MM-DD HH:mm:ss:SSS'),
+    str: value
+  })
 }
 
 const setWatch = (open = false) => {
   if (open) {
     $machine.scan().setWatch(scanWatch)
-    $machine.bmi().setWatch(bmiWatch)
   } else {
     $machine.scan().setWatch(null)
-    $machine.bmi().setWatch(null)
   }
 }
 
 
 // 挂载完成之后
 onMounted(async (r) => {
-  // console.log('index onMounted')
-  uni.$on('machineUsb', notifyMachineUsb)
-  // getListHandle()
 })
 
 onShow(async () => {
@@ -156,9 +115,7 @@ onHide(async () => {
 // 页面卸载前
 onBeforeUnmount(() => {
   setWatch()
-  uni.$off('machineUsb', notifyMachineUsb)
 })
-defineExpose({})
 
 // 激活页面时
 onActivated(async () => {
@@ -167,7 +124,7 @@ onActivated(async () => {
 
 <style lang="scss" scoped>
 .main {
-  background-image: url('static/image/index-bg.png');
+  //background-image: url('static/image/index-bg.png');
   width: 100%;
   height: 100%;
   background-position: center center;
@@ -176,7 +133,7 @@ onActivated(async () => {
 }
 
 .bg2 {
-  background-image: url('static/image/index-bg2.png');
+  //background-image: url('static/image/index-bg2.png');
   width: 80%;
   height: 80%;
   background-position: center center;

+ 66 - 42
pages/index/init.vue

@@ -1,29 +1,29 @@
 <template>
   <view class="window-box dis-flex flex-y-center">
     <view class="steps w40 form-box">
-<!--      <uv-steps :current="current" :customStyle="[{-->
-<!--        width:'70%',-->
-<!--        height:'90vh',-->
-<!--      }]" activeIcon="checkmark" direction="column" inactiveIcon="arrow-right">-->
-<!--        <uv-steps-item :iconSize="60" title="网络检测"></uv-steps-item>-->
-<!--        <uv-steps-item :iconSize="60" title="登录"></uv-steps-item>-->
-<!--        <uv-steps-item :iconSize="60" title="运行"></uv-steps-item>-->
-<!--      </uv-steps>-->
+      <!--      <uv-steps :current="current" :customStyle="[{-->
+      <!--        width:'70%',-->
+      <!--        height:'90vh',-->
+      <!--      }]" activeIcon="checkmark" direction="column" inactiveIcon="arrow-right">-->
+      <!--        <uv-steps-item :iconSize="60" title="网络检测"></uv-steps-item>-->
+      <!--        <uv-steps-item :iconSize="60" title="登录"></uv-steps-item>-->
+      <!--        <uv-steps-item :iconSize="60" title="运行"></uv-steps-item>-->
+      <!--      </uv-steps>-->
       <view class="h90 dis-flex flex-wrap flex-y-center step">
         <view v-for="(item,index) in pd.steps" class="w100">
-          <view class="dis-flex flex-y-center flex-x-evenly p-r" :class="[current < index? 'opacity' :'']">
-            <view class="circle dis-flex flex-center-center f-u-41 f-w-b p-r" :class="['circle-'+index]">
-              <text>{{index+1}}</text>
+          <view :class="[current < index? 'opacity' :'']" class="dis-flex flex-y-center flex-x-evenly p-r">
+            <view :class="['circle-'+index]" class="circle dis-flex flex-center-center f-u-41 f-w-b p-r">
+              <text>{{ index + 1 }}</text>
               <view v-if="item.next" class="p-a next">
-                <uv-image :src="pd.imgUrl+item.next" width="22px" height="97px" mode="widthFix"></uv-image>
+                <uv-image :src="pd.imgUrl+item.next" height="97px" mode="widthFix" width="22px"></uv-image>
               </view>
             </view>
-            <view class="dian" :class="['dian-'+index]"></view>
+            <view :class="['dian-'+index]" class="dian"></view>
             <view class="content dis-flex flex-center-center col-f f-u-51 f-w-b">
-              <view class="w80 p-b-20 b-b p-l-20">{{item.title}}</view>
+              <view class="w80 p-b-20 b-b p-l-20">{{ item.title }}</view>
             </view>
             <view v-if="item.img" class="p-a bg">
-              <uv-image :src="pd.imgUrl+item.img" width="86px" height="97px"></uv-image>
+              <uv-image :src="pd.imgUrl+item.img" height="97px" width="86px"></uv-image>
             </view>
           </view>
         </view>
@@ -36,11 +36,11 @@
           <view v-if="pd.network.search" class="f-42 col-c t-a-c">
             网络检测中。。。
           </view>
-<!--          <view @click="network">重新检测网络</view>-->
+          <!--          <view @click="network">重新检测网络</view>-->
           <template v-else>
             <view class="dis-flex flex-wrap flex-dir-column flex-center-center ">
               <view>
-                <uv-image :src="pd.imgUrl+ '/login-wifi.png'" width="150px" height="150px"></uv-image>
+                <uv-image :src="pd.imgUrl+ '/login-wifi.png'" height="150px" width="150px"></uv-image>
               </view>
               <view class="f-u-35 col-9 t-a-c p-t-10">
                 当前网络:{{ pd.network.type === 'unknown' ? '未知网络但可用' : pd.network.type }}
@@ -48,7 +48,9 @@
             </view>
           </template>
           <view class="p-a btns">
-            <view class="btn btn-primary w100" @click="next">{{pd.network.type === 'none' ? '重新检测网络':'下一步'}}</view>
+            <view class="btn btn-primary w100" @click="next">
+              {{ pd.network.type === 'none' ? '重新检测网络' : '下一步' }}
+            </view>
           </view>
         </view>
 
@@ -58,7 +60,7 @@
               自动登录中。。。
             </view>
             <view v-else class="w50">
-              <uv-form ref="form" :model="pd.loginForm" labelPosition="left" label-width="80px">
+              <uv-form ref="form" :model="pd.loginForm" label-width="80px" labelPosition="left">
                 <uv-form-item borderBottom label="设备码" leftIcon="order" prop="pd.loginForm.mac">
                   <uv-input v-model="pd.loginForm.mac" border="none"/>
                 </uv-form-item>
@@ -90,15 +92,20 @@
 import {onActivated, onMounted, reactive, ref} from "vue";
 import {getNetworkType} from "@/utils/uniFunction";
 import {useUserStore} from "@/store/useUserStore";
-import {sleep} from "@/utils/util";
+import {logs, sleep} from "@/utils/util";
 import {machineTypeList} from "@/utils/machine/config";
 import {useConfigStore} from "@/store/useConfigStore";
 import {getBeforePage, redirectTo} from "@/utils/app";
+import {FileStorage} from "@/utils/fileStorage";
+import {calcStrHash} from "@/utils/machine/function";
 
 
 const userStore = useUserStore()
 const configStore = useConfigStore()
 
+
+const fileStorage = new FileStorage()
+
 const current = ref(0)
 
 const pd = reactive({
@@ -111,12 +118,16 @@ const pd = reactive({
     mac: '',
     pwd: '',
   },
-  imgUrl:'/static/image',
-  steps:[{title:'网络检测',img:'/login-image1.png',next:'/login-next1.png'},{title:'登陆',next:'/login-next1.png'},{title:'进入系统'}],
+  imgUrl: '/static/image',
+  steps: [{title: '网络检测', img: '/login-image1.png', next: '/login-next1.png'}, {
+    title: '登陆',
+    next: '/login-next1.png'
+  }, {title: '进入系统'}],
 })
 const machineList = ref(JSON.parse(JSON.stringify(machineTypeList)))
 
 const currentAdd = async () => {
+  console.log('currentAdd')
   if (current.value < 2) current.value++
   if (current.value === 1 && pd.login) {
     await sleep(1000)
@@ -139,11 +150,11 @@ const network = async () => {
   }
 }
 
-const next = async ()=>{
-  if(current.value === 0){
-    if(pd.network.type === 'none'){
+const next = async () => {
+  if (current.value === 0) {
+    if (pd.network.type === 'none') {
       await network()
-    }else {
+    } else {
       await currentAdd()
     }
   }
@@ -163,10 +174,17 @@ const machineChange = (item) => {
   currentAdd()
 }
 
+const getConfig = async () => {
+  console.log('plus.io.convertLocalFileSystemURL( url )', plus.io.convertLocalFileSystemURL('/'))
+  let mac = await configStore.getMac()
+  console.log('mac', mac)
+}
+
 // 挂载完成之后
 onMounted(() => {
-  let beforePage = getBeforePage(0)
-  network()
+  // let beforePage = getBeforePage(0)
+  // network()
+  getConfig()
 })
 
 // 激活页面时
@@ -193,49 +211,52 @@ onActivated(() => {
 .form-box {
   padding: 2.5vw;
 }
-.step{
 
-  .circle{
+.step {
+
+  .circle {
     width: 90rpx;
     height: 90rpx;
     border-radius: 50%;
 
-    &-0{
+    &-0 {
       background-color: #FFFFFF;
       border: 8rpx solid #027EEC;
       color: #027EEC;
     }
 
-    &-1{
+    &-1 {
       background-color: #FFFFFF;
       border: 8rpx solid #17ACC3;
       color: #17ACC3;
     }
 
-    &-2{
+    &-2 {
       background-color: #FFFFFF;
       border: 8rpx solid #F7B03C;
       color: #F7B03C;
     }
   }
 
-  .dian{
+  .dian {
     width: 28rpx;
     height: 28rpx;
     border-radius: 50%;
-    &-0{
+
+    &-0 {
       background-color: #027EEC;
     }
 
-    &-1{
+    &-1 {
       background-color: #17ACC3;
     }
 
-    &-2{
+    &-2 {
       background-color: #F7B03C;
     }
   }
-  .content{
+
+  .content {
     background-image: url('static/image/login-bg1.png');
     width: 500rpx;
     height: 200rpx;
@@ -243,20 +264,23 @@ onActivated(() => {
     background-size: 100%;
     background-repeat: no-repeat;
   }
-  .bg{
+
+  .bg {
     right: 7%;
     top: -35%;
   }
-  .next{
+
+  .next {
     top: 100%;
     transform: translateY(60%)
   }
 }
 
-.opacity{
+.opacity {
   opacity: 0.5;
 }
-.btns{
+
+.btns {
   bottom: 10px;
   left: 50%;
   transform: translateX(-50%);

+ 208 - 96
pages/task/info.vue

@@ -9,44 +9,52 @@
           <student-info :student="student"/>
         </view>
         <view class="dis-flex flex-wrap flex-y-center m-40" style="height: 80px;text-align: center">
-          <view class="flex-three p-10">姓名:{{pageData.studentInfo.name}}</view>
-          <view class="flex-three p-10">性别:{{pageData.studentInfo.gender}}</view>
-          <view class="flex-three p-10">班级:{{pageData.studentInfo.class}}</view>
-          <view class="flex-three p-10">模式:{{pageData.studentInfo.model}}</view>
-          <view class="flex-three p-10">学校:{{pageData.studentInfo.school}}</view>
+          <view class="flex-three p-10">姓名:{{ pageData.studentInfo.name }}</view>
+          <view class="flex-three p-10">性别:{{ pageData.studentInfo.gender }}</view>
+          <view class="flex-three p-10">班级:{{ pageData.studentInfo.class }}</view>
+          <view class="flex-three p-10">模式:{{ pageData.studentInfo.model }}</view>
+          <view class="flex-three p-10">学校:{{ pageData.studentInfo.school }}</view>
+          <view class="flex-three p-10">卡号:{{ pageData.studentInfo.mac || '手动选择' }}</view>
         </view>
       </view>
 
       <view class="dis-flex w80">
-        <view v-if="pageData.status == 1" class="m-t-50 p-r-20">
-          <view v-for="(item,index) in pageData.card" :key="index" class="cardbg b-r-15" @click="showDetail(item)" :class="['cardbg-'+index]">
-            <view class="f-u-35 dis-flex flex-y-center checkCard p-l-20 p-r-20 p-t-20 p-b-5">
-              <view class="circle" :class="['circle-'+index]"></view>
-              <view class="flex-grow t-a-c">
-                <view class="f-w-b">{{item.name}}</view>
-                <view class="f-u-32 font-color p-10">
-                  <view v-if="pageData.status == 1" class="t-a-c f-w-5 f-u-29">
-                    <view v-if="item.value1">{{item.title1}}:{{item.value1}}</view>
-                    <view class="m-t-10" v-if="item.value2">{{item.title2}}:{{item.value2}}</view>
-                  </view>
-                </view>
-              </view>
-            </view>
-          </view>
-        </view>
+        <!--        <view v-if="pageData.status == 1" class="m-t-50 p-r-20">-->
+        <!--          <view v-for="(item,index) in pageData.card" :key="index" :class="['cardbg-'+index]" class="cardbg b-r-15"-->
+        <!--                @click="showDetail(item)">-->
+        <!--            <view class="f-u-35 dis-flex flex-y-center checkCard p-l-20 p-r-20 p-t-20 p-b-5">-->
+        <!--              <view :class="['circle-'+index]" class="circle"></view>-->
+        <!--              <view class="flex-grow t-a-c">-->
+        <!--                <view class="f-w-b">{{ item.name }}</view>-->
+        <!--                <view class="f-u-32 font-color p-10">-->
+        <!--                  <view v-if="pageData.status == 1" class="t-a-c f-w-5 f-u-29">-->
+        <!--                    <view v-if="item.value1">{{ item.title1 }}:{{ item.value1 }}</view>-->
+        <!--                    <view v-if="item.value2" class="m-t-10">{{ item.title2 }}:{{ item.value2 }}</view>-->
+        <!--                  </view>-->
+        <!--                </view>-->
+        <!--              </view>-->
+        <!--            </view>-->
+        <!--          </view>-->
+        <!--        </view>-->
 
-        <view class="checkMessage p-40 m-t-50 b-r-15 flex-center-center flex-dir-column flex-grow" style="min-height: 500rpx">
-          <view class="f-u-35 col-f p-20">{{pageData.status == 1?'检测结果展示':'待检测项目'}}</view>
+        <view class="checkMessage p-40 m-t-50 b-r-15 flex-center-center flex-dir-column flex-grow"
+              style="min-height: 500rpx">
+          <view class="f-u-35 col-f p-20">{{ pageData.status == 1 ? '检测结果展示' : '待检测项目' }}</view>
           <view class="w-bg w100 b-r-15 m-t-10 flex-y-start flex-wrap flex-grow ">
-            <view v-for="(item,index) in pageData.card" :key="index" class="flex-two t-a-c p-20 f-u-32 f-w-b">
+            <view v-for="(item,index) in card" :key="index" class="flex-two t-a-c p-20 f-u-32 f-w-b">
               <view class="flex-center-center">
-                <view class="circle1" :class="['circleBg-'+index]"></view>
-                <view class="p-l-10">{{ item.name }} </view>
+                <view :class="['circleBg-'+index]" class="circle1"></view>
+                <view class="p-l-10">{{ item.name }}</view>
               </view>
-              <view v-if="pageData.status == 0" class="t-a-c col-red f-w-5 p-l-50"> {{ item.status }} </view>
-              <view v-if="pageData.status == 1" class="t-a-c f-w-5 p-l-50 p-t-20 font-color dis-flex flex-x-center">
-                <view v-if="item.value1">{{item.title1}}:{{item.value1}}</view>
-                <view class="p-l-20" v-if="item.value2">{{item.title2}}:{{item.value2}}</view>
+              <view v-for="(it,ind) in item.val" :key="ind"
+                    class="t-a-c f-w-5 p-l-50 p-t-20 font-color flex-start-end">
+                <view class="m-r-10">{{ it.title }}:</view>
+                <template v-if="it.value">
+                  {{ it.value || '待检测' }}{{}}
+                </template>
+                <view v-else class="col-red f-u-21">
+                  待检测
+                </view>
               </view>
             </view>
 
@@ -56,6 +64,11 @@
 
 
       <view class="dis-flex flex-x-center w100 m-t-50">
+        <view v-if="pageData.status == -1" class="w10">
+          <template v-if="configStore.mType === 7">
+            <view v-if="!machineFun.machine.bmi" class="col-red">体重秤设备未连接</view>
+          </template>
+        </view>
         <view v-if="pageData.status == 0" class="w10" @click="toTask(10)">
           <view class="btn btn-primary w100">进入测试</view>
         </view>
@@ -66,57 +79,63 @@
           <view class="btn btn-primary w100">完成</view>
         </view>
       </view>
-
     </view>
-<!--    <view class="window w40 flex-center-center flex-dir-column">-->
-<!--      <student-info :student="student"/>-->
-<!--    </view>-->
-<!--    <view class="w60 h100 dis-flex flex-x-center flex-dir-column">-->
-<!--      <template v-if="configStore.mType === 7">-->
-<!--        <view class="info-item">-->
-<!--          <view class="info-item-label">身高</view>-->
-<!--          <view class="">-->
-<!--            <view class="col-checked f-64">{{ queryForm.value1 }}</view>-->
-<!--          </view>-->
-<!--        </view>-->
-<!--        <view class="info-item">-->
-<!--          <view class="info-item-label">体重</view>-->
-<!--          <view class="">-->
-<!--            <view class="col-checked f-64">{{ queryForm.value2 }}</view>-->
-<!--          </view>-->
-<!--        </view>-->
-<!--      </template>-->
-<!--      <view v-if="configStore.mType === 8" class="info-item">-->
-<!--        <view class="info-item-label">肺活量</view>-->
-<!--        <view class="">-->
-<!--          <view class="btn btn-primary">进入肺活量</view>-->
-<!--        </view>-->
-<!--      </view>-->
-<!--      <view v-if="configStore.mType === 9" class="info-item">-->
-<!--        <view class="info-item-label">视力</view>-->
-<!--        <view class="">-->
-<!--          <view class="btn btn-primary">进入视力</view>-->
-<!--        </view>-->
-<!--      </view>-->
-<!--    </view>-->
+    <!--    <view class="window w40 flex-center-center flex-dir-column">-->
+    <!--      <student-info :student="student"/>-->
+    <!--    </view>-->
+    <!--    <view class="w60 h100 dis-flex flex-x-center flex-dir-column">-->
+    <!--      <template v-if="configStore.mType === 7">-->
+    <!--        <view class="info-item">-->
+    <!--          <view class="info-item-label">身高</view>-->
+    <!--          <view class="">-->
+    <!--            <view class="col-checked f-64">{{ queryForm.value1 }}</view>-->
+    <!--          </view>-->
+    <!--        </view>-->
+    <!--        <view class="info-item">-->
+    <!--          <view class="info-item-label">体重</view>-->
+    <!--          <view class="">-->
+    <!--            <view class="col-checked f-64">{{ queryForm.value2 }}</view>-->
+    <!--          </view>-->
+    <!--        </view>-->
+    <!--      </template>-->
+    <!--      <view v-if="configStore.mType === 8" class="info-item">-->
+    <!--        <view class="info-item-label">肺活量</view>-->
+    <!--        <view class="">-->
+    <!--          <view class="btn btn-primary">进入肺活量</view>-->
+    <!--        </view>-->
+    <!--      </view>-->
+    <!--      <view v-if="configStore.mType === 9" class="info-item">-->
+    <!--        <view class="info-item-label">视力</view>-->
+    <!--        <view class="">-->
+    <!--          <view class="btn btn-primary">进入视力</view>-->
+    <!--        </view>-->
+    <!--      </view>-->
+    <!--    </view>-->
     <ly-modal ref="modelRef"></ly-modal>
   </view>
 </template>
 
 <script setup>
-import {onActivated, onMounted, reactive, ref} from "vue";
-import {formatZero} from "@/utils/util";
+import {inject, onActivated, onBeforeUnmount, onMounted, reactive, ref} from "vue";
+import {array_column, formatZero, logs, sleep} from "@/utils/util";
 import {useConfigStore} from "@/store/useConfigStore";
 import {redirectTo} from "@/utils/app";
 import debounce from "@/utils/debounce";
-import studentInfo from "./studentInfo"
 import storage from "@/utils/storage";
+import {onShow, onHide} from "@dcloudio/uni-app";
+import {machineFun} from "@/utils/machine/machineFun"
 
 const configStore = useConfigStore()
 const countDown = ref(0)
 const debounces = new debounce()
 const modelRef = ref()
+const $machine = inject('$machine')
 
+
+const pD = reactive({
+  value2: '',
+  value3: '',
+})
 let student = reactive({
   jname: '未识别',
   gender: 1,
@@ -126,21 +145,71 @@ const queryForm = reactive({
   value1: 0,
   value2: 0,
 })
+const defaultCard = {
+  7: {
+    name: 'BMI',
+    img: '/card-bg1.png',
+    val: [
+      {
+        id: 1,
+        title: '身高',
+        value: '',
+        unit: 'Cm',
+      },
+      {
+        id: 2,
+        title: '体重',
+        value: '',
+        unit: 'Kg',
+      },
+    ],
+  },
+  8: {
+    name: '肺活量',
+    img: '/card-bg2.png',
+    val: [
+      {
+        id: 1,
+        title: '身高',
+        value: '',
+        unit: 'ml',
+      },
+    ]
+  },
+  9: {
+    name: '视力',
+    img: '/card-bg3.png',
+    val: [
+      {
+        id: 1,
+        title: '左眼',
+        value: '',
+        unit: '',
+      },
+      {
+        id: 2,
+        title: '右眼',
+        value: '',
+        unit: '',
+      },
+    ]
+  },
+}
 const pageData = reactive({
   status: 0,
-  studentInfo:{
-    name:'测试',
-    gender:'男',
-    class:'xx年级xx班',
-    model:'机器录入',
-    school:'xxxx学校',
+  studentInfo: {
+    name: '测试',
+    gender: '男',
+    class: 'xx年级xx班',
+    model: '机器录入',
+    school: 'xxxx学校',
+    mac: '',
   },
-  card:[
-    {name:'BMI',img:'/card-bg1.png',status:'待检测',value1:'175cm',value2:'54kg',title1:'身高',title2:'体重'},
-    {name:'肺活量',img:'/card-bg2 .png',status:'待检测',value1:'3500ml',title1:'肺活量'},
-    {name:'视力',img:'/card-bg3.png',status:'待检测',value1:'5.0',value2:'5.0',title1:'左眼',title2:'右眼'}
-  ]
+  card: []
 })
+
+const card = reactive([])
+
 const search = () => {
   queryForm.student_id = 2260
 }
@@ -150,7 +219,7 @@ const backClick = () => {
     title: '温馨提示',
     content: '确认要退出吗?',
     showCancelButton: true,
-    confirm:()=>{
+    confirm: () => {
       logout()
     }
   })
@@ -172,21 +241,57 @@ const countDownHandle = () => {
     },
     endCallback: () => {
       // 清空缓存学生信息
-      logout()
+      // logout()
     },
   })
 }
-const showDetail = (item)=>{
+const showDetail = (item) => {
   console.log(item)
 }
 const toTask = () => {
-  pageData.status  = 1
+  pageData.status = 1
+}
+
+
+const bmiWatch = ({kg, cm}) => {
+  // console.log('bmiWatch123', res)
+  countDownHandle()
+  pD.value2 = kg
+  pD.value3 = cm
+}
+
+const setWatch = (open = false) => {
+  if (open) {
+    $machine.bmi().setWatch(bmiWatch)
+  } else {
+    $machine.bmi().setWatch(null)
+  }
 }
 
+
+onShow(async () => {
+  setWatch(true)
+})
+
+onHide(async () => {
+  setWatch()
+})
+// 页面卸载前
+onBeforeUnmount(() => {
+  setWatch()
+  machineFun.setUsbNotify(false)
+})
+
 // 挂载完成之后
-onMounted((r) => {
+onMounted(async (r) => {
+  await sleep(1000)
   // student = storage.getKey(`student-${r.id}`)
+  card.push(defaultCard[configStore.mType])
   countDownHandle()
+  machineFun.getOnlineUsb($machine, (list = []) => {
+    if (list.indexOf('bmi') === -1) pageData.status = -1
+  })
+  machineFun.setUsbNotify()
 })
 
 // 激活页面时
@@ -244,66 +349,73 @@ onActivated(() => {
 .checkMessage {
   background: linear-gradient(180deg, #498CFC 0%, #E0EDF8 100%);
 }
-.cardbg{
+
+.cardbg {
   width: 500rpx;
   height: 230rpx;
   background-size: 100%;
   border-radius: 15rpx;
   margin-bottom: 20rpx;
 
-  &-0{
+  &-0 {
     background: url('static/image/card-bg1.png') no-repeat center center;
   }
-  &-1{
+
+  &-1 {
     background: url('static/image/card-bg2.png') no-repeat center center;
   }
-  &-2{
+
+  &-2 {
     background: url('static/image/card-bg3.png') no-repeat center center;
   }
 }
 
-.checkCard{
+.checkCard {
 
   height: 80%;
   background-color: #FFFFFF;
   border-radius: 15rpx 15rpx 25rpx 25rpx;
 
-  .circle{
+  .circle {
     width: 130rpx;
     height: 130rpx;
     border-radius: 50%;
-    &-0{
+
+    &-0 {
       background-color: #027EEC;
     }
 
-    &-1{
+    &-1 {
       background-color: #F7B03C;
     }
 
-    &-2{
+    &-2 {
       background-color: #17ACC3;
     }
   }
 }
-.circle1{
+
+.circle1 {
   width: 35rpx;
   height: 35rpx;
   border-radius: 50%;
 }
-.circleBg{
-  &-0{
+
+.circleBg {
+  &-0 {
     background-color: #027EEC;
   }
 
-  &-1{
+  &-1 {
     background-color: #F7B03C;
   }
 
-  &-2{
+  &-2 {
     background-color: #17ACC3;
   }
 }
-.font-color{
+
+.font-color {
   color: #153269;
 }
 </style>

+ 36 - 5
plugins/ly-back.vue

@@ -3,24 +3,39 @@
     <view v-if="props.showBack" :class="{'action':select === 0}" class="p-f back-box" @click="clickHandle">
       <ly-icon :color="color" :size="60" name="icon-fanhui"/>
     </view>
-    <view class="p-f bottom-right"></view>
+    <view class="p-f bottom-right">
+      <view class="flex-between-center w50">
+        <view class="">
+          <ly-icon :color="machineStore.scan?'#00ce48':'red'" :size="50" name="icon-shuakaqi"/>
+        </view>
+        <view v-if="configStore.mType === 7" class="m-l-20">
+          <ly-icon :color="machineStore.bmi?'#00CE48':'red'" :size="45" name="icon-dianzicheng"/>
+        </view>
+      </view>
+    </view>
     <view class="p-f mac-info" @click="toSetting">
-      mac:{{ userStore.mac || '未登录' }}
+      MAC:{{ userStore.mac || '未登录' }}
     </view>
   </view>
 </template>
 
 <script setup>
-import {reactive} from "vue";
+import {inject, onBeforeUnmount, onMounted, reactive} from "vue";
 import {navigateBack, navTo, showToast} from "@/utils/app";
 import {useUserStore} from "@/store/useUserStore";
 import debounce from "@/utils/debounce";
+import {machineFun} from "@/utils/machine/machineFun";
+import {useConfigStore} from "@/store/useConfigStore";
+import {useMachineStore} from "@/store/useMachineStore";
+
+const $machine = inject('$machine')
 
 const debounces = new debounce()
 
 const userStore = useUserStore()
+const configStore = useConfigStore()
+const machineStore = useMachineStore()
 
-const pd = reactive({})
 const emits = defineEmits(['backClick'])
 const props = defineProps({
   showBack: {
@@ -66,16 +81,32 @@ const toSetting = () => {
     },
   })
 }
+
+
+// 挂载完成之后
+onMounted(async (r) => {
+  machineFun.setUsbNotify(true)
+  machineFun.getOnlineUsb($machine)
+})
+// 页面卸载前
+onBeforeUnmount(() => {
+  machineFun.setUsbNotify(false)
+})
 </script>
 
 <style lang="scss" scoped>
 .mac-info {
   bottom: 10rpx;
   right: 20rpx;
-  font-size: 35rpx;
+  font-size: 25rpx;
   color: #cccccc;
 }
 
+.bottom-right {
+  bottom: 10rpx;
+  left: 20rpx;
+}
+
 .back-box {
   //width: 30vw;
   height: 200px;

+ 9 - 1
static/iconfont/iconfont.css

@@ -1,6 +1,6 @@
 @font-face {
   font-family: "icon"; /* Project id 4463540 */
-  src: url('./iconfont.ttf?t=1710230317828') format('truetype');
+  src: url('/static/iconfont/iconfont.ttf') format('truetype');
 }
 
 .icon {
@@ -11,6 +11,14 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-dianzicheng:before {
+  content: "\e603";
+}
+
+.icon-shuakaqi:before {
+  content: "\e970";
+}
+
 .icon-ffanhui-:before {
   content: "\e6b1";
 }

BIN
static/iconfont/iconfont.ttf


+ 76 - 3
store/useConfigStore.js

@@ -1,10 +1,20 @@
 import {defineStore} from "pinia";
 import storage from "@/utils/storage";
 import platform from "@/utils/platform";
+import {getSystemDeviceInfo} from "@/utils/getSystemDeviceInfo";
+import {FileStorage} from "@/utils/fileStorage";
+import {confirmModal, showToast} from "@/utils/app";
+import dayjs from "dayjs";
+import {logs} from "@/utils/util";
+import {calcStrHash} from "@/utils/machine/function";
+
+const configUrl = '/storage/emulated/0/.TXZNMac.txt'
+const fileStorage = new FileStorage()
 
 export const useConfigStore = defineStore('config', {
   state: () => ({
-    mType: 0, // 7 BMI;8 肺活量;9 视力;
+    mac: null,
+    mType: 7, // 7 BMI(默认);8 肺活量;9 视力;
     mName: '',
     platform,
   }),
@@ -23,10 +33,73 @@ export const useConfigStore = defineStore('config', {
     },
     getMachineType() {
       let info = storage.getKey('machineType')
+      console.log('getMachineType', info)
       if (info) {
-        this.mType = info.mType
-        this.mName = info.mName
+        this.mType = info.type
+        this.mName = info.name
+      }
+    },
+
+    async getMac() {
+      return new Promise(async (resolve, reject) => {
+        let config = await this.getConfig()
+        console.log('config', config)
+        let mac = config.mac ?? await this.createMac()
+        console.log('config2', mac)
+        if (mac) {
+          resolve(mac)
+        } else {
+          reject(false)
+        }
+      })
+    },
+
+    async createMac() {
+      let {imei} = await getSystemDeviceInfo()
+      try {
+        if (!imei) {
+          // #ifdef APP-PLUS
+          await confirmModal('无法获取设备imei,请联系管理员!', {
+            showCancel: false,
+          })
+          plus.runtime.quit()
+          // #endif
+          // #ifdef H5
+          showToast('无法获取设备imei,请联系管理员!')
+          return false
+          // #endif
+        }
+      } catch (e) {
+        console.error('createMac 获取设备码失败')
+        return false
       }
+      let timestamp = dayjs().valueOf()
+      let data = await this.getConfig()
+      let a = calcStrHash(imei, 5)
+      let b = calcStrHash(timestamp, 4)
+      data.mac = `BMI${a}${b}`
+      data.timestamp = timestamp
+      data.imei = imei
+      await this.getConfig(data)
+      this.mac = data.mac
+      return data.mac
     },
+
+
+    async getConfig(data = false) {
+      if (data) {
+        fileStorage.storage(configUrl, (data || {}))
+        return data
+      }
+      data = {}
+      try {
+        let info = await fileStorage.read(configUrl)
+        if (info) data = info
+      } catch (e) {
+        fileStorage.storage(configUrl, {})
+      }
+      return data
+    },
+
   }
 })

+ 28 - 0
store/useMachineStore.js

@@ -0,0 +1,28 @@
+import {defineStore} from "pinia";
+import storage from "@/utils/storage";
+import platform from "@/utils/platform";
+import {getSystemDeviceInfo} from "@/utils/getSystemDeviceInfo";
+import {FileStorage} from "@/utils/fileStorage";
+import {confirmModal, showToast} from "@/utils/app";
+import dayjs from "dayjs";
+import {logs} from "@/utils/util";
+import {calcStrHash} from "@/utils/machine/function";
+
+const configUrl = '/storage/emulated/0/.TXZNMac.txt'
+const fileStorage = new FileStorage()
+
+export const useMachineStore = defineStore('machine', {
+  state: () => ({
+    scan: false,
+    bmi: false,
+  }),
+  getters: {},
+  actions: {
+
+    setStatus(key, up) {
+      console.log('setStatus', key, up)
+      this[key] = up
+    },
+
+  }
+})

+ 10 - 6
store/useUserStore.js

@@ -1,30 +1,34 @@
 import {defineStore} from "pinia";
 import storage from "@/utils/storage";
+import {useConfigStore} from "@/store/useConfigStore";
+
 
 export const useUserStore = defineStore({
   id: 'user',
   state: () => ({
-    mac: null,
     token: null,
   }),
   getters: {},
   actions: {
     _init() {
       this.checkLogin()
-      this.getMachineInfo()
     },
     checkLogin() {
       let token = storage.getKey('LOGIN_TEACHER_TOKEN')
       if (token) {
         this.token = token
-        this.getMachineInfo()
       }
     },
+    login() {
+      const configStore = useConfigStore()
+      let mac = configStore.getMac()
+      console.log('login mac', mac)
+    },
     logout() {
       this.token = null
     },
-    getMachineInfo() {
-      this.mac = '123'
-    },
+    // getMachineInfo() {
+    //   this.mac = '123'
+    // },
   }
 })

File diff suppressed because it is too large
+ 0 - 0
utils/dayjs.js


+ 76 - 0
utils/fileStorage.js

@@ -0,0 +1,76 @@
+export class FileStorage {
+  constructor() {
+  }
+
+  storage(addr, data) {
+    plus.io.requestFileSystem(
+      plus.io.PRIVATE_DOC, // 程序私有文档目录常量
+      fs => {
+        // 创建或打开文件, fs.root是根目录操作对象,直接fs表示当前操作对象
+        fs.root.getFile(
+          addr, {
+            create: true // 文件不存在则创建
+          },
+          fileEntry => {
+            // 文件在手机中的路径
+            fileEntry.createWriter(writer => {
+              // 写入文件成功完成的回调函数
+              writer.onwrite = e => {
+                console.log('写入成功');
+              };
+              // 向文件中写入数据
+              writer.write(
+                JSON.stringify(data)
+              );
+            });
+          },
+          e => {
+            console.log('getFile failed: ' + JSON.stringify(e));
+          }
+        );
+      },
+      e => {
+        console.log(e.message);
+      }
+    );
+  }
+
+  read(addr) {
+    let that = this;
+    return new Promise((resolve, reject) => {
+      plus.io.requestFileSystem(
+        plus.io.PRIVATE_DOC,
+        fs => {
+          fs.root.getFile(
+            addr, {
+              create: false
+            },
+            fileEntry => {
+              fileEntry.file(function (file) {
+                // console.log('文件大小:' + file.size + '-- 文件名:' + file.name);
+                //创建读取文件对象
+                let fileReader = new plus.io.FileReader();
+                //以文本格式读取文件数据内容
+                fileReader.readAsText(file, 'utf-8');
+                //文件读取操作完成时的回调函数
+                fileReader.onloadend = function (evt) {
+                  let result = evt.target.result ? JSON.parse(evt.target.result) : {}
+                  resolve(result)
+                };
+              });
+            },
+            e => {
+              reject(e)
+              console.log(e)
+            }
+          );
+        },
+        e => {
+          reject(e);
+          console.log(e.message);
+        }
+      );
+    })
+
+  }
+}

+ 52 - 0
utils/getSystemDeviceInfo.js

@@ -0,0 +1,52 @@
+/**
+ * 获取系统设备信息
+ */
+
+
+import {requestAndroidPermission} from "@/utils/permission";
+
+export function getSystemDeviceInfo() {
+  return new Promise((resolve, reject) => {
+    // 返回结果
+    let resolveResult = (deviceId, imei) => {
+      resolve({
+        deviceId,
+        imei
+      })
+    };
+
+    let sysInfo = uni.getSystemInfoSync();
+
+    // #ifdef APP-PLUS
+    if (sysInfo.osName.toLowerCase() == 'android' && sysInfo.osVersion >= 10) {
+      plus.device.getOAID({
+        success: ({oaid}) => {
+          resolveResult(oaid);
+        },
+        fail: (e) => {
+          resolveResult(sysInfo.deviceId);
+        }
+      });
+    } else {
+      requestAndroidPermission('android.permission.READ_PHONE_STATE').then(res => {
+        plus.device.getInfo({
+          success: (res) => {
+            let {uuid, imei} = res
+            let [oaid] = uuid?.split(",") || []
+            resolveResult(oaid || sysInfo.deviceId, imei)
+          },
+          fail: (error) => {
+            resolveResult(sysInfo.deviceId);
+          },
+        });
+      }).catch((err) => {
+        resolveResult(sysInfo.deviceId);
+      });
+    }
+    // #endif
+
+    // #ifndef APP-PLUS
+    resolveResult(sysInfo.deviceId);
+    // #endif
+  });
+}

+ 12 - 0
utils/machine/function.js

@@ -0,0 +1,12 @@
+export const calcStrHash = (str, long = -1) => {
+  str = str.replace(/[, _]/g, '')
+  const hash = str.split('').reduce((acc, char) => {
+    if (char !== ',') {
+      return acc + char.charCodeAt(0);
+    }
+    return acc;
+  }, 0)
+  str = hash.toString(16).toUpperCase()
+  if (long != -1) str = str.padStart(long, '0')
+  return str
+}

+ 14 - 4
utils/machine/index.js

@@ -85,7 +85,7 @@ export class Machine {
       // #ifdef APP-PLUS
       this.permission.list = {}
       usbSerial.findSerialPortDevice((resp) => {
-        // logs('getUsbList2', resp)
+        logs('getUsbList2', resp)
         if (resp.devices) {
           that.usbList = resp.devices;
           that.usbNum = resp.devices.length
@@ -110,9 +110,9 @@ export class Machine {
             }
           }
         }
-        logs('this.usbList', this.usbList)
-        logs('this.permission.list', this.permission.list)
-        logs('this.permission.okList', this.permission.okList)
+        // logs('this.usbList', this.usbList)
+        // logs('this.permission.list', this.permission.list)
+        // logs('this.permission.okList', this.permission.okList)
         if (open) {
           this.getPermission()
         } else {
@@ -124,6 +124,16 @@ export class Machine {
 
   }
 
+
+  getOnlineUsb(type = 1) {
+    let list = this.permission.okList
+    if (type === 1) {
+      list = array_column(list, 'id')
+    }
+    return list
+  }
+
+
   _init() {
     // logs('machine _init')
     // #ifdef APP-PLUS

+ 40 - 0
utils/machine/machineFun.js

@@ -0,0 +1,40 @@
+import {inject, reactive} from "vue";
+import {useMachineStore} from "@/store/useMachineStore";
+
+
+export const machineFun = {
+
+  machine: reactive({
+    scan: false,
+    bmi: false,
+  }),
+
+  notifyMachineUsb({id, up}) {
+    console.log('notifyMachineUsb', id, up)
+    const machineStore = useMachineStore()
+    this.machine[id] = up
+    machineStore.setStatus(id, up)
+  },
+
+  getOnlineUsb(machine, callback) {
+    let list = machine.getOnlineUsb()
+    if (list) {
+      list.forEach(it => {
+        this.notifyMachineUsb({
+          id: it,
+          up: true,
+        })
+      })
+    }
+    if (callback) callback()
+  },
+
+  setUsbNotify(open = true) {
+    if (open) {
+      uni.$on('machineUsb', this.notifyMachineUsb)
+    } else {
+      uni.$off('machineUsb', this.notifyMachineUsb)
+    }
+  },
+
+}

+ 8 - 8
utils/machine/scanMachine.js

@@ -20,14 +20,14 @@ export class ScanMachine extends Base {
 
   read(resp) {
     logs('read', this.id, resp)
-    if (!resp.data) return;
-    let data = resp.data
-    if (data.startsWith('02') && data.endsWith('03')) {
-      resp.value = data.substring(2, data.length - 2);
-    }
-    resp.value = ASCIIUtils.decodeUtf8(data)
-    // logs('scan usbSerial.read', resp)
-    if (this.notifyFun) this.notifyFun(resp)
+    let resArr = this.packetManager(resp.data)
+    resArr.forEach(it => {
+      let data = it.slice(2, -2);
+      it = ASCIIUtils.decodeUtf8(data)
+      logs('scan usbSerial.read', it)
+      if (this.notifyFun) this.notifyFun(it)
+    })
+
   }
 
 

+ 274 - 0
utils/permission.js

@@ -0,0 +1,274 @@
+/**
+ * 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
+ */
+let isIos;
+// #ifdef APP-PLUS
+isIos = (plus.os.name == "iOS")
+// #endif
+
+// 判断推送权限是否开启
+function judgeIosPermissionPush() {
+  let result = false;
+  const UIApplication = plus.ios.import("UIApplication");
+  const app = UIApplication.sharedApplication();
+  let enabledTypes = 0;
+  if (app.currentUserNotificationSettings) {
+    const settings = app.currentUserNotificationSettings();
+    enabledTypes = settings.plusGetAttribute("types");
+    console.log("enabledTypes1:" + enabledTypes);
+    if (enabledTypes == 0) {
+      console.log("推送权限没有开启");
+    } else {
+      result = true;
+      console.log("已经开启推送功能!")
+    }
+    plus.ios.deleteObject(settings);
+  } else {
+    enabledTypes = app.enabledRemoteNotificationTypes();
+    if (enabledTypes == 0) {
+      console.log("推送权限没有开启!");
+    } else {
+      result = true;
+      console.log("已经开启推送功能!")
+    }
+    console.log("enabledTypes2:" + enabledTypes);
+  }
+  plus.ios.deleteObject(app);
+  plus.ios.deleteObject(UIApplication);
+  return result;
+}
+
+// 判断定位权限是否开启
+function judgeIosPermissionLocation() {
+  let result = false;
+  const cllocationManger = plus.ios.import("CLLocationManager");
+  const status = cllocationManger.authorizationStatus();
+  result = (status != 2)
+  console.log("定位权限开启:" + result);
+  // 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
+  /* var enable = cllocationManger.locationServicesEnabled();
+  var status = cllocationManger.authorizationStatus();
+  console.log("enable:" + enable);
+  console.log("status:" + status);
+  if (enable && status != 2) {
+      result = true;
+      console.log("手机定位服务已开启且已授予定位权限");
+  } else {
+      console.log("手机系统的定位没有打开或未给予定位权限");
+  } */
+  plus.ios.deleteObject(cllocationManger);
+  return result;
+}
+
+// 判断麦克风权限是否开启
+function judgeIosPermissionRecord() {
+  let result = false;
+  const avaudiosession = plus.ios.import("AVAudioSession");
+  const avaudio = avaudiosession.sharedInstance();
+  const permissionStatus = avaudio.recordPermission();
+  console.log("permissionStatus:" + permissionStatus);
+  if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
+    console.log("麦克风权限没有开启");
+  } else {
+    result = true;
+    console.log("麦克风权限已经开启");
+  }
+  plus.ios.deleteObject(avaudiosession);
+  return result;
+}
+
+// 判断相机权限是否开启
+function judgeIosPermissionCamera() {
+  let result = false;
+  const AVCaptureDevice = plus.ios.import("AVCaptureDevice");
+  const authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
+  console.log("authStatus:" + authStatus);
+  if (authStatus == 3) {
+    result = true;
+    console.log("相机权限已经开启");
+  } else {
+    console.log("相机权限没有开启");
+  }
+  plus.ios.deleteObject(AVCaptureDevice);
+  return result;
+}
+
+// 判断相册权限是否开启
+function judgeIosPermissionPhotoLibrary() {
+  let result = false;
+  const PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
+  const authStatus = PHPhotoLibrary.authorizationStatus();
+  console.log("authStatus:" + authStatus);
+  if (authStatus == 3) {
+    result = true;
+    console.log("相册权限已经开启");
+  } else {
+    console.log("相册权限没有开启");
+  }
+  plus.ios.deleteObject(PHPhotoLibrary);
+  return result;
+}
+
+// 判断通讯录权限是否开启
+function judgeIosPermissionContact() {
+  let result = false;
+  const CNContactStore = plus.ios.import("CNContactStore");
+  const cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
+  if (cnAuthStatus == 3) {
+    result = true;
+    console.log("通讯录权限已经开启");
+  } else {
+    console.log("通讯录权限没有开启");
+  }
+  plus.ios.deleteObject(CNContactStore);
+  return result;
+}
+
+// 判断日历权限是否开启
+function judgeIosPermissionCalendar() {
+  let result = false;
+  const EKEventStore = plus.ios.import("EKEventStore");
+  const ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
+  if (ekAuthStatus == 3) {
+    result = true;
+    console.log("日历权限已经开启");
+  } else {
+    console.log("日历权限没有开启");
+  }
+  plus.ios.deleteObject(EKEventStore);
+  return result;
+}
+
+// 判断备忘录权限是否开启
+function judgeIosPermissionMemo() {
+  let result = false;
+  const EKEventStore = plus.ios.import("EKEventStore");
+  const ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
+  if (ekAuthStatus == 3) {
+    result = true;
+    console.log("备忘录权限已经开启");
+  } else {
+    console.log("备忘录权限没有开启");
+  }
+  plus.ios.deleteObject(EKEventStore);
+  return result;
+}
+
+// Android权限查询
+export function requestAndroidPermission(permissionID, quit = true) {
+  return new Promise((resolve, reject) => {
+    plus.android.requestPermissions(
+      [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
+      function (resultObj) {
+        let i;
+        let result = 0;
+        for (i = 0; i < resultObj.granted.length; i++) {
+          const grantedPermission = resultObj.granted[i];
+          console.log('已获取的权限:' + grantedPermission);
+          result = 1
+        }
+        for (i = 0; i < resultObj.deniedPresent.length; i++) {
+          const deniedPresentPermission = resultObj.deniedPresent[i];
+          console.log('拒绝本次申请的权限:' + deniedPresentPermission);
+
+          if (("android.permission.READ_PHONE_STATE" == deniedPresentPermission)) {
+            console.log(`拒绝了电话权限`)
+            if (quit) {
+              plus.runtime.quit()
+            }
+          }
+
+          result = 0
+        }
+        for (i = 0; i < resultObj.deniedAlways.length; i++) {
+          const deniedAlwaysPermission = resultObj.deniedAlways[i];
+          console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
+          result = -1
+        }
+        resolve(result);
+        // 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
+        // if (result != 1) {
+        // gotoAppPermissionSetting()
+        // }
+      },
+      function (error) {
+        console.log('申请权限错误:' + error.code + " = " + error.message);
+        resolve({
+          code: error.code,
+          message: error.message
+        });
+      }
+    );
+  });
+}
+
+// 使用一个方法,根据参数判断权限
+export function judgeIosPermission(permissionID) {
+  if (permissionID == "location") {
+    return judgeIosPermissionLocation()
+  } else if (permissionID == "camera") {
+    return judgeIosPermissionCamera()
+  } else if (permissionID == "photoLibrary") {
+    return judgeIosPermissionPhotoLibrary()
+  } else if (permissionID == "record") {
+    return judgeIosPermissionRecord()
+  } else if (permissionID == "push") {
+    return judgeIosPermissionPush()
+  } else if (permissionID == "contact") {
+    return judgeIosPermissionContact()
+  } else if (permissionID == "calendar") {
+    return judgeIosPermissionCalendar()
+  } else if (permissionID == "memo") {
+    return judgeIosPermissionMemo()
+  }
+  return false;
+}
+
+// 跳转到**应用**的权限页面
+export function gotoAppPermissionSetting() {
+  if (isIos) {
+    const UIApplication = plus.ios.import("UIApplication");
+    const application2 = UIApplication.sharedApplication();
+    const NSURL2 = plus.ios.import("NSURL");
+    // var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
+    const setting2 = NSURL2.URLWithString("app-settings:");
+    application2.openURL(setting2);
+
+    plus.ios.deleteObject(setting2);
+    plus.ios.deleteObject(NSURL2);
+    plus.ios.deleteObject(application2);
+  } else {
+    // console.log(plus.device.vendor);
+    const Intent = plus.android.importClass("android.content.Intent");
+    const Settings = plus.android.importClass("android.provider.Settings");
+    const Uri = plus.android.importClass("android.net.Uri");
+    const mainActivity = plus.android.runtimeMainActivity();
+    const intent = new Intent();
+    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+    const uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
+    intent.setData(uri);
+    mainActivity.startActivity(intent);
+  }
+}
+
+// 检查系统的设备服务是否开启
+// var checkSystemEnableLocation = async function () {
+export function checkSystemEnableLocation() {
+  let result;
+  if (isIos) {
+    result = false;
+    const cllocationManger = plus.ios.import("CLLocationManager");
+    result = cllocationManger.locationServicesEnabled();
+    console.log("系统定位开启:" + result);
+    plus.ios.deleteObject(cllocationManger);
+    return result;
+  } else {
+    const context = plus.android.importClass("android.content.Context");
+    const locationManager = plus.android.importClass("android.location.LocationManager");
+    const main = plus.android.runtimeMainActivity();
+    const mainSvr = main.getSystemService(context.LOCATION_SERVICE);
+    result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
+    console.log("系统定位开启:" + result);
+    return result
+  }
+}

+ 42 - 0
utils/requestPermissions.js

@@ -0,0 +1,42 @@
+/**
+ * 申请权限
+ *
+ * @param {Object} permissions
+ */
+export function requestPermissions(permissions) {
+  return new Promise((resolve, reject) => {
+    plus.android.requestPermissions(permissions, function (e) {
+      if (e.deniedAlways.length > 0) { //权限被永久拒绝
+        // 弹出提示框解释为何需要定位权限,引导用户打开设置页面开启
+        console.log('Always Denied!!! ' + e.deniedAlways.toString());
+        return reject({
+          code: -1,
+          message: '权限被永久拒绝',
+          deniedAlways: e.deniedAlways
+        });
+      }
+
+      if (e.deniedPresent.length > 0) { //权限被临时拒绝
+        // 弹出提示框解释为何需要定位权限,可再次调用plus.android.requestPermissions申请权限
+        console.log('Present Denied!!! ' + e.deniedPresent.toString());
+
+        return reject({
+          code: -2,
+          message: '权限被临时拒绝',
+          deniedAlways: e.deniedPresent
+        });
+      }
+
+      if (e.granted.length > 0) { // 权限被允许
+        // 调用依赖获取定位权限的代码
+        console.log('Granted!!! ' + e.granted.toString());
+
+        return resolve();
+      }
+    }, function (e) {
+      console.log('Request Permissions error:' + JSON.stringify(e));
+
+      reject(e);
+    });
+  });
+}

Some files were not shown because too many files changed in this diff