sige 1 year ago
parent
commit
886a352b76
  1. 5
      src/web/package.json
  2. 36
      src/web/src/pages/main/Page.vue
  3. 77
      src/web/src/pages/main/contents/OperationTubeRackAdd.vue
  4. 50
      src/web/src/pages/main/contents/notification/TaskSampleAddTubeRackPutIn.vue
  5. 72
      src/web/src/pages/main/contents/notification/TaskSampleAddTubeRackStatusConfirm.vue
  6. 42
      src/web/src/pages/main/contents/notification/TaskStartResetErrorTubeRackPutIn.vue
  7. 9
      src/web/src/stores/AppStore.js

5
src/web/package.json

@ -49,9 +49,6 @@
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
"Chrome 98"
]
}

36
src/web/src/pages/main/Page.vue

@ -59,6 +59,9 @@
</a-layout>
</a-layout>
<loading ref="loadingModal" />
<noti-handler-task-start-reset-error-tube-rack-put-in />
<noti-handler-task-sample-add-tube-rack-put-in />
<noti-handler-task-sample-add-tube-rack-status-confirm />
</template>
<script setup>
import { ref,onMounted, onUnmounted } from 'vue';
@ -73,6 +76,9 @@ import ContentTask from './contents/Task.vue'
import ApiClient from '@/utils/ApiClient';
import Loading from '@/components/Loading.vue'
import Common from '@/utils/Common';
import NotiHandlerTaskStartResetErrorTubeRackPutIn from './contents/notification/TaskStartResetErrorTubeRackPutIn.vue';
import NotiHandlerTaskSampleAddTubeRackPutIn from './contents/notification/TaskSampleAddTubeRackPutIn.vue';
import NotiHandlerTaskSampleAddTubeRackStatusConfirm from './contents/notification/TaskSampleAddTubeRackStatusConfirm.vue';
/** @var {AppStore} */
const appStore = useAppStore();
/** @var {Ref<string>} */
@ -99,6 +105,8 @@ const statusMessage = ref('');
const user = ref(null);
/** @var {number} */
let statusMessageTimer = null;
/** @var {number} */
let notificationTimer = null;
// on mounted
onMounted(mounted);
// on unmounted
@ -106,6 +114,8 @@ onUnmounted(unmounted);
// mounted
async function mounted() {
notificationRefresh();
loadingModal.value.show('设备正在初始化,请稍后...');
let client = ApiClient.getClient();
user.value = await client.userCurrentGet();
@ -121,8 +131,8 @@ async function mounted() {
} else {
let subTitle = await client.deviceRuntimeVariableGet('TaskStartResetMessage');
loadingModal.value.updateSubTitle(subTitle);
await Common.delay(1000);
}
await Common.delay(1000);
} while (true);
loadingModal.value.hide();
refresh();
@ -131,11 +141,35 @@ async function mounted() {
// unmounted
function unmounted() {
clearTimeout(notificationTimer);
if ( null !== statusMessageTimer ) {
clearInterval(statusMessageTimer);
}
}
// refresh notification
async function notificationRefresh() {
let client = ApiClient.getClient();
let notification = await client.call('device/notification-fetch-one');
console.log('notification', notification);
if ( null === notification ) {
notificationTimer = setTimeout(notificationRefresh, 1000);
return ;
}
if ( 'task-action' === notification.type ) {
let action = JSON.parse(notification.data);
console.log('execute task action', action);
let handlers = appStore.notificationHandlers[action.action] || [];
for ( let handler of handlers ) {
await handler(action.task, action.data);
}
}
notificationTimer = setTimeout(notificationRefresh, 1000);
}
// action logout
async function actionUserLogout() {
let client = ApiClient.getClient();

77
src/web/src/pages/main/contents/OperationTubeRackAdd.vue

@ -1,66 +1,41 @@
<template>
<a-popconfirm title="是否添加样本?" ok-text="确认" cancel-text="取消" @confirm="actionAdd">
<a-button class="ml-1"
style="background: transparent;border: solid 1px #becfe7;color: #7c92b1;"
><PlusCircleOutlined /></a-button>
</a-popconfirm>
<!-- 添加样品弹框 -->
<a-modal v-if="puttingConfirmEnable" v-model:open="puttingConfirmEnable"
title="添加样本"
ok-text="确认"
<a-button class="ml-1"
style="background: transparent;border: solid 1px #becfe7;color: #7c92b1;"
@click="actionEnable"
><PlusCircleOutlined /></a-button>
<a-modal v-if="enable" v-model:open="enable"
title="添加样本"
ok-text="确认"
cancel-text="取消"
@ok="actionOk"
@cancel="actionSampleAddCancel"
@ok="actionOk"
>
<p>放入样本后点击确认完成添加</p>
<a-form label-align="left" :label-col="{span:4}" :wrapper-col="{span:20}">
<a-form-item label="ID">
<a-input v-model:value="digestion.eid" />
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup>
import { ref } from 'vue';
import ApiClient from '@/utils/ApiClient';
import { nextTick, ref } from 'vue';
import { Modal } from 'ant-design-vue';
import Common from '@/utils/Common';
/** @var {Object} */
const puttingConfirmEnable = ref(false);
/** @var {Boolean} */
const enable = ref(false);
/** @var {String} */
let taskId = null;
//
function actionAdd() {
nextTick(async () => {
let client = ApiClient.getClient();
let response = await client.taskAppend('SampleAdd');
taskId = response.id;
const digestion = ref(null);
do {
let task = await client.taskExecutionGet(taskId);
if ( 'RUNNING' === task.status ) {
if ( 'WAIT_FOR_PUTTING_CONFIRM' === task.runtimeStatus ) {
puttingConfirmEnable.value = true;
}
} else if ( 'ERROR' === task.status ) {
Modal.error({title: '添加失败', content: task.message});
break ;
} else if ( 'FINISHED' === task.status ) {
break ;
}
await Common.delay(1000);
} while( true );
});
//
function actionEnable() {
digestion.value = {};
digestion.value.eid = null;
enable.value = true;
}
//
//
async function actionOk() {
enable.value = false;
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, 'done');
puttingConfirmEnable.value = false;
}
//
async function actionSampleAddCancel() {
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, 'cancel');
puttingConfirmEnable.value = false;
await client.taskAppend('SampleAdd', digestion.value);
}
</script>

50
src/web/src/pages/main/contents/notification/TaskSampleAddTubeRackPutIn.vue

@ -0,0 +1,50 @@
<template>
<!-- 添加样品弹框 -->
<a-modal v-if="enable" v-model:open="enable"
title="添加样本"
ok-text="确认"
cancel-text="取消"
@ok="actionOk"
@cancel="actionCancel"
>
<p>放入样本后点击确认完成添加</p>
</a-modal>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useAppStore } from '@/stores/AppStore';
import ApiClient from '@/utils/ApiClient';
/** @var {AppStore} */
const appStore = useAppStore();
/** @var {Ref<boolean>} */
const enable = ref(false);
/** @var {string} */
let taskId = null;
// on mounted
onMounted(mounted);
// mounted
function mounted() {
appStore.registerNotificationHandler('TaskSampleAddTubeRackPutIn', handleNotification);
}
// handle TaskSampleAddTubeRackPutIn
function handleNotification( task ) {
taskId = task;
enable.value = true;
}
//
async function actionOk() {
enable.value = false;
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, 'PutInConfirm', {result:'ok'});
}
//
async function actionCancel() {
enable.value = false;
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, 'PutInConfirm', {result:'canceled'});
}
</script>

