Browse Source

fix:对事件处理逻辑进行补充;目前还缺少对试管架配置更新事件的处理逻辑;增加了一些弹窗组件,用于显示错误事件和通知事件;项目适配待优化;

feature/history-20250108
gzt 8 months ago
parent
commit
096f17954f
  1. 2
      .env.development
  2. 2
      .env.production
  3. 12
      src/App.vue
  4. 2
      src/pages/Index/History.vue
  5. 199
      src/pages/Index/Index.vue
  6. 2
      src/pages/Index/Regular.vue
  7. 30
      src/pages/Index/Regular/Consumables.vue
  8. 43
      src/pages/Index/components/Consumables/MoveLiquidArea.vue
  9. 6
      src/services/Index/Test-tube/test-tube.ts
  10. 2
      src/services/Index/idCard.ts
  11. 24
      src/services/Index/init.ts
  12. 8
      src/store/modules/consumables.ts
  13. 8
      src/style.css
  14. 13
      关于初始化程序的逻辑说明.txt

2
.env.development

@ -1,3 +1,3 @@
VITE_USE_MOCK=true
# VITE_API_BASE_URL=http://localhost:5173
VITE_API_BASE_URL=http://127.0.0.1:8081
VITE_API_BASE_URL=http://127.0.0.1:8080

2
.env.production

@ -1,4 +1,4 @@
VITE_USE_MOCK=false
# VITE_API_BASE_URL=http://localhost:5173
VITE_API_BASE_URL=http://127.0.0.1:8081
VITE_API_BASE_URL=http://127.0.0.1:8080
# http://127.0.0.1:8081

12
src/App.vue

@ -1,14 +1,14 @@
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { getDeviceStatus } from './services';
// import { getDeviceStatus } from './services';
//500ms
const pollingInterval = 500;
// const pollingInterval = 500;
let pollingTimer: any;
const getEvent = async () => {
const res = await getDeviceStatus();
console.log(res);
};
// const getEvent = async () => {
// const res = await getDeviceStatus();
// console.log(res);
// };
onMounted(() => {
// pollingTimer = setInterval(getEvent, pollingInterval);
})

2
src/pages/Index/History.vue

