Browse Source

解决编码问题

feature/user-0111
LiLongLong 7 months ago
parent
commit
150a3118f2
  1. 7
      .eslintrc.ts
  2. 5
      components.d.ts
  3. 4
      package.json
  4. 9
      src/components/Keyboard.vue
  5. 24
      src/components/dialogs/ErrorModal.vue
  6. 1
      src/mock/Index/Running.ts
  7. 69
      src/pages/Index/Index.vue
  8. 2
      src/pages/Index/Regular.vue
  9. 30
      src/pages/Index/Regular/Emergency.vue
  10. 9
      src/pages/Index/Regular/Running.vue
  11. 2
      src/pages/Index/Regular/TestTube.vue
  12. 2
      src/pages/Index/Settings/Users.vue
  13. 2
      src/pages/Index/TestTube/TubeUserId.vue
  14. 4
      src/pages/Index/components/Consumables/IdCardInfo.vue
  15. 20
      src/pages/Index/components/Consumables/MoveLiquidArea.vue
  16. 4
      src/pages/Index/components/Consumables/Warn/InitWarn.vue
  17. 26
      src/pages/Index/components/Running/EmergencyResultDialog.vue
  18. 2
      src/pages/Index/components/Running/SampleDisplay.vue
  19. 10
      src/router/router.ts
  20. 2
      src/types/Index/Running.ts
  21. 3
      src/types/Index/TestTube.ts
  22. 3
      src/utils/getServerInfo.ts
  23. 119
      tsconfig.app.tsbuildinfo
  24. 3
      tsconfig.json
  25. 2
      tsconfig.node.tsbuildinfo

7
.eslintrc.ts

@ -14,5 +14,12 @@ module.exports = {
},
rules: {
// 你可以在这里添加或修改 ESLint 规则
'@typescript-eslint/no-unused-vars': ['error', {
args: 'none', // 不检查函数参数是否被使用
vars: 'exceptDestructuring', // 检查所有变量是否被使用
varsIgnorePattern: '^_', // 忽略以 "_" 开头的变量
argsIgnorePattern: '^_', // 忽略以 "_" 开头的参数
destructuredArrayIgnorePattern: '^_' // 忽略以 "_" 开头的解构数组成员
}],
},
};

5
components.d.ts

@ -9,12 +9,17 @@ declare module 'vue' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElRow: typeof import('element-plus/es')['ElRow']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ErrorModal: typeof import('./src/components/dialogs/ErrorModal.vue')['default']
Keyboard: typeof import('./src/components/Keyboard.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']

4
package.json

@ -38,10 +38,10 @@
"@vitejs/plugin-vue": "^5.1.4",
"@vue/compiler-sfc": "^3.5.12",
"autoprefixer": "^10.4.20",
"eslint": "^9.12.0",
"eslint": "^9.17.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.29.0",
"eslint-plugin-vue": "^9.32.0",
"jest": "^29.7.0",
"postcss-pxtorem": "^6.1.0",
"prettier": "^3.3.3",

9
src/components/Keyboard.vue