72
src/web/src/pages/main/contents/notification/TaskSampleAddTubeRackStatusConfirm.vue

@ -0,0 +1,72 @@
<template>
<a-modal v-if="enable" v-model:open="enable" title="标记空位">
<div class="relative">
<div>
<img :src="imageShotData" class="w-full rounded-xl" />
</div>
<div class="absolute top-0 w-full h-full flex flex-col justify-around">
<div v-for="row in 4" :key="row" class="h-full flex flex-row justify-around">
<div v-for="col in 4" :key="col" class="h-full w-full p-2 flex flex-row items-center justify-center">
<div class="w-1/2 h-1/2 rounded-full border-5 border-dashed border-gray-300"
:class="{'!border-red-500':slotEmptyIndexList.includes((row-1)*4+(col-1))}"
@click="actionTubeEmptyToggle((row-1)*4+(col-1))"
></div>
</div>
</div>
</div>
</div>
<template #footer>
<a-button type="primary" @click="actionOk">确定</a-button>
</template>
</a-modal>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useAppStore } from '@/stores/AppStore';
import ApiClient from '@/utils/ApiClient';
/** @var {AppStore} */
const appStore = useAppStore();
/** @var {Ref<boolean>} */
const enable = ref(false);
/** @var {Object} */
const imageShotData = ref(null);
/** @var {Array} */
const slotEmptyIndexList = ref([]);
/** @var {string} */
let taskId = null;
// on mounted
onMounted(mounted);
// mounted
function mounted() {
appStore.registerNotificationHandler('TaskSampleAddTubeRackStatusConfirm', handleNotification);
}
// handle TaskSampleAddTubeRackStatusConfirm
async function handleNotification( task ) {
let client = ApiClient.getClient();
let response = await client.call('camera/take-shot');
imageShotData.value = response.data;
slotEmptyIndexList.value = [];
taskId = task;
enable.value = true;
}
//
function actionTubeEmptyToggle(index) {
if ( slotEmptyIndexList.value.includes(index) ) {
slotEmptyIndexList.value = slotEmptyIndexList.value.filter(item => item !== index);
} else {
slotEmptyIndexList.value.push(index);
}
}
//
async function actionOk() {
enable.value = false;
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, 'TubeStatusConfirm', {emptyList:slotEmptyIndexList.value});
}
</script>