@ -441,7 +441,7 @@ onMounted(() => {
<style scoped lang="less">
#history-container {
width: 100%;
padding-bottom: 6rem;
padding-bottom: 96px;
.history-filter {
width: 70.5625rem;

199
src/pages/Index/Index.vue

@ -71,7 +71,12 @@
<InitWarn v-if="showFailModal" :visible="showFailModal" title="检测失败" :message="failMessage"
icon="/src/assets/Warn.svg" cancelText="返回" confirmText="确认" @close="showFailModal = false"
@confirm="checkIfResetCompleted" />
<InitWarn v-if="idCardInserted" :visible="idCardInserted" title="检测到id卡插入" message="是否保存id卡信息" cancelText="返回"
icon="/src/assets/update-pin-icon.svg" confirmText="确认保存" @close="idCardInserted = false" @confirm="saveIdInfo" />
<InitWarn v-if="showErrorModal" :visible="showErrorModal" title="错误提示" :message="ErrorMessage"
icon="/src/assets/Warn.svg" cancelText="返回" confirmText="确认" @close="confirmError" @confirm="confirmError" />
<InitWarn v-if="showWarnModal" :visible="showWarnModal" title="注意" :message="WarnMessage" cancelText="返回"
icon="/src/assets/update-pin-icon.svg" confirmText="确认" @close="confirmWarn" @confirm="confirmWarn" />
</template>
@ -79,9 +84,9 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { Time, InitWarn, LoadingModal } from './components/Consumables';
import { getCheckList, startWork, pauseWork, continueWork, stopWork, pollAllAppEvents } from '../../services/index';
import { getCheckList, startWork, pauseWork, continueWork, stopWork, pollAllAppEvents, getInitState, initDevice, saveMountedCardInfo, openBuzzer, closeBuzzer } from '../../services/index';
import { CheckItem, User } from '../../types/Index';
import { useConsumablesStore } from '../../store';
const selectedTab = ref(sessionStorage.getItem('selectedTab') || '常规');
const lineWidth = ref(0);
const lineLeft = ref(0);
@ -91,81 +96,95 @@ const showAlreadyModal = ref(false);
const showFailModal = ref(false);
const checkData = ref<CheckItem[]>([]);
const failItems = ref<CheckItem[]>([]);
const consumableStore = useConsumablesStore();
//
const user = ref<User>(JSON.parse(sessionStorage.getItem('token') || '{}') as unknown as User)
console.log(user.value);
const isTesting = ref(false); //
const isPaused = ref(false); //
const username = ref<string>(user.value.account)
const failMessage = ref(''); //
const idCardInserted = ref(false) // id
//
const EventText = ref<string>('闲置...')
const showWarnModal = ref(false)
const ErrorMessage = ref<string>('')
const showErrorModal = ref(false)
const WarnMessage = ref<string>('')
interface EventType {
typeName: string,
timestamp: number
projectInfo?: {
id: number,
projName: string,
lotId: string,
expiryDate: number,
projId: 1,
palteCode: number,
updateChipVersion: number
},
error?: {
code: string,
prompt?: {
type: string,
projName?: string,
exmsg?: string,
mid?: string,
cmdId?: string,
actionStep?: string
info: string,
detailInfos: string[],
stackInfo: null
}
actionStep?: string,
actionStepName?: string
}
// A8kEcodeContextListPromptEvent
const handleA8kEcodeContextListPromptEvent = (error: any): string => {
switch (error.code) {
case "APPE_CONSUME_NOT_ENOUGH":
return `${error.projName}耗材不足`;
case "CODEERROR":
return `额外的错误${error.exmsg}`;
case "LOW_ERROR_CHECKCODE_IS_ERROR":
return "校验码错误";
default:
return ''; //
}
};
// const handleA8kEcodeContextListPromptEvent = (error: any): string => {
// switch (error.code) {
// case "APPE_CONSUME_NOT_ENOUGH":
// return `${error.projName}`;
// case "CODEERROR":
// return `${error.exmsg}`;
// case "LOW_ERROR_CHECKCODE_IS_ERROR":
// return "";
// default:
// return ''; //
// }
// };
const getEventText = (data: EventType | EventType[]): string => {
let eventName = '';
// if
const eventTypeMap: { [key: string]: string } = {
"AppIDCardMountEvent": "id卡已插入",
"AppIDCardUnmountEvent": "id卡已拔出",
"AppTubeholderSettingUpdateEvent": "试管架设置已更新",
"A8kEcodeContextListPromptEvent": "设备暂停",
};
// const eventTypeMap: { [key: string]: string } = {
// "AppIDCardMountEvent": "id",
// "AppIDCardUnmountEvent": "id",
// "AppTubeholderSettingUpdateEvent": "",
// "A8kEcodeContextListPromptEvent": "",
// };
// data
const processEvent = (item: EventType) => {
//
const eventText = eventTypeMap[item.typeName];
if (eventText) {
eventName = eventText;
} else if (item.typeName === "AppWarningNotifyEvent" && item.error?.code === "USR_NOT_EXIT") {
//
eventName = "用户不存在";
} else if (item.typeName === "A8kEcodeContextListPromptEvent" && item.error) {
// A8kEcodeContextListPromptEvent
eventName = handleA8kEcodeContextListPromptEvent(item.error);
} else if (item.typeName === "DoA8kStepActionEvent" && item.error) {
//
eventName = `步骤${item.error.actionStep}已执行`;
const processEvent = async (item: EventType) => {
//id
if (item.typeName === "AppIDCardMountEvent") {
consumableStore.isIdCardInserted = true;
idCardInserted.value = true;
eventName = "id卡已插入"
} else if (item.typeName === "AppIDCardUnmountEvent") {
consumableStore.isIdCardInserted = false;
eventName = "id卡已拔出"
} else if (item.typeName === "DoA8kStepActionEvent") {
eventName = item.actionStepName!
} else if (item.typeName === "AppPromptEvents") {
//propmt
if (Array.isArray(item.prompt)) {
console.log("propmt是个数组")
item.prompt.forEach(async (item) => {
if (item.type === "Error") {
showErrorModal.value = true
ErrorMessage.value = item.info
await openBuzzer()
} else if (item.type === "Warn") {
showWarnModal.value = true
WarnMessage.value = item.info
}
})
} else {
console.log("propmt不是数组", item)
}
} else if (item.typeName === "AppTubeholderSettingUpdateEvent ") {
eventName = "试管架配置更新"
//
}
else {
eventName = "闲置..."
}
};
if (Array.isArray(data)) {
// item
data.forEach(processEvent);
@ -188,9 +207,28 @@ const getEvent = async () => {
return
}
}
//
const confirmError = async () => {
showErrorModal.value = false
//
await closeBuzzer()
}
//
const confirmWarn = async () => {
showWarnModal.value = false
return
}
//id
const saveIdInfo = async () => {
const res = await saveMountedCardInfo();
if (res.success) {
console.log("保存id卡信息成功")
idCardInserted.value = false;
}
}
// 10
const pollingInterval = 10000;
const pollingInterval = 500;
let pollingTimer: ReturnType<typeof setInterval>;
onMounted(() => {
@ -214,7 +252,10 @@ const generateErrorMessages = (data: CheckItem[]): string[] => {
//
const startTest = async () => {
const res = await startWork();
await checkIfResetCompleted()
const isCheck = sessionStorage.getItem('testStarted');
if (!isCheck) {
await checkIfResetCompleted()
}
if (res.success) {
isTesting.value = true;
}
@ -235,7 +276,6 @@ const stopTest = async () => {
const res = await stopWork();
if (res.success) {
isTesting.value = false;
sessionStorage.removeItem('testStarted'); //
}
};
//
@ -247,8 +287,8 @@ const continueTest = async () => {
}
};
const handleConfirm = async () => {
console.log('用户确认操作');
showModal.value = false; //
await initDevice(); //
await checkIfResetCompleted(); //
};
@ -257,19 +297,28 @@ const checkIfResetCompleted = async () => {
showLoadingModal.value = true; // LoadingModal
// 2
await new Promise(resolve => setTimeout(resolve, 2000));
await getCheckData(); //
const failedItems = checkData.value.filter(item => !item.pass);
if (failedItems.length > 0) {
const errorMessages = generateErrorMessages(failedItems);
console.log('生成的错误信息:', errorMessages);
failItems.value = failedItems; //
failMessage.value = errorMessages.join('\n'); //
showLoadingModal.value = false; // LoadingModal
showFailModal.value = true; //
} else {
showLoadingModal.value = false; // LoadingModal
showAlreadyModal.value = true; //
//
const initState = await getInitState();
if (initState.ecode === "SUC") {
if (initState.data.passed) {
sessionStorage.setItem('testStarted', "true");
showLoadingModal.value = false;
showAlreadyModal.value = true;
} else {
await getCheckData(); //
const failedItems = checkData.value.filter(item => !item.pass);
if (failedItems.length > 0) {
const errorMessages = generateErrorMessages(failedItems);
console.log('生成的错误信息:', errorMessages);
failItems.value = failedItems; //
failMessage.value = errorMessages.join('\n'); //
showLoadingModal.value = false; // LoadingModal
showFailModal.value = true; //
} else {
showLoadingModal.value = false; // LoadingModal
showAlreadyModal.value = true; //
}
}
}
};
@ -345,8 +394,8 @@ onMounted(() => {
#index-container {
margin: 0;
padding: 0;
width: 75rem;
height: 120.125rem;
width: 1200px;
height: 1920px;
background-color: #fff;
position: relative;
box-sizing: border-box;
@ -377,7 +426,7 @@ onMounted(() => {
.nav-bar {
width: 100%;
height: 5.1875rem;
height: 83px;
margin-bottom: 5px;
display: flex;
justify-content: space-between;
@ -452,7 +501,7 @@ onMounted(() => {
.footer-info {
width: 1200px;
height: 3.25rem;
height: 52px;
display: flex;
justify-content: space-between;
align-items: center;

2
src/pages/Index/Regular.vue

@ -26,7 +26,7 @@ import TabBar from './components/Consumables/TabBar.vue'
}
.main-bottom {
width: 1148px;
width: 1200px;
.buffer-little-title {
display: flex;

30
src/pages/Index/Regular/Consumables.vue

@ -3,17 +3,9 @@
<!--耗材页面 -->
<div class="main-top">
<SpttingPlates :plates="plates" />
<MoveLiquidArea
:isLoad="isLoad"
:isLoading="isLoading"
:moveLiquids="moveLiquids"
:tempTipNum="tempTipNum"
:bufferBig="bufferBig"
:emergencyInfo="emergencyInfo"
@loadConsumables="handleIsLoad"
@unloadConsumables="handleIsUnload"
@updateTipNum="updateTipNum"
/>
<MoveLiquidArea :isLoad="isLoad" :isLoading="isLoading" :moveLiquids="moveLiquids" :tempTipNum="tempTipNum"
:bufferBig="bufferBig" :emergencyInfo="emergencyInfo" @loadConsumables="handleIsLoad"
@unloadConsumables="handleIsUnload" @updateTipNum="updateTipNum" />
</div>
<div class="main-bottom">
<!--缓冲液区域小-->
@ -22,19 +14,9 @@
<div class="content">缓冲液区()</div>
</div>
<div class="ball-area">
<MainComponent
v-for="item in bufferLittles"
:key="item"
class="ball-grid"
:projectName="item.projShortName"
:currentCount="item.num"
:totalBalls="25"
:activatedBalls="item.num"
:columns="5"
gridWidth="370px"
gridHeight="368px"
:activeColor="item.color"
/>
<MainComponent v-for="item in bufferLittles" :key="item" class="ball-grid" :projectName="item.projShortName"
:currentCount="item.num" :totalBalls="25" :activatedBalls="item.num" :columns="5" gridWidth="370px"
gridHeight="368px" :activeColor="item.color" />
</div>
</div>
</div>

43
src/pages/Index/components/Consumables/MoveLiquidArea.vue

@ -57,9 +57,9 @@
<div class="line"></div>
<div class="content">ID芯片区</div>
</div>
<button class="id-button" @click="openTableModal">
<button class="id-button" @click="openTableModal" :disabled="!consumableStore.isIdCardInserted">
<span class="button-text">
{{ IDCardStatus ? '已插入' : '未插入芯片' }}</span>
{{ consumableStore.isIdCardInserted ? '已插入' : '未插入芯片' }}</span>
</button>
</div>
<!--废料区-->
@ -100,17 +100,16 @@ import BallGrid from './BallGrid.vue'
import IdCardInfo from './IdCardInfo.vue'
import { ref, onMounted, watch, onBeforeUnmount, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useEmergencyStore } from '../../../../store'
import { useEmergencyStore, useConsumablesStore } from '../../../../store'
import { Tube, LiquidState, BottleGroup } from '../../../../types/Index/index'
import {
getMountedCardInfo,
wasteArea,
saveMountedCardInfo,
} from '../../../../services/index'
import wasteFullIcon from '@/assets/Index/waste-full.svg'
import wasteIcon from '@/assets/Index/waste.svg'
const emergencyStore = useEmergencyStore()
const consumableStore = useConsumablesStore()
const visible = ref(false)
const openTableModal = () => {
visible.value = true
@ -148,25 +147,23 @@ const handleIsUnload = () => {
const activeTab = ref(0)
//
const wasteStatus = ref(false)
//Id
const IDCardStatus = ref(false)
//
const pollInterVal = 3000
//id
const fetchIdCardStatus = async () => {
try {
const res = await getMountedCardInfo()
if (res.data) {
IDCardStatus.value = true
//
await saveMountedCardInfo()
} else {
IDCardStatus.value = false
}
} catch (error) {
console.log('获取Id卡状态失败', error)
}
}
// const fetchIdCardStatus = async () => {
// try {
// const res = await getMountedCardInfo()
// if (res.data) {
// IDCardStatus.value = true
// //
// await saveMountedCardInfo()
// } else {
// IDCardStatus.value = false
// }
// } catch (error) {
// console.log('Id', error)
// }
// }
//
const fetchWasteStatus = async () => {
try {
@ -179,12 +176,12 @@ const fetchWasteStatus = async () => {
//
const startPolling = () => {
const idCardPoll = setInterval(fetchIdCardStatus, pollInterVal)
// const idCardPoll = setInterval(fetchIdCardStatus, pollInterVal)
const wastePoll = setInterval(fetchWasteStatus, pollInterVal)
//
onBeforeUnmount(() => {
console.log("清除轮询")
clearInterval(idCardPoll)
// clearInterval(idCardPoll)
clearInterval(wastePoll)
})
}

6
src/services/Index/Test-tube/test-tube.ts

@ -1,9 +1,5 @@
import apiClient from '../../../utils/axios'
import type {
DataItem,
handleTube,
TubeActivationStatus,
} from '../../../types/Index'
import type { handleTube, TubeActivationStatus } from '../../../types/Index'
//获取已经配置的试管信息
export const getTestTube = async () => {
try {

2
src/services/Index/idCard.ts

@ -23,7 +23,7 @@ export const saveMountedCardInfo = async () => {
const res = await apiClient.post(
'/api/v1/app/a8kProjectCard/saveMountedCardInfo',
)
return res
return res.data
} catch (error) {
console.log('保存id出错', error)
}

24
src/services/Index/init.ts

@ -3,9 +3,31 @@ import apiClient from '../../utils/axios'
//设备检查api
export const getCheckList = async () => {
try {
const res = await apiClient.post('/api/v1/app/deviceInit/initDevice')
const res = await apiClient.post('/api/v1/app/deviceInit/check')
return res.data
} catch (error) {
console.log('设备检查接口出错', error)
}
}
//设备初始化
export const initDevice = async () => {
try {
const res = await apiClient.post('/api/v1/app/deviceInit/initDevice')
return res.data
} catch (error) {
console.log('设备初始化接口出错', error)
}
}
//获取初始化状态
export const getInitState = async () => {
try {
const res = await apiClient.post(
'/api/v1/app/deviceInit/getDeviceInitedTaskState',
)
return res.data
} catch (error) {
console.log('获取初始化状态接口出错', error)
}
}

8
src/store/modules/consumables.ts

@ -18,7 +18,8 @@ export const useConsumablesStore = defineStore(
const plates = ref<ReactionPlate[]>([])
const bufferLittles = ref<BottleGroup[]>([])
const bufferBig = ref<BottleGroup[]>([])
//id卡是否插入
const isIdCardInserted = ref(false)
// 设置数据的 action
function setConsumablesData(data: ConsumableState) {
isLoad.value = true // 设置为已加载状态
@ -37,6 +38,9 @@ export const useConsumablesStore = defineStore(
bufferLittles.value = []
bufferBig.value = []
}
function updateIdCardStatus(status: boolean) {
isIdCardInserted.value = status
}
return {
isLoad,
@ -45,8 +49,10 @@ export const useConsumablesStore = defineStore(
plates,
bufferLittles,
bufferBig,
isIdCardInserted,
setConsumablesData,
resetConsumablesData,
updateIdCardStatus,
}
},
{

8
src/style.css

@ -45,7 +45,7 @@ button {
}
#app {
max-width: 1280px;
max-width: 1200px;
margin: 0 auto;
text-align: center;
}
@ -64,3 +64,9 @@ button {
background-color: #f9f9f9;
}
}
@media (max-width: 800px) {
:root {
font-size: 0.8em;
}
}

13
关于初始化程序的逻辑说明.txt

@ -0,0 +1,13 @@
逻辑代码位于 src/pages/Index/Index.vue中
1.首先首次登录进入首页会进行初始化程序的调用,会弹窗提醒用户取下试管帽,当用户点击确认取下/开始复位后,执行内部代码
2.调用 “/api/v1/app/deviceInit/initDevice” 接口,初始化设备,并调用 “/api/v1/app/deviceInit/getDeviceStatus” 接口,获取设备状态,如果返回的passed字段是true,则表示初始化成功,否则失败
3.初始化成功后,弹窗告知用户,并将EventText设置为初始化完成(底部状态信息)
4.初始化失败后,弹窗告知用户,会自动调用 /api/v1/app/deviceInit/check 接口 判断是哪个部位初始化没有成功(目前只会显示一个错误,不清楚是否有多个错误)
5.弹出初始化失败并显示失败信息的弹窗后,用户点击确认,会再次进行初始化程序的调用,直到程序没有错误,或者用户点击取消,暂时跳过这个流程,在后续点击开始检测时,会对初始化是否执行成功进行调用,如果没有成功,会再次调用初始化程序
Loading…
Cancel
Save