采样、送检登记

This commit is contained in:
wyuu 2025-08-29 17:40:32 +08:00
parent 17bd08bea0
commit ef2856f0ff
4 changed files with 217 additions and 79 deletions

View File

@ -26,4 +26,20 @@ export function fetchCodeDetail(query?: Object) {
method: 'get', method: 'get',
params: query, params: query,
}); });
}
// 执行条码
export function fetchCodeExec(query?: Object) {
return request({
url: '/zyreq/exec',
method: 'get',
params: query,
});
}
// 获取申请单主表信息
export function fetchCodeReqmain(query?: Object) {
return request({
url: 'zyreq/reqmain',
method: 'get',
params: query,
});
} }

View File

@ -1,11 +1,21 @@
import axios from 'axios' import axios from 'axios'
import { ElLoading, ElMessage } from 'element-plus' import {
import { saveAs } from 'file-saver' ElLoading,
import { getToken } from '@/utils/auth' ElMessage
} from 'element-plus'
import {
saveAs
} from 'file-saver'
import {
getToken
} from '@/utils/auth'
import errorCode from '@/utils/errorCode' import errorCode from '@/utils/errorCode'
import { blobValidate } from '@/utils/ruoyi' import {
blobValidate
} from '@/utils/ruoyi'
const baseURL = import.meta.env.VITE_APP_BASE_API const baseURL =
import.meta.env.VITE_APP_BASE_API
let downloadLoadingInstance; let downloadLoadingInstance;
export default { export default {
@ -15,7 +25,14 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: {
'Authorization': 'Bearer ' + getToken()
},
onDownloadProgress: (progressEvent) => {
console.log(progressEvent)
//progressEvent.loaded 下载文件的当前大小
//progressEvent.total 下载文件的总大小 如果后端没有返回 请让他加上
}
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data); const isBlob = blobValidate(res.data);
if (isBlob) { if (isBlob) {
@ -32,7 +49,9 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: {
'Authorization': 'Bearer ' + getToken()
}
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data); const isBlob = blobValidate(res.data);
if (isBlob) { if (isBlob) {
@ -45,16 +64,23 @@ export default {
}, },
zip(url, name) { zip(url, name) {
var url = baseURL + url var url = baseURL + url
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", }) downloadLoadingInstance = ElLoading.service({
text: "正在下载数据,请稍候",
background: "rgba(0, 0, 0, 0.7)",
})
axios({ axios({
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() } headers: {
'Authorization': 'Bearer ' + getToken()
}
}).then((res) => { }).then((res) => {
const isBlob = blobValidate(res.data); const isBlob = blobValidate(res.data);
if (isBlob) { if (isBlob) {
const blob = new Blob([res.data], { type: 'application/zip' }) const blob = new Blob([res.data], {
type: 'application/zip'
})
this.saveAs(blob, name) this.saveAs(blob, name)
} else { } else {
this.printErrMsg(res.data); this.printErrMsg(res.data);
@ -75,5 +101,4 @@ export default {
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
ElMessage.error(errMsg); ElMessage.error(errMsg);
} }
} }

View File

@ -2,7 +2,9 @@
import { io, Socket } from "socket.io-client"; import { io, Socket } from "socket.io-client";
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { usePrintStore } from '@/store/modules/printStore' import { usePrintStore } from '@/store/modules/printStore'
import { onUnmounted } from "vue"
// @ts-ignore
import Download from '@/plugins/download';
// ... 类型定义 ... // ... 类型定义 ...
type PrinterInfo = { type PrinterInfo = {
name: string; name: string;
@ -61,7 +63,7 @@ function initSocket(onPrinterUpdate?: OnPrinterUpdate) {
socket.on("connect_error", (err: Error) => { socket.on("connect_error", (err: Error) => {
console.log('连接错误', err); console.log('连接错误', err);
ElMessageBox.alert( ElMessageBox.alert(
`连接失败!<br>请确保目标服务器已<a style="color: #1f79db" href="https://gitee.com/CcSimple/electron-hiprint/releases" target="_blank"> 下载 </a> 并运行 打印服务!`, `连接失败!<br>请确保目标服务器已<a style="color: #1f79db" onclick="downExe()"> 下载 </a> 并运行 打印服务!`,
"客户端未连接", "客户端未连接",
{ {
dangerouslyUseHTMLString: true, dangerouslyUseHTMLString: true,
@ -70,8 +72,19 @@ function initSocket(onPrinterUpdate?: OnPrinterUpdate) {
printStore.setConnected(false); printStore.setConnected(false);
socket?.close(); socket?.close();
}); });
} }
const downExe = () => {
// 下载逻辑实现
console.log('开始下载打印服务');
Download.name('hiprint_win_x64-1.0.13.exe')
};
// 挂载到window,使其能被全局访问
(window as any).downExe = downExe
function silentPrintPdf(url: string, printOptions?: object) { function silentPrintPdf(url: string, printOptions?: object) {
const printStore = usePrintStore(); const printStore = usePrintStore();
if (!url) { if (!url) {
@ -143,4 +156,10 @@ export const HiprintPrinter = {
const printStore = usePrintStore(); const printStore = usePrintStore();
return printStore.defaultPrinter; return printStore.defaultPrinter;
}, },
}; };
onUnmounted(() => {
if ('downExe' in window) {
delete (window as any).downExe;
}
});

View File

@ -4,7 +4,7 @@
<el-row :gutter="10" class="compact-form" v-show="showSearch"> <el-row :gutter="10" class="compact-form" v-show="showSearch">
<el-form :model="queryParams" ref="queryRef" :inline="true" :rules="queryRules"> <el-form :model="queryParams" ref="queryRef" :inline="true" :rules="queryRules">
<el-form-item label="日期:" prop="failed1"> <el-form-item label="日期:" prop="failed1">
<el-date-picker v-model="queryParams.failed1" type="datetimerange" range-separator="-" <el-date-picker v-model="queryParams.times" type="datetimerange" range-separator="-"
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" @change="handletime" /> value-format="YYYY-MM-DD HH:mm:ss" @change="handletime" />
</el-form-item> </el-form-item>
@ -15,12 +15,12 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="条码状态:" prop="zt"> <el-form-item label="条码状态:" prop="zt">
<el-select v-model="queryParams.zt" placeholder="请选择" style="width: 120px;"> <el-select v-model="queryParams.zt" placeholder="请选择" style="width: 100px;">
<el-option v-for="item in dictData.ST" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in dictData.ST" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="" prop="failed4"> <el-form-item label="" prop="failed4">
<el-select v-model="queryParams.failed4" placeholder="请选择" style="width:120px"> <el-select v-model="queryParams.failed4" placeholder="请选择" style="width:140px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -54,10 +54,10 @@
<el-button type="success" plain @click="printHandle1">打印</el-button> <el-button type="success" plain @click="printHandle1">打印</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="info" plain icon="Upload" @click="openBlock">采样登记</el-button> <el-button type="info" plain icon="Upload" @click="openBlock('采样登记')">采样登记</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain @click="openSj">送检登记</el-button> <el-button type="warning" plain @click="openBlock('送检登记')">送检登记</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="warning" plain @click="goReport">报告查询</el-button> <el-button type="warning" plain @click="goReport">报告查询</el-button>
@ -76,7 +76,7 @@
</el-row> </el-row>
<CustomTable :data="tableData" :columns="columns" :config="tableConfig" :loading="loading" <CustomTable :data="tableData" :columns="columns" :config="tableConfig" :loading="loading"
@row-click="rowHandle"> @row-click="rowHandle" @selection-change="selectionChange">
<template #jzbz="{ row }"> <template #jzbz="{ row }">
{{ row.jzbz == '1' ? '急诊' : '非急诊' }} {{ row.jzbz == '1' ? '急诊' : '非急诊' }}
</template> </template>
@ -87,7 +87,7 @@
{{ formatDict(row.brly, 'PT') }} {{ formatDict(row.brly, 'PT') }}
</template> </template>
<template #zt="{ row }"> <template #zt="{ row }">
{{ formatDict(row.zt, 'ST') }} {{ formatDict(row.zt.trim(), 'ST') }}
</template> </template>
<template #yljg="{ row }"> <template #yljg="{ row }">
{{ formatDict(row.yljg, 'HOS') }} {{ formatDict(row.yljg, 'HOS') }}
@ -111,15 +111,15 @@
<!-- 采样登记 --> <!-- 采样登记 -->
<el-dialog v-model="dialogVisible" title="采样登记" draggable :close-on-click-modal="false"> <el-dialog v-model="dialogVisible" :title="title" draggable :close-on-click-modal="false" width="70vw"
@close="closeDialog">
<div class="flex-between"> <div class="flex-between">
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-input v-model="queryParams.failed5" clearable placeholder="条形码" @keyup.enter="handleQuery" <el-input v-model="sqhText" clearable placeholder="条形码" @keyup.enter="sqdQuery" @clear="sqdQuery" />
@clear="handleQuery" />
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain>读取</el-button> <el-button type="primary" @click="sqdQuery" plain>读取</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" plain icon="delete">删除选中行</el-button> <el-button type="danger" plain icon="delete">删除选中行</el-button>
@ -128,35 +128,13 @@
<el-button type="info" plain>打印</el-button> <el-button type="info" plain>打印</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-button type="primary" plain>保存</el-button> <!-- <el-button type="primary" plain>保存</el-button> -->
</div> </div>
<CustomTable :data="rightTableData" :columns="rightColumns" :config="rightTableConfig"> <CustomTable :data="cyTableData" :columns="cyColumns" :config="cyTableConfig">
<template #zt="{ row }">
{{ formatDict(row.zt, 'ST') }}
</template>
</CustomTable> </CustomTable>
</el-dialog>
<!-- 送检登记 -->
<el-dialog v-model="dialogSjVisible" title="送检登记" draggable :close-on-click-modal="false">
<div class="flex-between">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-input v-model="queryParams.failed5" clearable placeholder="条形码" @keyup.enter="handleQuery"
@clear="handleQuery" />
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain>读取</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="delete">删除选中行</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain>打印</el-button>
</el-col>
</el-row>
<el-button type="primary" plain>保存</el-button>
</div>
<CustomTable :data="rightTableData" :columns="rightColumns" :config="rightTableConfig">
</CustomTable>
</el-dialog> </el-dialog>
</div> </div>
@ -169,8 +147,9 @@ import { classCom } from '@/utils/classCom';
import CustomTable from '@/components/tableCom/index.vue' import CustomTable from '@/components/tableCom/index.vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { usePrintStore } from '@/store/modules/printStore' import { usePrintStore } from '@/store/modules/printStore'
import { fetchCodeList, addObj, fetchCodeDetail } from '@/api/checkCode/index' import { fetchCodeList, addObj, fetchCodeDetail, fetchCodeExec, fetchCodeReqmain } from '@/api/checkCode/index'
import { TableColumnCtx } from 'element-plus'; import { TableColumnCtx } from 'element-plus';
import dayjs from 'dayjs';
//@ts-ignore //@ts-ignore
import { comDict } from '@/utils/dict' import { comDict } from '@/utils/dict'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
@ -179,17 +158,20 @@ const printStore = usePrintStore();
const compactForm = ref<HTMLElement | null>(null); const compactForm = ref<HTMLElement | null>(null);
const heightForm = ref(90); const heightForm = ref(90);
const dialogVisible = ref(false) const dialogVisible = ref(false)
const openBlock = () => { const title = ref('采样登记')
dialogVisible.value = true const sqhText = ref('')
}
const dialogSjVisible = ref(false) interface QueryParams {
const openSj = () => { times: string[]; // 明确类型为字符串元组
dialogSjVisible.value = true yljg: string;
zt: string;
failed4: string;
failed5: string;
} }
// 提交表单数据 // 提交表单数据
const queryParams = reactive({ const queryParams = reactive<QueryParams>({
failed1: ['2025-07-18 00:00:00', '2025-07-18 23:59:59'], times: ['2025-07-18 00:00:00', '2025-07-18 23:59:59'],
// times: [],
yljg: '1', yljg: '1',
zt: '', zt: '',
failed4: '', failed4: '',
@ -210,14 +192,17 @@ const queryRules = ref({
}) })
const options = [ const options = [
{ {
value: 'Option1', value: '1',
label: 'Option1', label: '通过姓名搜索',
}, },
{ {
value: 'Option2', value: '2',
label: 'Option2', label: '通过病人号搜索',
},
{
value: '3',
label: '通过床号搜索',
}, },
] ]
interface DictData { interface DictData {
SX?: Array<any>; SX?: Array<any>;
@ -267,6 +252,9 @@ const columns = ref([
{ prop: 'yljg', label: '医疗机构', align: 'center', visible: true, slot: 'yljg', key: 18, width: '170px' }, { prop: 'yljg', label: '医疗机构', align: 'center', visible: true, slot: 'yljg', key: 18, width: '170px' },
]) ])
const single = ref(true);
const multiple = ref(true);
const sqhs = ref([]);
// 单元格样式 // 单元格样式
const cellStyleHd = ({ row, column, rowIndex, columnIndex }: { const cellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any; row: any;
@ -298,11 +286,15 @@ const rowClassNameHd = ({ row, rowIndex }: {
}; };
// 点击行 // 点击行
const rowHandle = (row: any, column: TableColumnCtx<any>, event: Event) => { const rowHandle = (row: any, column: TableColumnCtx<any>, event: Event) => {
console.log(row);
getRightTable(row) getRightTable(row)
}; };
const selectionChange = (selection: any) => {
sqhs.value = selection;
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 左侧表格配置 // 左侧表格配置
const tableConfig = ref({ const tableConfig = ref({
// stripe: true, // 斑马纹 // stripe: true, // 斑马纹
@ -337,6 +329,84 @@ const rightTableConfig = ref({
highlightCurrentRow: true, // 高亮当前行 highlightCurrentRow: true, // 高亮当前行
}) })
// 采样数据源
const cyTableData = ref([])
// 配置项
const cyColumns = ref([
{ prop: 'sqh', label: '申请号/条形码', visible: true, key: 0, sortable: true, width: '140px' },
{ prop: 'ksdh', label: '科室病区', visible: true, key: 1, width: '120px' },
{ prop: 'ch', label: '床号', visible: true, key: 2, sortable: true, },
{ prop: 'brxm', label: '姓名', visible: true, key: 3, },
{ prop: 'brdh', label: '病人号', visible: true, key: 4, },
{ prop: 'brxb', label: '性别', align: 'center', visible: true, key: 5, },
{ prop: 'yblx', label: '样本类型', align: 'center', visible: true, key: 6 },
{ prop: 'zt', label: '状态', align: 'center', visible: true, slot: 'zt', key: 7 },
{ prop: 'jzbz', label: '急诊', align: 'center', visible: true, key: 8 },
{ prop: 'jjzt', label: '采样人', align: 'center', visible: true, key: 8 },
{ prop: 'cysj', label: '采样时间', align: 'center', visible: true, key: 8 },
{ prop: 'zxysname', label: '执行医生', align: 'center', visible: true, key: 8 },
{ prop: 'zxsj', label: '执行时间', align: 'center', visible: true, key: 8 },
])
// 表格配置
const cyTableConfig = ref({
// stripe: true, // 斑马纹
border: false, // 边框
selection: true, // 多选框
index: false, // 序号
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
})
// 采样登记
const openBlock = async (value: string) => {
if (sqhs.value.length > 0) {
try {
// 生成请求Promise数组
const requests = sqhs.value.map((item: any) => fetchCodeExec({
sqh: item.sqh,
userid: 'lis',
status: 12,
yljg: 1
}));
const results = await Promise.all(requests);
console.log('所有请求成功:', results);
return results;
} catch (error: any) {
console.error('至少一个请求失败:', error.message);
throw error;
}
} else {
title.value = value
dialogVisible.value = true
}
}
// 采样读取
const sqdQuery = () => {
const index = cyTableData.value.findIndex((item: any) => item.sqh == sqhText.value)
if (index !== -1) return ElMessage.warning('该申请单数据已存在!')
fetchCodeReqmain({ sqh: sqhText.value }).then((res: any) => {
if (res.code == 0 && res.data.sqh) {
fetchCodeExec({
sqh: res.data.sqh,
userid: 'lis',
status: 12,
yljg: 1
})
cyTableData.value = cyTableData.value.concat(res.data)
}
})
}
// 关闭弹窗清空
const closeDialog = () => {
cyTableData.value = []
sqhText.value = ''
}
interface ColumnItem { interface ColumnItem {
prop: string; prop: string;
label: string; label: string;
@ -367,8 +437,13 @@ const goReport = () => {
}; };
onMounted(async () => { onMounted(async () => {
adjustTableHeight(); // 初始化3天区间(今天-前两天)
// const end = dayjs().format('YYYY-MM-DD HH:mm:ss');
// const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD HH:mm:ss'); //add 时间往后
// queryParams.times = [start, end];
// console.log(queryParams.times);
getList() getList()
adjustTableHeight();
// 加载病人来源字典 // 加载病人来源字典
const dictRefs = await comDict('PT', 'HOS', 'ST'); const dictRefs = await comDict('PT', 'HOS', 'ST');
@ -378,11 +453,13 @@ onMounted(async () => {
HOS: toRaw(dictRefs.HOS.value) || [], HOS: toRaw(dictRefs.HOS.value) || [],
ST: toRaw(dictRefs.ST.value) || [], ST: toRaw(dictRefs.ST.value) || [],
}; };
}); });
// 字典格式化方法 // 字典格式化方法
const formatDict = (v: string, dictType: string) => { const formatDict = (v: string, dictType: string) => {
// 从全局字典中获取映射值
return dictData.value[dictType]?.find((item: any) => item.value == v)?.label; return dictData.value[dictType]?.find((item: any) => item.value == v)?.label;
}; };
@ -397,14 +474,13 @@ function adjustTableHeight() {
if (compactForm.value) { if (compactForm.value) {
// 获取高度 // 获取高度
heightForm.value = compactForm.value.offsetHeight; heightForm.value = compactForm.value.offsetHeight;
tableConfig.value.height = `calc(75vh - ${heightForm.value}px)`; // 设置表格容器的高度 tableConfig.value.height = `calc(72vh - ${heightForm.value}px)`; // 设置表格容器的高度
rightTableConfig.value.height = `calc(79vh - ${heightForm.value}px)`; rightTableConfig.value.height = `calc(76vh - ${heightForm.value}px)`;
} }
} }
const handletime = (val: Array<string>) => { const handletime = (val: Array<string>) => {
console.log(val); console.log('时间', val);
} }
// 生成条码 // 生成条码
@ -412,8 +488,8 @@ const printHandle = () => {
const data = { const data = {
dept: '0235', dept: '0235',
userid: 'lis', userid: 'lis',
st: queryParams.failed1[0], st: queryParams.times[0],
et: queryParams.failed1[1], et: queryParams.times[1],
yljg: queryParams.yljg yljg: queryParams.yljg
} }
addObj(data).then((res: any) => { addObj(data).then((res: any) => {
@ -430,8 +506,8 @@ const getList = () => {
const data = { const data = {
dept: '0235', dept: '0235',
userid: 'lis', userid: 'lis',
st: queryParams.failed1[0], st: queryParams.times[0],
et: queryParams.failed1[1], et: queryParams.times[1],
yljg: queryParams.yljg yljg: queryParams.yljg
} }
fetchCodeList(data).then((response: any) => { fetchCodeList(data).then((response: any) => {
@ -444,6 +520,7 @@ const getList = () => {
} }
const printHandle1 = () => { const printHandle1 = () => {
const url = 'http://47.97.125.165:8904/lis.pdf' const url = 'http://47.97.125.165:8904/lis.pdf'
// const url = sqhs.value[0]?.pdfUrl
HiprintPrinter.silentPrintPdf( HiprintPrinter.silentPrintPdf(
url, url,
{ {
@ -451,6 +528,7 @@ const printHandle1 = () => {
orientation: "portrait", // 纵向(landscape=横向) orientation: "portrait", // 纵向(landscape=横向)
copies: 1, copies: 1,
monochrome: false, // 是否黑白打印 monochrome: false, // 是否黑白打印
// paperName: 'A4', // 纸张大小 A2, A3, A4, A5, A6, letter, legal, tabloid, statement
}, },
); );