42
src/web/src/pages/main/contents/notification/TaskStartResetErrorTubeRackPutIn.vue

@ -0,0 +1,42 @@
<template>
<a-modal v-if="enable" v-model:open="enable" title="设备准备中...">
<p>请放入空试管架用于异常处理 放置完成后请点击 确定 按钮以继续</p>
<template #footer>
<a-button type="primary" @click="actionOk">确定</a-button>
</template>
</a-modal>
</template>
<script setup>
import { onMounted, ref } from 'vue';
import { useAppStore } from '@/stores/AppStore';
import ApiClient from '@/utils/ApiClient';
/** @var {AppStore} */
const appStore = useAppStore();
/** @var {Ref<boolean>} */
const enable = ref(false);
/** @var {string} */
let taskId = null;
/** @var {Object} */
let params = null;
// on mounted
onMounted(mounted);
// mounted
function mounted() {
appStore.registerNotificationHandler('TaskStartResetErrorTubeRackPutIn', handleTaskStartResetErrorTubeRackPutIn);
}
// handle TaskStartResetErrorTubeRackPutIn
function handleTaskStartResetErrorTubeRackPutIn( task, data ) {
taskId = task;
params = data;
enable.value = true;
}
// action ok
async function actionOk() {
enable.value = false;
let client = ApiClient.getClient();
await client.taskActionExecute(taskId, "ErrorTubeRackPutIn");
}
</script>

9
src/web/src/stores/AppStore.js

@ -8,6 +8,8 @@ export const useAppStore = defineStore('AppStore', {
isDeviceReady : false,
// is camera enable
isCameraEnable : false,
// notification handlers
notificationHandlers : {},
};
},
@ -25,5 +27,12 @@ export const useAppStore = defineStore('AppStore', {
setCameraEnable( isEnable ) {
this.isCameraEnable = isEnable;
},
// register notification handler
registerNotificationHandler( name, handler ) {
if ( !this.notificationHandlers[name] ) {
this.notificationHandlers[name] = [];
}
this.notificationHandlers[name].push(handler);
}
},
})
Loading…
Cancel
Save