diff --git a/src/assets/img/icon/exclamation-cricle-red-fill.svg b/src/assets/img/icon/exclamation-cricle-red-fill.svg
new file mode 100644
index 0000000..62fc034
--- /dev/null
+++ b/src/assets/img/icon/exclamation-cricle-red-fill.svg
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/src/components/MyModal.vue b/src/components/MyModal.vue
new file mode 100644
index 0000000..6fec489
--- /dev/null
+++ b/src/components/MyModal.vue
@@ -0,0 +1,133 @@
+
+
+
+
+

+
+
+
+
+
+
+ {{ props.content }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/Operator.vue b/src/components/Operator.vue
index 1744b0e..8ba426c 100644
--- a/src/components/Operator.vue
+++ b/src/components/Operator.vue
@@ -487,6 +487,7 @@ import { useOperatorStore, useWebSocketStore, useSettingStore } from '@/store'
import { startDisinfectionJSON, getStateJSON } from '@/mock/command'
import { showSuccessToast, showFailToast } from 'vant'
import { time_To_hhmmss } from '@/utils'
+import MyModal from '../utils/MyModal'
const operatorStore = useOperatorStore()
const webSocketStore = useWebSocketStore()
@@ -570,20 +571,29 @@ const startDisinfect = () => {
realStart()
}
-const realStart = () => {
- localStorage.setItem('logVal', logVal.value)
- if (
- operatorStore.disinfectStatus == 0 ||
- operatorStore.disinfectStatus == 5
- ) {
- localStorage.removeItem('bin')
- localStorage.removeItem('envir1')
- localStorage.removeItem('envir2')
- webSocketStore.sendCommandMsg(
- startDisinfectionJSON(parseInt(logVal.value), parseInt(roomSize.value)),
- )
- props.changeShowOperator(false)
- }
+// 开始消毒
+async function realStart() {
+ operatorStore.updateShowStartReady(true)
+ localStorage.setItem('logVal', logVal.value)
+ if ( operatorStore.disinfectStatus == 0 || operatorStore.disinfectStatus == 5 ) {
+ localStorage.removeItem('bin')
+ localStorage.removeItem('envir1')
+ localStorage.removeItem('envir2')
+
+ try {
+ await webSocketStore.call('startDisinfection', {
+ loglevel : parseInt(logVal.value),
+ roomVolume : parseInt(roomSize.value),
+ });
+ } catch ( e ) {
+ operatorStore.updateShowStartReady(false)
+ await MyModal.error(`无法开始消毒 : ${e.message || e}`);
+ return ;
+ }
+
+ operatorStore.updateShowStartReady(false)
+ props.changeShowOperator(false)
+ }
}
const showLogPicker = () => {
diff --git a/src/main.js b/src/main.js
index a7d2205..1148c9d 100644
--- a/src/main.js
+++ b/src/main.js
@@ -23,6 +23,7 @@ import 'vant/lib/index.css'
import '@/assets/css/reset.css'
import './style.scss'
import MyInput from 'cpns/MyInput.vue'
+import MyModal from 'cpns/MyModal.vue'
createApp(App)
.use(router)
@@ -41,4 +42,5 @@ createApp(App)
.use(Toast)
.use(store)
.component('my-input', MyInput)
+ .component('my-modal', MyModal)
.mount('#app')
diff --git a/src/store/modules/websocket.js b/src/store/modules/websocket.js
index 2a5f42d..b47eafd 100644
--- a/src/store/modules/websocket.js
+++ b/src/store/modules/websocket.js
@@ -23,10 +23,31 @@ export const useWebSocketStore = defineStore({
socketCommandInstance: null,
// 事件上报websocket 实例
socketEventInstance: null,
+ // Event Handlers
+ eventHandlers : {},
+
+ // Call ID Counter
+ callIdCounter : 0,
+ // Call Resolve Handler Map
+ callPromiseHandlers : {},
+ // Call Param Merge Commands
+ callparamMergeCmds : [
+ 'cleanDisinfectionRecord', 'startDisinfection', 'changeDisinfectionParameter','setSettingVal'
+ ],
}
},
// actions
actions: {
+ // register event handler
+ registerEventHandler( event, handler ) {
+ this.eventHandlers[event] = this.eventHandlers[event] || [];
+ this.eventHandlers[event].push(handler);
+ },
+
+
+
+
+
initCommandSocket() {
const url = import.meta.env.VITE_BASE_WS1_URL
const init = new Socket(url)
@@ -41,8 +62,27 @@ export const useWebSocketStore = defineStore({
const runningStore = useRunningStore()
const historyStore = useHistoryStore()
init.connect()
+
+ let $this = this;
init.ws.onmessage = function (ev) {
const { messageId, timeStamp } = JSON.parse(ev.data)
+
+ // 优先处理call-response
+ if ( undefined !== $this.callPromiseHandlers[messageId] ) {
+ let response = JSON.parse(ev.data);
+ const handler = $this.callPromiseHandlers[messageId];
+ delete $this.callPromiseHandlers[messageId];
+ console.log(`[Call Response : ${messageId}] ${handler.message.command} => ${JSON.stringify(response)}`);
+ if ( 0 === response.ackcode ) {
+ handler.resolve(response);
+ } else {
+ handler.reject(response.ackDisplayInfo);
+ }
+ return;
+ }
+
+
+
console.log(JSON.parse(ev.data))
switch (messageId) {
case 'getState':
@@ -275,6 +315,31 @@ export const useWebSocketStore = defineStore({
sendCommandMsg(message) {
this.socketCommandInstance?.msg(message)
},
+
+ // call and wait for response
+ call( command, params=null ) {
+ this.callIdCounter += 1;
+ if ( this.callIdCounter > 1000000 ) {
+ this.callIdCounter = 0;
+ }
+ const callId = `call-${this.callIdCounter}`;
+ return new Promise(( resolve, reject ) => {
+ let message = {};
+ message.command = command;
+ message.messageId = callId;
+ if ( null !== params ) {
+ if ( this.callparamMergeCmds.includes(command) ) {
+ message = { ...message, ...params };
+ } else {
+ message.params = params;
+ }
+ }
+ this.callPromiseHandlers[callId] = { resolve, reject, message };
+ console.log(`[Call Request : ${callId}] ${command}(${JSON.stringify(params)})`);
+ this.sendCommandMsg(message);
+ });
+ },
+
initEventSocket() {
const url = import.meta.env.VITE_BASE_WS2_URL
const init = new Socket(url)
@@ -284,9 +349,21 @@ export const useWebSocketStore = defineStore({
const settingStore = useSettingStore()
const operatorStore = useOperatorStore()
const echartsStore = useEchartsStore()
+
+ let $this = this;
init.ws.onmessage = function (ev) {
// console.log(JSON.parse(ev.data))
const { command, timeStamp } = JSON.parse(ev.data)
+ if ( undefined !== $this.eventHandlers[command] ) {
+ let data = JSON.parse(ev.data);
+ data = data.data;
+ for ( const handler of $this.eventHandlers[command] ) {
+ handler(data);
+ }
+ return ;
+ }
+
+
switch (command) {
case 'RealtimeSensorDataReport':
const { sensor_data } = JSON.parse(ev.data)
diff --git a/src/utils/MyModal.js b/src/utils/MyModal.js
new file mode 100644
index 0000000..a74a7c6
--- /dev/null
+++ b/src/utils/MyModal.js
@@ -0,0 +1,60 @@
+import { createApp, h } from 'vue';
+import MyModalComponent from 'cpns/MyModal.vue';
+export default class MyModal {
+ // show error message
+ static error( message ) {
+ return new Promise( resolve => {
+ const modalContainer = document.createElement('div');
+ document.body.appendChild(modalContainer);
+ const modalApp = createApp({
+ render() {
+ return h(MyModalComponent, {
+ ref : 'modal',
+ icon : 'warning',
+ type : 'info',
+ content : message,
+ onOk : () => {
+ modalApp.unmount();
+ document.body.removeChild(modalContainer);
+ resolve();
+ }
+ });
+ },
+ });
+
+ const vm = modalApp.mount(modalContainer);
+ vm.$refs.modal.show();
+ });
+ }
+
+ // show confirm message
+ static confirm( message ) {
+ return new Promise( resolve => {
+ const modalContainer = document.createElement('div');
+ document.body.appendChild(modalContainer);
+ const modalApp = createApp({
+ render() {
+ return h(MyModalComponent, {
+ ref : 'modal',
+ icon : 'warning',
+ type : 'confirm',
+ content : message,
+ onOk : () => {
+ modalApp.unmount();
+ document.body.removeChild(modalContainer);
+ resolve(true);
+ },
+ onCancel : () => {
+ modalApp.unmount();
+ document.body.removeChild(modalContainer);
+ resolve(false);
+ }
+ });
+ },
+ });
+
+ const vm = modalApp.mount(modalContainer);
+ vm.$refs.modal.show();
+ });
+ }
+}
\ No newline at end of file