Tinger 1 rok pred
rodič
commit
d89ce6db69

+ 11 - 5
public/static/debugger.js

@@ -34,8 +34,14 @@ const randStr = len => {
         let body = JSON.parse(data.data);
         socketHandler[body.event] && socketHandler[body.event](body.data);
     }
-    socket.onclose = () => socket = null;
-}, sendEvent = (event, data) => socket.send(JSON.stringify({event, data}));
+    socket.onclose = e => {
+        socket = null;
+        if (e.code === 1006) connectSocket();
+    }
+}, sendEvent = (event, data) => {
+    if (socket !== null) socket.send(JSON.stringify({event, data}));
+    else setTimeout(() => sendEvent(event, data), 1000);
+};
 
 window.onload = () => {
     const $searchIcon = document.getElementById("search-icon"),
@@ -58,8 +64,8 @@ window.onload = () => {
         $stopDebug = document.getElementById("stop-debug");
     const filterAndShow = seq => {
         $devices.innerHTML = "";
-        for(let key in DevicesAll) if (key.includes(seq)) DevicesShow[key] = DevicesAll[key];
-        for(let key in DevicesShow) {
+        for (let key in DevicesAll) if (key.includes(seq)) DevicesShow[key] = DevicesAll[key];
+        for (let key in DevicesShow) {
             let $device = createDeviceNode(key, DevicesShow[key].online);
             $device.onclick = function () {
                 DeviceNow = DevicesShow[this.getAttribute("rel")];
@@ -127,4 +133,4 @@ window.onload = () => {
     socketHandler.openResult = data => alert(data.type + (data.result ? "-成功" : "-失败"));
     socketHandler.workFinished = data => alert(data);
     connectSocket();
-}
+}

+ 44 - 1
src/App.vue

@@ -27,6 +27,45 @@ import AlertPopup from "@/components/AlertPopup";
 
 const GapTime = 200;
 export default {
+  directives: {
+    click: {
+      mounted(el, binding) {
+        let timer = null, count = 0, timeout = 150;
+        const clearTimer = () => {
+          clearTimeout(timer);
+          timer = null;
+        }
+        const handler = function () {
+          if (timer === null) {
+            count = 0;
+            timer = setTimeout(clearTimer, 1000);
+          }
+          count++;
+          if (count === 5) {
+            setTimeout(() => {
+              if (count === 5) {
+                count = 0;
+                binding.value.t5();
+              }
+            }, timeout);
+          } else if (count === 7) {
+            setTimeout(() => {
+              if (count === 7) {
+                count = 0;
+                binding.value.t7();
+              }
+            }, timeout);
+          }
+        }
+        el.__my_click = handler;
+        el.addEventListener("click", handler);
+      },
+      unmounted(el) {
+        el.removeEventListener("click", el.__my_click);
+        delete el.__my_click;
+      }
+    }
+  },
   components: {
     AlertPopup,
     DeviceFixPage,
@@ -84,6 +123,7 @@ export default {
     _onWineResult(wines) {
       for (let i = 0; i < wines.length; ++i) {
         wines[i].cell = i;
+        wines[i].density = wines[i].density / 1000;
         wines[i].price_in_yuan = wines[i].price / 100;  // 分 -> 元
         wines[i].remain_in_weight = this.$utils.Volume2Weight(wines[i].remain, wines[i].density);  // ml -> 两
       }
@@ -118,7 +158,7 @@ export default {
       this.$utils.Android("setVolume", this.$utils.ParamMap.VolumeAdv);
     },
     addDebug(msg) {
-      this.debug.texts.push(msg);
+      this.debug.texts.unshift(msg);
     },
     AlertReady() {
       this.$refs.alert.Update(this.alert.options);
@@ -146,8 +186,11 @@ export default {
     if (window.android === undefined) this.$utils.VmAndroid();
 
     this.$utils.Register("__Error_Happened__", this.ShowError);
+    this.$utils.Register("pon", () => {
+    });
     this.$utils.Register("startApp", this._start);
     this.$utils.Android("onWebMounted");
+    setInterval(() => this.$utils.Android("pin"), 10 * 60 * 1000);
   }
 }
 </script>

+ 3 - 2
src/pages/AdvertisePage.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <img v-if="ads[index].type" :src="ads[index].src" :style="full" alt="...">
-    <video v-else :src="ads[index].src" :style="full" autoplay/>
+    <video ref="video" v-else :src="ads[index].src" :style="full" autoplay/>
   </div>
 </template>
 
@@ -37,10 +37,11 @@ export default {
     clearTimeout(Timer);
     Timer = setTimeout(this.next, this.ads[this.index].duration);
   },
-  unmounted() {
+  beforeUnmount() {
     clearTimeout(Timer);
     Timer = null;
     Counter = -1;
+    if (this.$refs.video) this.$refs.video.pause();
   },
   computed: {
     full() {

+ 2 - 2
src/pages/WineControlPage.vue

@@ -79,7 +79,7 @@ export default {
       this.$refs.outPage.Over();
       this.$refs.payPage.Over();
       this.$refs.detailPage.Over();
-      this.$refs.listPage.Start();
+      this.$refs.listPage.Start(true);
       this.detailClass = this.payClass = this.outClass = {in: false, out: true};
     }
   },
@@ -144,4 +144,4 @@ export default {
 .slide-out {
   animation: slide-out var(--duration) forwards;
 }
-</style>
+</style>

+ 38 - 9
src/pages/WineDetailPage.vue

@@ -14,15 +14,15 @@
       </div>
       <div class="right">
         <div class="right-top">
-          <h1>{{ wine.name }}</h1>
+          <h1 class="wine-name">{{ wine.name }}<small>{{ concentration }}°</small></h1>
           <div class="info">
             <h3>¥<span class="wine-price">{{ wine.price_in_yuan }}</span>/两</h3>
             <div class="remain">剩余:<span :style="`color: ${color_of_remain};`">{{ wine.remain_in_weight }}</span> 两
             </div>
           </div>
-          <div class="count-tip">请选择购买份额(单位:两)</div>
+          <div class="count-tip">请选择购买份额</div>
           <div class="count-items">
-            <span :class="class_of(c)" v-for="c in 20" :key="c" @click="try_choose(c)">{{ c }}</span>
+            <span :class="class_of(c)" v-for="c in selectList" :key="c" @click="try_choose(c)">{{ c }} 两</span>
           </div>
         </div>
         <div class="button" @click="try_buy">
@@ -34,7 +34,7 @@
 </template>
 
 <script>
-let Timer = null, Index = 0;
+let Timer = null, Index = 0, LightTimer = null, LightEpoch = 6;
 export default {
   name: "WineDetailPage",
   data() {
@@ -43,6 +43,7 @@ export default {
         id: 0, name: "", price: 0, density: 0, picture: "", describe: "", remain: 0, ppv: 0,
         price_in_yuan: 0, remain_in_weight: 0, cell: 0
       },
+      selectList: [2, 3, 4, 5, 6, 7, 8, 9, 10],
       time: this.$utils.ParamMap.DetailTimeOut,
       selected: 1
     }
@@ -52,7 +53,8 @@ export default {
       if (index !== undefined) {
         Index = index;
         this.wine = this.$utils.Wines[index];
-        this.selected = 1;
+        this.selected = 2;
+        this.spark_light()
       }
       this.time = this.$utils.ParamMap.DetailTimeOut;
       this.clear_timer();
@@ -62,6 +64,23 @@ export default {
     },
     Over() {
       this.clear_timer();
+      if (LightTimer !== null) {
+        clearInterval(LightTimer);
+        LightTimer = null;
+        setTimeout(() =>  this.$utils.Android("lightOff", Index), 200);
+      }
+    },
+    spark_light() {
+      let epoch = LightEpoch;
+      this.$utils.Android("lightOn", Index);
+      LightTimer = setInterval(() => {
+        if (--epoch === 0) {
+          clearInterval(LightTimer);
+          LightTimer = null;
+          return;
+        }
+        this.$utils.Android(epoch % 2 === 0 ? "lightOn" : "lightOff", Index);
+      }, 1000);
     },
     get_icon(name) {
       return `${process.env.BASE_URL}icon/${name}.svg`;
@@ -101,6 +120,9 @@ export default {
     },
     cash() {
       return (this.wine.price * this.selected / 100).toFixed(2);
+    },
+    concentration() {
+      return (this.wine.degree / 100).toFixed(2)
     }
   }
 }
@@ -183,9 +205,16 @@ export default {
   width: 100%;
 }
 
-h1 {
+.wine-name {
   margin-block-start: 0;
   font-size: 34px;
+  display: flex;
+  align-items: flex-end;
+}
+
+.wine-name > small {
+  font-size: 24px;
+  margin-left: 20px;
 }
 
 .info {
@@ -227,8 +256,8 @@ h3 {
 }
 
 .item {
-  width: 18%;
-  height: 60px;
+  width: 30%;
+  height: 70px;
   margin-bottom: 20px;
   display: flex;
   justify-content: center;
@@ -274,4 +303,4 @@ h3 {
   transform: scale(0.99);
   box-shadow: 1px 2px 4px lightgray;
 }
-</style>
+</style>

+ 5 - 5
src/pages/WineListPage.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="wines">
-    <div class="wine" v-for="(wine, index) in wines" :key="keys[index]" @click="detail_of(index)">
+    <div class="wine" v-for="(wine, index) in wines" :key="index + ':' + keys[index]" @click="detail_of(index)">
       <img class="wine-picture" :src="wine.picture" alt="wine-image">
       <h2>{{ wine.name }}</h2>
       <div class="info">
@@ -19,12 +19,12 @@ export default {
   data() {
     return {
       wines: this.$utils.Wines,
-      keys: [10, 11, 12, 13]
+      keys: [1, 2, 3, 4]
     };
   },
   methods: {
-    Start() {
-      for (let i = 0; i < 4; i++) this.keys[i]++;
+    Start(update) {
+      if (update === true) for (let i = 0; i < 4; i++) this.keys[i]++;
       this.clear_timer();
       Timer = setTimeout(() => {
         this.$emit("list2adv");
@@ -113,4 +113,4 @@ h3 {
   color: rgba(0, 0, 0, .4);
   font-size: 20px;
 }
-</style>
+</style>

+ 18 - 6
src/pages/WineOutPage.vue

@@ -92,7 +92,7 @@ export default {
       this.$utils.Android("lightOn", this.wine.cell);
       setTimeout(() => {
         this.$utils.EventBus["debug"]("continually command: read-weight");
-        this.$utils.Android("isCupProperlyPlaced");
+        this.$utils.Android("isCupProperlyPlaced", this.wine.cell);
       }, Gap);
     },
     Over() {
@@ -106,9 +106,13 @@ export default {
       this.$utils.EventBus["debug"](`command: close-valve[${this.wine.cell}]`);
       this.$utils.Android("closeValve", this.wine.cell);
       setTimeout(() => {
+        this.$utils.EventBus["debug"](`command: close-gas`);
+        this.$utils.Android("closeGas");
+      }, Gap);
+      setTimeout(() => {
         this.$utils.EventBus["debug"](`command: light-off[${this.wine.cell}]`);
         this.$utils.Android("lightOff", this.wine.cell);
-      }, Gap);
+      }, Gap * 2);
       this.$utils.EventBus["ShowAlert"]({
         title: "发生故障", subtitle: `请联系管理人员:${reason}`, color: "red", icon: this.get_icon("error"),
         button: {need: true, text: "确 认 并 返 回"}, callback: () => this.$emit("out2list")
@@ -126,6 +130,10 @@ export default {
         button: {need: true, text: "开 始 出 酒", countdown: sec}, callback: () => {
           this.stage.current = 1;
           Timer = setTimeout(() => this._onErrorHappened("酒水不足-1"), 3000);
+          setTimeout(() => {
+            this.$utils.EventBus["debug"](`command: open-gas`);
+            this.$utils.Android("openGas");  // cell号酒, 一共pulse个流量脉冲
+          }, Gap);
           this.$utils.EventBus["debug"](`command: open-valve[${this.wine.cell}] for pulses[${this.wine.pulse}]`);
           this.$utils.Android("openValve", this.wine.cell, this.wine.pulse);  // cell号酒, 一共pulse个流量脉冲
         }
@@ -168,9 +176,13 @@ export default {
       this.$utils.EventBus["debug"](`command: close-valve[${this.wine.cell}]`);
       this.$utils.Android("closeValve", this.wine.cell);
       setTimeout(() => {
-        this.$utils.EventBus["debug"]("continually command: read-weight");
-        this.$utils.Android("readSteadyWeight");
+        this.$utils.EventBus["debug"]("command: close-gas");
+        this.$utils.Android("closeGas");
       }, Gap);
+      setTimeout(() => {
+        this.$utils.EventBus["debug"]("continually command: read-weight");
+        this.$utils.Android("readSteadyWeight", this.wine.cell);
+      }, Gap * 2);
     },
     clear_timer() {
       if (Timer !== null) clearTimeout(Timer);
@@ -181,7 +193,7 @@ export default {
       this.$utils.EventBus["debug"]("wine out finished");
       this.$utils.EventBus["ShowAlert"]({
         title: "温馨提示", subtitle: "您的酒品已全部取出,请拿好您的商品", color: "deepskyblue", icon: this.get_icon("finish"),
-        button: {need: true, text: "返 回 列 表", countdown: -1}, callback: () => this.$emit("out2list")
+        button: {need: true, text: "返 回 列 表", countdown: 10}, callback: () => this.$emit("out2list")
       });
     },
     stage_class(index) {
@@ -339,4 +351,4 @@ export default {
   font-size: 22px;
   font-weight: bold;
 }
-</style>
+</style>

+ 32 - 17
src/utils/lib.js

@@ -1,13 +1,14 @@
 let DebugMode = false, Wines = [], ParamMap = {
-    ListTimeOut: 60,
-    DetailTimeOut: 120,
-    PayTimeOut: 180,
-    WaitCountDown: 5,
-    WarnLine: 3000,
-    DangerLine: 500,
-    VolumeAdv: 5,
-    VolumeNormal: 15
-}, EventBus = {}, socket = null, socketUrl, SockEventMap = {"pon": undefined};
+        ListTimeOut: 60,
+        DetailTimeOut: 120,
+        PayTimeOut: 180,
+        WaitCountDown: 5,
+        WarnLine: 3000,
+        DangerLine: 500,
+        VolumeAdv: 5,
+        VolumeNormal: 15
+    }, EventBus = {}, SockEventMap = {"pon": c => EventBus["debug"](`time: ${new Date().toLocaleString()}, pin/pon: ${c}`)},
+    socket = null, socketTimer = null, socketUrl = "";
 
 // wss://wine.ifarmcloud.com/api/seller/socket, ws://192.168.1.6:3080/seller/socket
 const ServerPrefix = "wss://wine.ifarmcloud.com/api/seller/socket";
@@ -22,15 +23,19 @@ const Android = (func, ...args) => {
         window._weight = 0;
         window._timer = null;
         window.android = {
+            pin: window.pon,
             onWebMounted: () => window.startApp("EMULATOR32X1X14X0", "v2023.11.01"),
             openFrontGate: () => window.frontGateResult(true),
             openBackGate: () => window.backGateResult(true),
             lightOn: index => console.log(`light on: ${index}`),
             lightOff: index => console.log(`light off: ${index}`),
-            isCupProperlyPlaced: () => {
-                window._weight = 2;  // 0.2g
+            isCupProperlyPlaced: index => {
+                console.log(`is cup properly placed at ${index}`)
+                window._weight = 34;  // 0.2g
                 setTimeout(() => window.cupProperlyPlaced(window._weight), 1500);
             },
+            openGas: () => console.log("open gas"),
+            closeGas: () => console.log("close gas"),
             openValve: (index, pulse) => {
                 console.log(`valve[${index}] opened for: ${pulse}`);
                 let outed = 0;
@@ -49,25 +54,35 @@ const Android = (func, ...args) => {
                 if (window._timer !== null) clearInterval(window._timer);
                 window._timer = null;
             },
-            readSteadyWeight: () => window.steadyWeight(window._weight),
+            readSteadyWeight: index => {
+                console.log(`steady weight of ${index}`);
+                window.steadyWeight(window._weight);
+            },
             setVolume: volume => console.log(`volume will be set to: ${volume}`),
             hide: () => console.log("gesture will be hide"),
             show: () => console.log("gesture will be show")
         };
     },
-    SendWss = data => socket.send(JSON.stringify(data)),
+    SendWss = (data, ttl) => {
+        if (socket !== null) return socket.send(JSON.stringify(data));
+        if (ttl === undefined) ttl = 3;
+        if (ttl > 0) setTimeout(() => SendWss(data, ttl - 1), 1000);
+        EventBus["debug"](`event: ${data.event}, ttl: ${ttl}`);
+    },
     ConnectSocket = device => {
         if (device !== undefined) socketUrl = `${ServerPrefix}/${device}`;
         socket = new WebSocket(socketUrl);
-        socket.onclose = e => {
-            EventBus["debug"](`websocket断开:code[${e.code}], reason[${e.reason}], clean[${e.wasClean}]`);
+        socket.onclose = () => {
+            socket = null;
+            ConnectSocket();
         }
         socket.onopen = () => {
-            setInterval(() => SendWss({event: "pin", data: null}), 50 * 1000);
+            let count = 0;
+            clearInterval(socketTimer);
+            socketTimer = setInterval(() => SendWss({event: "pin", data: count++}), 50 * 1000);
         }
         socket.onmessage = event => {
             let body = JSON.parse(event.data);
-            EventBus["debug"](`event: ${body.event}`);
             SockEventMap[body.event] && SockEventMap[body.event](body.data);
         }
     },