2025-11-11 18:17:47 +08:00

601 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<!-- <el-row :gutter="5" class="compact-form" :span="24"> -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-position="left">
<el-col :span="24" :xs="24">
<el-form-item label="执行时间:" label-width="75px" prop="stime">
<el-date-picker style="width: 130px;" v-model="queryParams.st" type="date" placeholder="起始"
value-format="YYYY-MM-DD" :clearable="false"></el-date-picker>
</el-form-item>
<el-form-item label="--" label-width="30px" prop="etime">
<el-date-picker style="width: 130px;" v-model="queryParams.et" type="date" placeholder="结束"
value-format="YYYY-MM-DD" :clearable="false"></el-date-picker>
</el-form-item>
<el-form-item label="病人代号:" label-width="75px" prop="brdh">
<el-input style="width: 150px;" v-model="queryParams.brdh" placeholder="病人代号" />
</el-form-item>
<el-form-item label="病人姓名:" label-width="75px" prop="brxm">
<el-input style="width: 150px;" v-model="queryParams.brxm" placeholder="病人姓名" />
</el-form-item>
<el-form-item label="状态:" label-width="50px" prop="zt">
<el-select v-model="queryParams.zt" placeholder="状态" clearable style="width: 100px;">
<el-option v-for="(item, index) in ztOptions" :key="index" :label="item.label" :value="item.value"
:disabled="item.disabled"></el-option>
</el-select>
</el-form-item>
<el-form-item label="病人类型:" label-width="75px" prop="brly">
<el-select v-model="queryParams.brly" placeholder="病人类型" clearable style="width: 100px;">
<el-option v-for="(item, index) in pattypeOptions" :key="index" :label="item.label" :value="item.value"
:disabled="item.disabled"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-form>
<!-- </el-row> -->
<el-row :gutter="5" class="mb8 mt10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Search" @click="handleQuery"
v-hasPermi="['system:reqmain:Search']">查询</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Printer" :disabled="single" @click="printAll"
v-hasPermi="['system:reqmain:add']">打印</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Printer" :disabled="freesingle" @click="printSigne"
v-hasPermi="['system:reqmain:edit']">单打条码</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Printer" :disabled="freesingle" @click="printBackpaper"
v-hasPermi="['system:reqmain:edit']">单打回单</el-button>
</el-col>
</el-row>
<el-row :gutter="5" class="table-container">
<el-table ref="tableRef" class="compact-form my-table" :data="reqmainList"
@selection-change="handleSelectionChange" @select="handleSelect" height="100%" :cell-style="tableCellStyle">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="项目名称" align="center" prop="sqxmmc" width="200" show-overflow-tooltip />
<el-table-column label="项目代码" align="center" prop="sqxmdh" width="100" show-overflow-tooltip />
<el-table-column label="项目类别" align="center" prop="cp_xmlb" />
<el-table-column label="样本类型" align="center" prop="yblx" />
<el-table-column label="条码号" align="center" prop="sqh" width="150" show-overflow-tooltip />
<el-table-column label="申请时间" align="center" prop="sqsj" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.sqsj, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="病人姓名" align="center" prop="brxm" show-overflow-tooltip />
<el-table-column label="申请医生" align="center" prop="sqys" :formatter="formatDict('SRD')" show-overflow-tooltip />
<el-table-column label="序号" align="center" prop="xh" show-overflow-tooltip />
<el-table-column label="数量" align="center" prop="sl" show-overflow-tooltip />
<el-table-column label="单价" align="center" prop="dj" show-overflow-tooltip />
<el-table-column label="状态" align="center" prop="zt" show-overflow-tooltip />
<el-table-column label="计价" align="center" prop="jjzt">
<template #default="scope">
<el-checkbox :model-value="scope.row.jjzt === '1'" disabled>
</el-checkbox>
</template>
</el-table-column>
<el-table-column label="病人代号" align="center" prop="brdh" show-overflow-tooltip />
<el-table-column label="执行时间" align="center" prop="zxsj" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.sqsj, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="执行医生" align="center" prop="zxys" :formatter="formatDict('SRD')" show-overflow-tooltip />
<el-table-column label="备注1" align="center" prop="detailBZ1" show-overflow-tooltip />
<el-table-column label="备注2" align="center" prop="detailBZ2" show-overflow-tooltip />
<el-table-column label="颜色" align="center" prop="cp_color" v-if="false" show-overflow-tooltip />
<el-table-column label="确认标识" align="center" prop="cp_cflag" v-if="false" show-overflow-tooltip />
<el-table-column label="科室" align="center" prop="ksdh" :formatter="formatDict('DP')" show-overflow-tooltip />
<el-table-column label="病人类型" align="center" prop="brly" :formatter="formatDict('PT')" show-overflow-tooltip />
<el-table-column label="性别" align="center" prop="brxb" :formatter="formatDict('SX')" show-overflow-tooltip />
<el-table-column label="生日" align="center" prop="brsr" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.brsr, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="床号" align="center" prop="ch" width="50" show-overflow-tooltip />
<el-table-column label="诊断" align="center" prop="zd" width="150" show-overflow-tooltip />
<el-table-column label="条码类别" align="center" prop="bgddh" v-if="false" show-overflow-tooltip />
<el-table-column label="年龄" align="center" prop="nl" show-overflow-tooltip />
<el-table-column label="年龄单位" align="center" prop="nldw" :formatter="formatDict('AU')" show-overflow-tooltip />
<el-table-column label="采样时间" align="center" prop="cysj" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.cysj, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
</el-table>
</el-row>
</div>
</template>
<script setup>
import {
querySQD,
queryPatList,
printBarcode,
printBarcodeall
} from "@/api/mzcx/cydj.js";
const comDict = inject('comDict');
// 字典数据存储
const dictData = ref({});
const tableRef = ref(null);
const { proxy } = getCurrentInstance();
// 选中的行
const selectedRows = ref([]);
const reqmainList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
// 新增:计算属性,返回去重后的ids数组
const idsnew = computed(() => {
return [...new Set(ids.value)];
});
const single = ref(true);
const freesingle = ref(true);
const ztOptions = ref([{ "label": "全部", "value": 0 }, { "label": "未打印", "value": 1 }, { "label": "已打印", "value": 11 }, { "label": "签收", "value": 2 }, { "label": "完成", "value": 4 }, { "label": "剔回", "value": 8 }, { "label": "作废", "value": 9 }])
let pattypeOptions = ref([]);
const data = reactive({
form: {},
queryParams: {
brdh: null,
st: null,
et: null,
stime: null,
etime: null,
brly: null,
zt: 0,
brxm: null
}
});
const { queryParams, form } = toRefs(data);
// 标志位:是否是程序自动勾选(避免循环触发事件)
const isAutoSelect = ref(false);
/**
* 监听单选勾选/取消事件
* @param {Array} selection 目前已选中的行
* @param {Object} row 当前操作的行数据
* @param {Boolean} selected 是否勾选(true=勾选,false=取消)
*/
const handleSelect = (selection, row, selected) => {
if (isAutoSelect.value) return;
const targetSqh = row.sqh;
const targetxh = row.xh;
if (!targetSqh) return;
// 先收集需要自动勾选的行(避免在循环中修改数据)
const rowsToSelect = reqmainList.value.filter(
item => item.sqh === targetSqh && item.xh !== targetxh
);
// 如果有需要自动勾选的行,才开启标志位
if (rowsToSelect.length > 0) {
rowsToSelect.forEach(item => {
tableRef.value.toggleRowSelection(item, selected);
isAutoSelect.value = true;
});
setTimeout(() => isAutoSelect.value = false, 0);
}
};
// 字典格式化方法
const formatDict = (dictType) => {
return (row, column, value) => {
// 从全局字典中获取映射值
return dictData.value[dictType].find(item => String(item.value) === String(value).trim())?.label || value;
};
};
// 定义“空数据”的判断函数
const isEmptyData = (data) => {
// 处理 null/undefined
if (data === null || data === undefined) return true;
// 处理空数组
if (Array.isArray(data) && data.length === 0) return true;
// 处理空对象(无任何属性)
if (typeof data === 'object' && Object.keys(data).length === 0) return true;
// 处理空字符串
if (typeof data === 'string' && data.trim() === '') return true;
return false;
};
/**
* 获取指定天数偏移后的日期时间字符串
* @param {number} days 偏移天数(正数表示未来,负数表示过去)
* @returns {string} 格式化的日期时间字符串 'yyyy-mm-dd HH:MM:SS'
*/
function getDateOffset(days) {
const now = new Date();
const offsetTimestamp = now.getTime() + days * 24 * 60 * 60 * 1000;
const targetDate = new Date(offsetTimestamp);
const year = targetDate.getFullYear();
const month = String(targetDate.getMonth() + 1).padStart(2, '0');
const day = String(targetDate.getDate()).padStart(2, '0');
// const hours = String(targetDate.getHours()).padStart(2, '0');
// const minutes = String(targetDate.getMinutes()).padStart(2, '0');
//const seconds = String(targetDate.getSeconds()).padStart(2, '0');
// return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
return `${year}-${month}-${day}`;
}
function getSubday() {
queryParams.value.stime = `${queryParams.value.st} 00:00:00`
queryParams.value.etime = `${queryParams.value.et} 23:59:59`
}
/** 查询采样登记列表 */
function getList() {
loading.value = true;
getSubday();
querySQD(queryParams.value).then(response => {
if (isEmptyData(response.data)) proxy.$modal.alert("没有检索的数据!");
reqmainList.value = response.data;
// console.log('response:', response.data);
loading.value = false;
single.value = false;
// 新增:数据加载完成后触发全选
// 延迟执行(确保DOM已更新)
setTimeout(() => {
if (tableRef.value) {
tableRef.value.toggleAllSelection(); // 调用全选方法
}
}, 0);
});
}
// 取消按钮
function cancel() {
// open.value = false;
// reset();
}
// 表单重置
function reset() {
form.value = {
sqh: null,
xh: null,
sqxmdh: null,
sqxmmc: null,
sl: null,
dj: null,
detailZT: null,
detailJJZT: null,
ksdh: null,
sqys: null,
sqsj: null,
jsys: null,
jssj: null,
brly: null,
brdh: null,
brxm: null,
zt: null,
jjzt: null,
brxb: null,
brsr: null,
jzbz: null,
cp_xmlb: null,
cp_color: null,
cp_cflag: null,
detailBZ1: null,
ch: null,
detailBZ2: null,
bz1: null,
bz2: null,
bz3: null,
yblx: null,
zxys: null,
zxsj: null,
bgddh: null,
nl: null,
nldw: null,
zd: null,
cysj: null
};
freesingle.value = false;
single.value = false;
proxy.resetForm("reqmainRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
function readCard() {
//getList();
}
// 处理病人选择事件
const handlePatientSelect = (patient) => {
// console.log('选中的病人:', patient);
queryParams.value.brdh = patient
// 处理选中的病人数据
handleQuery();
};
// 多选框选中数据
function handleSelectionChange(selection) {
if (isAutoSelect.value) return;
selectedRows.value = selection;
ids.value = selection.map(item => item.sqh);
}
/** 打印选择 */
function printAll(row) {
console.log('idsnew:', idsnew.value);
if (idsnew.value.length === 0) {
return;
}
printBarcodeall(idsnew.value).then(response => {
proxy.$modal.msgSuccess("打印成功");
open.value = false;
freesingle.value = false;
}).catch(() => {
});
}
/** 单打条码*/
function printSigne(row) {
if (idsnew.value.length === 0) {
return;
}
apiprintAll(idsnew.value).then(response => {
proxy.$modal.msgSuccess("打印成功");
open.value = false;
freesingle.value = false;
}).catch(() => {
});
}
/** 打印回单 */
function printBackpaper(row) {
if (idsnew.value.length === 0) {
return;
}
apiprintAll(idsnew.value).then(response => {
proxy.$modal.msgSuccess("打印成功");
open.value = false;
}).catch(() => {
});
}
const totalRows = computed(() => {
return reqmainList.value.length || 0;
});
const totalPrice = computed(() => {
return reqmainList.value.reduce((sum, row) => {
const price = parseFloat(row.dj) || 0;
return sum + price;
}, 0);
});
// 组件挂载时加载字典
onMounted(async () => {
// 加载病人来源字典
const dictRefs = await comDict('PT', 'DP', 'SRD', 'BT', 'SX', 'AU');
// 从 ref 中获取实际数据
dictData.value = {
PT: toRaw(dictRefs.PT.value) || [],
DP: toRaw(dictRefs.DP.value) || [],
SRD: toRaw(dictRefs.SRD.value) || [],
BT: toRaw(dictRefs.BT.value) || [],
SX: toRaw(dictRefs.SX.value) || [],
AU: toRaw(dictRefs.AU.value) || []
};
pattypeOptions = dictData.value.PT;
queryParams.value.brly = "1";
queryParams.value.st = getDateOffset(0);
queryParams.value.et = getDateOffset(0);
});
// 表格单元格样式(仅作用于“项目类别”列)
const tableCellStyle = ({ row, column }) => {
// 只对“项目类别”列生效
if (column.label === '项目类别') {
// 1. 转换颜色(十进制→十六进制)
const bgColor = decimalToHexColor(row.cp_color);
// 2. 自动计算文字颜色(确保和背景色对比度足够)
const textColor = getContrastTextColor(bgColor);
return {
backgroundColor: bgColor, // 背景色(转换后的值)
color: textColor, // 文字色(自动适配)
textAlign: 'center', // 文字居中
fontWeight: '500' // 文字加粗(提升可读性)
};
}
return {}; // 其他列保持默认样式
};
// 十进制颜色值转十六进制颜色码(适配BGR转RGB)
const decimalToHexColor = (decimal) => {
if (!decimal && decimal !== 0) return '#FFFFFF'; // 空值默认白色
// 1. 十进制转十六进制(去除前缀0x,大写)
let hex = parseInt(decimal, 10).toString(16).toUpperCase();
// 2. 不足6位则前面补0(确保是6位)
if (hex.length < 6) {
hex = hex.padStart(6, '0'); // 例如:192→"C0"→补0为"0000C0"
}
// 3. BGR转RGB(反转字节顺序:前两位和后两位交换)
// 例:80FFFF → 拆分为80、FF、FF → 反转后FF、FF、80 → FFFF80
const r = hex.substring(4, 6); // 取后两位
const g = hex.substring(2, 4); // 取中间两位
const b = hex.substring(0, 2); // 取前两位
const rgbHex = r + g + b;
return `#${rgbHex}`; // 最终颜色码
};
// 辅助函数:根据背景色计算文字颜色(黑/白)
const getContrastTextColor = (bgColor) => {
// 提取RGB值(如#FFFF80 → R=255, G=255, B=128)
const r = parseInt(bgColor.slice(1, 3), 16);
const g = parseInt(bgColor.slice(3, 5), 16);
const b = parseInt(bgColor.slice(5, 7), 16);
// 计算亮度(标准公式)
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
// 亮度>0.5用黑色,否则用白色(确保清晰)
return luminance > 0.5 ? '#333333' : '#FFFFFF';
};
</script>
<style scoped lang="scss">
.app-container {
display: flex;
flex-direction: column;
height: 90vh;
/* 容器高度等于窗口高度 */
overflow: hidden;
}
.compact-form {
height: 40px;
/* 固定高度 */
}
.mb8 {
height: 30px;
/* 固定高度 */
}
.table-container {
flex: 1;
/* 占满剩余高度 */
overflow: hidden;
/* 避免表格超出容器 */
}
.compact-form .el-form-item {
padding: 5px;
margin-bottom: 5px;
}
.compact-form .el-form-item__label {
padding-bottom: 0px;
}
:deep(.my-table .el-table__row td) {
padding: 1px 0;
/* 减小行高 */
}
:deep(.my-table .el-table__header-wrapper th) {
padding: 6px 0;
/* 表头内边距 */
background-color: #b3d8ff !important;
/* 表头背景色(保留之前的设置) */
color: #333;
/* 文字颜色加深,提升可读性 */
font-weight: 500;
/* 文字加粗 */
}
:deep(.my-table .el-table__cell) {
padding: 0 2px;
/* 减小列间距 */
}
/* 可选:调整表格整体样式 */
:deep(.my-table) {
font-size: 13px;
/* 适当减小字体 */
}
:deep(.my-table .el-table__cell),
:deep(.my-table .el-table__header-wrapper th) {
border-width: 1px;
border-color: #ebeef5;
}
.card-content {
max-height: 450px;
/* 设置最大高度 */
overflow-y: auto;
/* 超出高度时显示垂直滚动条 */
padding: 5px;
/* 保持与卡片默认一致的内边距 */
}
.clickable:hover {
cursor: pointer;
/* 鼠标悬停时显示手型 */
transition: all 0.3s;
/* 平滑过渡效果 */
color: blue;
}
/* 消除inline表单中表单项的右侧间距(主要间距来源) */
/* 消除表单项之间的间距 */
:deep(.el-form--inline .el-form-item) {
margin-right: 0 !important;
margin-bottom: 0 !important;
}
/* 缩小标签与输入框的间距 */
:deep(.el-form-item__label) {
padding-right: 8px !important;
}
/* 表单项之间添加微小间隙(避免完全贴靠) */
:deep(.el-form-item) {
margin-left: 5px !important;
}
/* 汇总行样式 */
.table-summary {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 6px 16px;
margin-top: 8px;
background-color: #f5f7fa;
border: 1px solid #ebeef5;
border-radius: 4px;
font-weight: 500;
line-height: 24px;
/* 汇总行文字行高 */
.summary-item {
display: flex;
align-items: center;
margin-left: 24px;
.summary-label {
color: #606266;
margin-right: 8px;
}
.summary-value {
color: #303133;
min-width: 40px;
text-align: left;
/* 核心:数值左对齐 */
}
/* 单独设置"单价合计"的值为红色 */
&:nth-child(3) .summary-value {
color: #f56c6c;
/* Element UI 红色主题色 */
font-weight: 600;
/* 可选:加粗字体 */
}
}
}
</style>