@ -1,7 +1,7 @@
<template>
<div class="keyboard-wrapper">
<el-input ref="inputRef" v-model="model" @focus="focusInput" @keyup.enter="handleEnter" v-bind="$attrs">
<template v-for="index in Object.keys($slots)" :key="index" #[index]>
<template v-for="index in slotList" :key="index" #[index]>
<slot :name="index"></slot>
</template>
</el-input>
@ -15,7 +15,7 @@
</template>
<script setup lang="ts">
import { ref, onUnmounted } from 'vue'
import { ref, onUnmounted, useSlots } from 'vue'
import Keyboard from 'simple-keyboard'
import 'simple-keyboard/build/css/index.css'
// import layout from 'simple-keyboard-layouts/build/layouts/chinese.js'
@ -24,6 +24,11 @@ defineOptions({
})
const model = defineModel<string>()
const emits = defineEmits(['onChange', 'enter', 'close', 'focus'])
const slots = useSlots();
const slotList = ref<any[]>([]); // 使
slotList.value = Object.values(slots)
const props = defineProps({
layoutName: {
type: String,

24
src/components/dialogs/ErrorModal.vue

@ -265,10 +265,10 @@ import { eventBus } from '../../eventBus'
import { onMounted, onUnmounted, ref, computed } from 'vue'
import type { ErrorModalData, ErrorDetail } from '../../eventBus'
let ErrorIcon = new URL('@/assets/Warn.svg', import.meta.url).href
let WarnIcon = new URL('@/assets/update-pin-icon.svg', import.meta.url).href
let NotifyIcon = new URL('@/assets/notify.svg', import.meta.url).href
let FatalIcon = new URL('@/assets/fatal.svg', import.meta.url).href
// let ErrorIcon = new URL('@/assets/Warn.svg', import.meta.url).href
// let WarnIcon = new URL('@/assets/update-pin-icon.svg', import.meta.url).href
// let NotifyIcon = new URL('@/assets/notify.svg', import.meta.url).href
// let FatalIcon = new URL('@/assets/fatal.svg', import.meta.url).href
const showErrorStack = ref(false)
const info = ref('')
const type = ref<'Fatal' | 'Error' | 'Warn' | 'Notify'>('Notify')
@ -308,14 +308,14 @@ const buttonClass = computed(() => {
}
})
//
const iconMap = computed(() => {
return {
'Fatal': FatalIcon,
'Error': ErrorIcon,
'Warn': WarnIcon,
'Notify': NotifyIcon
}
})
// const iconMap = computed(() => {
// return {
// 'Fatal': FatalIcon,
// 'Error': ErrorIcon,
// 'Warn': WarnIcon,
// 'Notify': NotifyIcon
// }
// })
const toggleDetails = () => {
isShow.value = !isShow.value

1
src/mock/Index/Running.ts

@ -332,6 +332,7 @@ const runningList = [
]
//试管架信息
const mockTubeRackResponse: TubeRackResponse = {
// @ts-ignore
data: {
tubes: [
{

69
src/pages/Index/Index.vue

@ -41,10 +41,22 @@
<!-- 底部操作信息 -->
<el-footer class="footer-info">
<div class="user-card">
<img class="user-logo" src="@/assets/Index/user.svg"></img>
<div class="user-name">操作人:{{ username || "未登录" }}</div>
</div>
<el-dropdown placement="top-start">
<div class="user-card">
<img class="user-logo" src="@/assets/Index/user.svg"></img>
<div class="user-name">操作人:{{ username || "未登录" }}</div>
</div>
<template #dropdown>
<el-dropdown-menu >
<el-dropdown-item>
<img class="user-logo" src="@/assets/Index/user.svg" height="30"></img>
<button class="logout" @click="onLogout">注销</button>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="equipment-status">
<div class="status-text">系统:{{ EventText }}</div>
</div>
@ -81,15 +93,17 @@
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { Time, InitWarn, LoadingModal } from './components/Consumables';
import { startWork, pauseWork, continueWork, stopWork, getInitState, initDevice, saveMountedCardInfo, openBuzzer, closeBuzzer } from '../../services/index';
import { CheckItem, User } from '../../types/Index';
import { User } from '../../types/Index';
import { useConsumablesStore } from '../../store';
import { createWebSocket } from '../../websocket/socket';
import type { AppEventMessage } from '../../websocket/socket';
import { getServerInfo } from '../../utils/getServerInfo';
import { eventBus } from '../../eventBus';
import { logout } from '@/services/Login/login';
const selectedTab = ref(sessionStorage.getItem('selectedTab') || '常规');
const lineWidth = ref(0);
const lineLeft = ref(0);
@ -97,8 +111,8 @@ const showModal = ref(false);
const showLoadingModal = ref(false);
const showAlreadyModal = ref(false);
const showFailModal = ref(false);
const checkData = ref<CheckItem[]>([]);
const failItems = ref<CheckItem[]>([]);
// const checkData = ref<CheckItem[]>([]);
// const failItems = ref<CheckItem[]>([]);
const consumableStore = useConsumablesStore();
//
const user = ref<User>(JSON.parse(sessionStorage.getItem('token') || '{}') as unknown as User)
@ -152,6 +166,17 @@ const handleAppEvent = (data: AppEventMessage['data']) => {
}
};
//
const router = useRouter();
const onLogout = ()=> {
logout().then(() => {
router.push({
path: "/login",
});
sessionStorage.setItem('token', '')
})
}
//
const confirmError = async () => {
showErrorModal.value = false
@ -186,11 +211,11 @@ onBeforeUnmount(() => {
ws.disconnect();
});
//
const generateErrorMessages = (data: CheckItem[]): string[] => {
return data
.filter(item => !item.pass)
.map(item => `错误:${item.typechinfo} 检测未通过,请检查设备状态。`);
};
// const generateErrorMessages = (data: CheckItem[]): string[] => {
// return data
// .filter(item => !item.pass)
// .map(item => `${item.typechinfo} `);
// };
//
const startTest = async () => {
@ -262,7 +287,7 @@ const pollingInitState = async () => {
}
else {
const infos = res.data.promopt.detailInfos
failMessage.value= infos && infos.length > 0 ? infos.map(d => d.name).join('\n') : res.data.promopt.info
failMessage.value= infos && infos.length > 0 ? infos.map((d:any) => d.name).join('\n') : res.data.promopt.info
showFailModal.value = true; //
}
}
@ -307,14 +332,14 @@ const pollingInitState = async () => {
// }
// };
const isTestTubeSlotReady = ref(false); //
// const isTestTubeSlotReady = ref(false); //
//
const checkTestTubeSlotStatus = (data: CheckItem[]) => {
const slotCheck = data.find(item => item.type === 'CHECK_TEST_TUBE_SLOT_READY');
isTestTubeSlotReady.value = slotCheck?.pass ?? false;
console.log('试管槽状态:', isTestTubeSlotReady.value ? '准备就绪' : '未准备好');
};
// const checkTestTubeSlotStatus = (data: CheckItem[]) => {
// const slotCheck = data.find(item => item.type === 'CHECK_TEST_TUBE_SLOT_READY');
// isTestTubeSlotReady.value = slotCheck?.pass ?? false;
// console.log(':', isTestTubeSlotReady.value ? '' : '');
// };
const handleAlreadyConfirm = () => {
console.log('用户确认操作');
@ -503,6 +528,12 @@ onMounted(() => {
font-size: 26px;
}
}
.logout{
width: 70px;
text-align: center;
font-size: 20px;
margin: auto;
}
}
.main-content {

2
src/pages/Index/Regular.vue

@ -12,7 +12,7 @@
</template>
<script setup lang="ts">
import TabBar from './Components/Consumables/TabBar.vue'
import TabBar from './components/Consumables/TabBar.vue'
import { createWebSocket } from '../../websocket/socket'
import { getServerInfo } from '../../utils/getServerInfo'
import { onMounted, onDeactivated } from 'vue';

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

@ -125,6 +125,7 @@ const ws = createWebSocket(getServerInfo().wsUrl);
const consumableStore = useConsumablesStore();
const emergencyStore = useEmergencyStore();
const deviceStore = useDeviceStore();
console.log('deviceStore---', deviceStore)
// /
const isEmergencyEnabled = ref(true);//
@ -315,20 +316,21 @@ const selectBloodType = (item: any) => {
};
// /
const toggleEmergency = () => {
isEmergencyEnabled.value = !isEmergencyEnabled.value;
if (!isEmergencyEnabled.value) {
//
emergencyPosition.value = {
sampleBarcode: '',
userid: '',
projIds: [],
bloodType: '',
};
projectName.value = '';
bloodType.value = '';
}
};
// const toggleEmergency = () => {
// isEmergencyEnabled.value = !isEmergencyEnabled.value;
// if (!isEmergencyEnabled.value) {
// //
// emergencyPosition.value = {
// sampleBarcode: '',
// userid: '',
// projIds: [],
// bloodType: '',
// };
// projectName.value = '';
// bloodType.value = '';
// }
// };
watch(isEmergencyEnabled, (newVal) => {
if (newVal) {
showTubeSelector.value = true

9
src/pages/Index/Regular/Running.vue

@ -116,14 +116,14 @@
import { ref, onMounted, onUnmounted, watch, onActivated, onDeactivated } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useTestTubeStore, useConsumablesStore } from '../../../store'
import { getBloodTypeLabel, processTubeSettings } from '../Utils'
import { getBloodTypeLabel, processTubeSettings } from '../utils'
import {
SampleDisplay,
PlateDisplay,
LittleBufferDisplay,
EmergencyResultDialog,
} from '../Components'
import BallGrid from '../Components/Consumables/BallGrid.vue'
} from '../components'
import BallGrid from '../components/Consumables/BallGrid.vue'
import { wasteArea, getTubeRackState } from '../../../services/index'
import type { Subtank, TubeRackInfo } from '../../../types/Index'
import { getRunningList } from '../../../services/Index/running/running'
@ -233,7 +233,9 @@ onMounted(() => {
updateProcessedTubeSettings()
// testTubeStore
watch(
// @ts-ignore
() => testTubeStore.tubeInfo?.tubeSettings, //
(newTubeSettings) => {
if (newTubeSettings) {
@ -283,6 +285,7 @@ onActivated(() => {
//
const updateProcessedTubeSettings = () => {
// @ts-ignore
const tubeSettings = testTubeStore.tubeInfo?.tubeSettings || [] //
const plateData = plates.value || [] //

2
src/pages/Index/Regular/TestTube.vue

@ -67,7 +67,7 @@
import { ref, onMounted, nextTick, computed, onActivated } from 'vue'
import * as R from 'ramda'
import { useRouter } from 'vue-router'
import TestTubeRack from '../Components/TestTube/TestTubeRack.vue'
import TestTubeRack from '../components/TestTube/TestTubeRack.vue'
import {
addTestTube,
getTestTube,

2
src/pages/Index/Settings/Users.vue

@ -50,7 +50,7 @@
<script setup lang="ts">
import type { User } from '../../../types/Index'
import { DelWarn, DelMessage, AddUserModal, EnterPinModal } from '../Components'
import { DelWarn, DelMessage, AddUserModal, EnterPinModal } from '../components'
import { ref, onMounted, computed } from 'vue'
import {
getUserList,

2
src/pages/Index/TestTube/TubeUserId.vue

@ -92,7 +92,7 @@ import { useRouter } from 'vue-router'
import * as R from 'ramda'
import { useTestTubeStore, useConsumablesStore } from '../../../store'
import SimpleKeyboard from '../../../components/SimpleKeyboard.vue'
import Tube from '../Components/TestTube/Tube.vue'
import Tube from '../components/TestTube/Tube.vue'
import { updateTubeConfig } from '../../../services'
import { ElMessage } from 'element-plus'

4
src/pages/Index/components/Consumables/IdCardInfo.vue

@ -163,7 +163,7 @@ const selectAll = ref(false) // 全选状态
const totalPages = computed(() => Math.ceil(totalItems.value / pageSize.value))
//
const searchValue = ref<string>('')
// const _searchValue = ref<string>('')
const prevPage = () => {
if (currentPage.value > 1) currentPage.value--
}
@ -182,7 +182,7 @@ const currentData = computed(() => {
//
const displayedPages = computed(() => {
const pages = []
const pages:any = [];
if (totalPages.value <= 5) {
for (let i = 1; i <= totalPages.value; i++) {
pages.push(i)

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

@ -138,6 +138,10 @@
</button>
</div>
</div>
{{ showModal }}
<InitWarn v-if="showModal" :visible="showModal" title="提示" message="请及时清理废料箱"
icon="/src/assets/Warn.svg" confirmText="确定" @close="showModal = false"
@confirm="handleConfirm" />
<!--缓冲液大-->
<div class="buffer-area">
<div class="buffer-title">
@ -159,6 +163,7 @@
</div>
</div>
<IdCardInfo v-model="visible"></IdCardInfo>
</template>
<script setup lang="ts">
@ -174,6 +179,7 @@ import wasteIcon from '@/assets/Index/waste.svg'
import type { EmergencyPosStateMessage } from '@/websocket/socket'
import { createWebSocket } from '@/websocket/socket'
import { isTubeExist } from '@/services/Index/index';
import { InitWarn } from './Warn';
import { getServerInfo } from '@/utils/getServerInfo'
const { wsUrl } = getServerInfo('/api/v1/app/ws/state')
const socket = createWebSocket(wsUrl)
@ -201,6 +207,18 @@ const props = defineProps({
wasteStatus: Boolean,
})
let showModal = ref(false)
const handleConfirm = ()=> {
showModal.value = false;
}
//
const wasteStatus = ref(props.wasteStatus)
watch(() => props.wasteStatus, (newVal)=>{
wasteStatus.value = newVal
if(newVal)showModal.value = true;
},
{ immediate: true, deep: true },
)
//使websocket
const startWebSocket = () => {
socket.connect()
@ -270,7 +288,7 @@ const handleIsUnload = () => {
//
const activeTab = ref(0)
//
const wasteStatus = ref(props.wasteStatus)
const isActive = ref(false)
watch(

4
src/pages/Index/components/Consumables/Warn/InitWarn.vue

@ -13,7 +13,7 @@
<p v-if="errorTip" class="modal-error">{{ errorTip }}</p>
</div>
<div class="modal-buttons">
<button @click="onCancel" class="cancel-btn">{{ cancelText }}</button>
<button v-if="cancelText" @click="onCancel" class="cancel-btn">{{ cancelText }}</button>
<button @click="onConfirm" class="confirm-btn">
{{ confirmText }}
</button>
@ -39,7 +39,7 @@ const props = defineProps({
cancelText: {
//
type: String,
default: '取消',
default: '',
},
confirmText: {
//

26
src/pages/Index/components/Running/EmergencyResultDialog.vue

@ -9,25 +9,25 @@
<div class="result-dialog-body">
<div class="result-item">
<span class="label">日期</span>
<span class="value">{{ result.date || '无数据' }}</span>
<span class="value">{{ dialogData.date || '无数据' }}</span>
</div>
<div class="result-item">
<span class="label">样本编号</span>
<span class="value">{{ result.sampleBarcode || '无数据' }}</span>
<span class="value">{{ dialogData.sampleBarcode || '无数据' }}</span>
</div>
<div class="result-item">
<span class="label">{{
result.projInfo.projName || '无项目'
dialogData.projInfo.projName || '无项目'
}}</span>
<span class="value">{{ result.value || '无数据' }}</span>
<span class="value">{{ dialogData.value || '无数据' }}</span>
</div>
<ul class="additional-info">
<li>样本种类{{ result.bloodType || '无数据' }}</li>
<li>操次{{ result.operator || '无数据' }}</li>
<li>有效期{{ result.expiryDate || '无数据' }}</li>
<li>操作人{{ result.operator || '无数据' }}</li>
<li>序列号{{ result.serialNumber || '无数据' }}</li>
<li>参考值{{ result.reference || '无数据' }}</li>
<li>样本种类{{ dialogData.bloodType || '无数据' }}</li>
<li>操次{{ dialogData.operator || '无数据' }}</li>
<li>有效期{{ dialogData.expiryDate || '无数据' }}</li>
<li>操作人{{ dialogData.operator || '无数据' }}</li>
<li>序列号{{ dialogData.serialNumber || '无数据' }}</li>
<li>参考值{{ dialogData.reference || '无数据' }}</li>
</ul>
</div>
<div class="result-dialog-footer">
@ -39,7 +39,8 @@
</template>
<script setup lang="ts">
defineProps({
import { ref } from 'vue'
const props = defineProps({
result: {
type: Object,
// required: true,
@ -51,7 +52,8 @@ defineProps({
})
const emits = defineEmits(['update:visible'])
let dialogData = ref()
dialogData.value = props.result;
//
const closeDialog = () => {
emits('update:visible', false)

2
src/pages/Index/components/Running/SampleDisplay.vue

@ -41,7 +41,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import { generateSampleBackground, getBloodTypeLabel } from '../../Utils'
import { generateSampleBackground, getBloodTypeLabel } from '../../utils'
import type { TubeHolderStateMessage } from '../../../../websocket/socket'
defineProps<{
samples: TubeHolderStateMessage['data']['tubes'] //

10
src/router/router.ts

@ -99,8 +99,10 @@ function getCurrentUser() {
return token
}
// 路由守卫,检查本地 Token 是否存在
// 在 router/index.ts 中添加全局路由守卫
// @ts-igmore
router.beforeEach((to, from, next) => {
console.log(from)
console.log('路由守卫--from--', to, from)
const token = sessionStorage.getItem('token')
if (!token && to.path !== '/login') {
next('/login') // 没有 token,重定向到登录页
@ -109,12 +111,8 @@ router.beforeEach((to, from, next) => {
} else {
next() // 通过
}
})
// 在 router/index.ts 中添加全局路由守卫
router.beforeEach((to, from, next) => {
console.log(from)
const user = getCurrentUser() // 获取当前用户
console.log(user)
// 判断目标路由是否需要权限检查
if (to.matched.some((record) => record.meta.requiresAuth)) {
// 如果没有登录,重定向到登录页面

2
src/types/Index/Running.ts

@ -75,7 +75,7 @@ export interface TubeRackInfo {
tubes: TubeInfo[] // 包含的试管信息
state: string // 试管架的总体状态
hasTubeToBeProcessed: boolean // 是否有待处理的试管
}
}
export interface TubeRackResponse {
data: TubeRackInfo // 试管架数据

3
src/types/Index/TestTube.ts

@ -20,7 +20,8 @@ export interface Project {
export interface TestTubeRack {
uuid: string
state: 'INACTIVE' | 'ACTIVE' | 'LOCKED'
tubeSettings: TubeSetting[]
tubeSettings: TubeSetting[],
tubeInfo:{}
}
export interface ApiResponse {

3
src/utils/getServerInfo.ts

@ -1,5 +1,6 @@
export function getServerInfo(wsPath: string = '/api/v1/app/ws/state') {
// 获取当前页面的 URL 对象
// 获取当前页面的 URL 对象
// @ts-ignore
const url = new URL(window.location.href)
// 获取主机名(IP 或域名)和端口号

119
tsconfig.app.tsbuildinfo
File diff suppressed because it is too large
View File

3
tsconfig.json

@ -5,6 +5,7 @@
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"types": ["vue"]
"types": ["vue"],
"noImplicitAny": false // noImplicitAny
}
}

2
tsconfig.node.tsbuildinfo
File diff suppressed because it is too large
View File

Loading…
Cancel
Save