Compare commits

..

No commits in common. "f69122ff6d68674edcc2d2baf96c8bfc9df8179c" and "5a3fb07f49a2680e2bf1a634e0b395e1617fd750" have entirely different histories.

7 changed files with 12 additions and 908 deletions

11
src/env.d.ts vendored
View File

@ -1,14 +1,3 @@
import type { HTMLAttributes } from 'vue'
declare global {
namespace JSX {
interface IntrinsicElements {
[elemName: string]: HTMLAttributes
}
}
}
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>

View File

@ -32,16 +32,6 @@ export default {
console.log(progressEvent)
//progressEvent.loaded 下载文件的当前大小
//progressEvent.total 下载文件的总大小 如果后端没有返回 请让他加上
let progressPercent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
let loading = ElLoading.service({
lock: true,
text: `下载中,请稍候${progressPercent}%`,
background: 'rgba(0, 0, 0, 0.7)',
})
loading.setText(`下载中,请稍候${progressPercent}%`)
if (progressPercent == 100) {
loading.close()
}
}
}).then((res) => {
const isBlob = blobValidate(res.data);

View File

@ -63,7 +63,7 @@ function initSocket(onPrinterUpdate?: OnPrinterUpdate) {
socket.on("connect_error", (err: Error) => {
console.log('连接错误', err);
ElMessageBox.alert(
`连接失败!<br>请确保目标服务器已<a style="color: #1f79db" onclick="downExe()">下载安装</a> 并<a style="color: #1f79db" onclick="yxHiprint()"> 运行 </a> 打印服务!`,
`连接失败!<br>请确保目标服务器已<a style="color: #1f79db" onclick="downExe()"> 下载 </a> 并运行 打印服务!`,
"客户端未连接",
{
dangerouslyUseHTMLString: true,
@ -79,17 +79,12 @@ function initSocket(onPrinterUpdate?: OnPrinterUpdate) {
const downExe = () => {
// 下载逻辑实现
// console.log('开始下载打印服务');
Download.name('hiprint_win_x64-1.0.13.exe', false)
};
const yxHiprint = () => {
// 唤起客户端
window.open("hiprint://");
console.log('开始下载打印服务');
Download.name('hiprint_win_x64-1.0.13.exe')
};
// 挂载到window,使其能被全局访问
(window as any).downExe = downExe;
(window as any).yxHiprint = yxHiprint;
(window as any).downExe = downExe
function silentPrintPdf(url: string, printOptions?: object) {
const printStore = usePrintStore();
if (!url) {

View File

@ -93,9 +93,9 @@
<div class="title">检验结果</div>
<div class="mb10">
<el-button type="primary" @click="openDB">对比历史</el-button>
<el-button type="primary" @click="copyData('All')">复制全部数据</el-button>
<el-button type="primary" @click="copyData('N')">复制异常数据</el-button>
<el-button type="primary" @click="copyData('Y')">复制正常数据</el-button>
<el-button type="primary">复制全部数据</el-button>
<el-button type="primary">复制异常数据</el-button>
<el-button type="primary">复制正常数据</el-button>
<el-button type="primary">知识库</el-button>
</div>
@ -351,6 +351,7 @@ const rightColumns = ref([
{ prop: 'refs', label: '参考值', align: 'center', visible: true, key: 3 },
{ prop: 'dw', label: '单位', align: 'center', visible: true, key: 4 },
{ prop: 'jgbz', label: '结果标志', align: 'center', visible: true, key: 5 },
])
// 表格配置
const rightTableConfig = ref(
@ -385,9 +386,7 @@ const periods = ref<string[]>([])
const compareTableData = ref([])
const aaaa = () => {
}
// 历史数据对比
const openDB = () => {
// 00507620
@ -420,49 +419,6 @@ const openDB = () => {
})
}
interface copyItem {
xmdh: string;
xmmc: string;
csjg: string | number;
refs: string | number;
dw: string;
jgbz: string;
}
// 复制函数
const copyData = (type: string) => {
let str = ''
const getCommonRow = (item: copyItem) => `${item.xmdh}\t${item.xmmc}\t${item.csjg}\t${item.refs}\t${item.dw}\t${item.jgbz}\t\r\n`;
rightTableData.value.forEach((v: any) => {
if (type == 'All') {
str = str + getCommonRow(v)
str = str + v.xmmc + v.csjg + v.dw + + ',';
}
if (type == 'N' && v.jgbz != 'M' && v.jgbz != '') {
str = str + getCommonRow(v)
}
if (type == 'Y' && v.jgbz == 'M' && v.jgbz != '') {
str = str + getCommonRow(v)
}
})
var input = document.createElement('textarea');
if (!str) return ElMessage.error('没有数据可复制');
// 把文字放进input中,供复制
input.value = str;
document.body.appendChild(input);
// 选中创建的input
input.select();
var copy_result = document.execCommand('copy');
if (copy_result) {
ElMessage.success('复制成功');
} else {
ElMessage.error('复制失败');
}
// 移除
document.body.removeChild(input);
}
// 数据重组
const formatGroupedData = (data: any[]) => {
if (!data || data.length === 0) return [];
@ -536,6 +492,7 @@ const getEcharts = (data: any) => {
axisLabel: {
rotate: 30,
textStyle: {
color: "#8D949B "
}
},

View File

@ -1,296 +0,0 @@
<template>
<div class="editable-table-container">
<el-table :data="tableData" border style="width: 100%" @cell-click="handleCellClick"
:cell-class-name="cellClassName">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="name" label="姓名" width="120">
<template #default="scope">
<template v-if="isEditing(scope.row, scope.column)">
<el-input v-model="scope.row.name" size="small" @blur="handleSave(scope.row, scope.column)"
@keyup.enter="handleSave(scope.row, scope.column)" ref="editInput" auto-focus />
</template>
<template v-else>
<span>{{ scope.row.name }}</span>
</template>
</template>
</el-table-column>
<el-table-column prop="age" label="年龄" width="100" align="center">
<template #default="scope">
<template v-if="isEditing(scope.row, scope.column)">
<el-input-number v-model="scope.row.age" :min="0" :max="150" size="small"
@blur="handleSave(scope.row, scope.column)" @keyup.enter="handleSave(scope.row, scope.column)"
ref="editInput" auto-focus />
</template>
<template v-else>
<span>{{ scope.row.age }}</span>
</template>
</template>
</el-table-column>
<el-table-column prop="email" label="邮箱">
<template #default="scope">
<template v-if="isEditing(scope.row, scope.column)">
<el-input v-model="scope.row.email" size="small" @blur="handleSave(scope.row, scope.column)"
@keyup.enter="handleSave(scope.row, scope.column)" ref="editInput" auto-focus />
</template>
<template v-else>
<span>{{ scope.row.email }}</span>
</template>
</template>
</el-table-column>
<el-table-column prop="department" label="部门" width="150">
<template #default="scope">
<template v-if="isEditing(scope.row, scope.column)">
<el-select v-model="scope.row.department" size="small" @change="handleSave(scope.row, scope.column)"
@blur="handleSave(scope.row, scope.column)" ref="editSelect" auto-focus>
<el-option v-for="dept in departments" :key="dept.value" :label="dept.label" :value="dept.value" />
</el-select>
</template>
<template v-else>
<span>{{ getDepartmentLabel(scope.row.department) }}</span>
</template>
</template>
</el-table-column>
<el-table-column prop="joinDate" label="入职日期" width="140">
<template #default="scope">
<template v-if="isEditing(scope.row, scope.column)">
<el-date-picker v-model="scope.row.joinDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
size="small" @blur="handleSave(scope.row, scope.column)" @change="handleSave(scope.row, scope.column)"
ref="editDate" auto-focus />
</template>
<template v-else>
<span>{{ scope.row.joinDate }}</span>
</template>
</template>
</el-table-column>
</el-table>
<div class="table-info">
<p>点击任意单元格即可直接编辑该单元格内容</p>
<p>编辑完成后可按Enter键或点击其他区域保存修改</p>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue';
import { ElMessage } from 'element-plus';
// 部门选项
const departments = [
{ label: '技术部', value: 'tech' },
{ label: '市场部', value: 'marketing' },
{ label: '销售部', value: 'sales' },
{ label: '人力资源', value: 'hr' },
{ label: '财务部', value: 'finance' }
];
// 表格数据
const tableData = reactive([
{
id: 1,
name: '张三',
age: 28,
email: 'zhangsan@example.com',
department: 'tech',
joinDate: '2020-03-15',
originalData: {} // 用于保存原始数据
},
{
id: 2,
name: '李四',
age: 32,
email: 'lisi@example.com',
department: 'marketing',
joinDate: '2019-07-22',
originalData: {}
},
{
id: 3,
name: '王五',
age: 45,
email: 'wangwu@example.com',
department: 'sales',
joinDate: '2018-11-05',
originalData: {}
},
{
id: 4,
name: '赵六',
age: 23,
email: 'zhaoliu@example.com',
department: 'hr',
joinDate: '2021-02-18',
originalData: {}
}
]);
// 当前编辑的单元格信息
const editingCell = ref({
row: null,
column: null
});
// 判断单元格是否处于编辑状态
const isEditing = (row, column) => {
return editingCell.value.row === row && editingCell.value.column === column;
};
// 获取部门显示名称
const getDepartmentLabel = (value) => {
const dept = departments.find(item => item.value === value);
return dept ? dept.label : '';
};
// 处理单元格点击事件 - 进入编辑状态
const handleCellClick = (row, column) => {
// ID列不可编辑
if (column.property === 'id') return;
// 如果点击的是当前编辑的单元格,不做处理
if (editingCell.value.row === row && editingCell.value.column === column) {
return;
}
// 先保存之前编辑的单元格(如果有)
if (editingCell.value.row && editingCell.value.column) {
handleSave(editingCell.value.row, editingCell.value.column);
}
// 保存原始值,用于取消编辑时恢复
row.originalData[column.property] = JSON.parse(JSON.stringify(row[column.property]));
// 设置当前编辑的单元格
editingCell.value = { row, column };
// 自动聚焦到输入框
nextTick(() => {
const inputElements = [
document.querySelector('.el-input__inner'),
document.querySelector('.el-input-number__input'),
document.querySelector('.el-select'),
document.querySelector('.el-date-editor input')
];
const activeInput = inputElements.find(el => el);
if (activeInput) {
activeInput.focus();
}
});
};
// 保存编辑
const handleSave = (row, column) => {
// 如果不是编辑状态,直接返回
if (!isEditing(row, column)) return;
const prop = column.property;
let isValid = true;
let errorMessage = '';
// 根据字段类型进行验证
switch (prop) {
case 'name':
if (!row[prop].trim()) {
isValid = false;
errorMessage = '姓名不能为空';
}
break;
case 'email':
if (row[prop] && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(row[prop])) {
isValid = false;
errorMessage = '请输入有效的邮箱地址';
}
break;
case 'age':
if (row[prop] === null || row[prop] <= 0 || row[prop] > 150) {
isValid = false;
errorMessage = '请输入有效的年龄(1-150)';
}
break;
case 'department':
if (!row[prop]) {
isValid = false;
errorMessage = '请选择部门';
}
break;
case 'joinDate':
if (!row[prop]) {
isValid = false;
errorMessage = '请选择入职日期';
}
break;
}
// 验证不通过,恢复原始值并提示
if (!isValid) {
row[prop] = row.originalData[prop];
ElMessage.error(errorMessage);
return;
}
// 清除编辑状态
editingCell.value = { row: null, column: null };
// 实际应用中这里会调用API保存数据
ElMessage.success('数据已更新');
console.log(`保存单元格数据: 行ID=${row.id}, 字段=${prop}, 值=${row[prop]}`);
};
// 单元格样式 - 用于突出显示可编辑单元格
const cellClassName = ({ row, column }) => {
// ID列不可编辑
if (column.property === 'id') return '';
return isEditing(row, column)
? 'cell-editing'
: 'cell-editable';
};
onMounted(() => {
console.log('点击编辑表格组件已加载');
});
</script>
<style scoped>
.editable-table-container {
padding: 20px;
max-width: 1400px;
margin: 0 auto;
}
.table-info {
margin-top: 15px;
color: #666;
font-size: 14px;
line-height: 1.6;
}
::v-deep .cell-editable {
cursor: pointer;
transition: background-color 0.2s;
}
::v-deep .cell-editable:hover {
background-color: #f5f7fa;
}
::v-deep .cell-editing {
background-color: #e6f7ff !important;
}
::v-deep .el-input,
::v-deep .el-input-number,
::v-deep .el-select,
::v-deep .el-date-editor {
width: 100%;
}
/* 移除输入框默认边框,与表格融合更自然 */
::v-deep .cell-editing .el-input__inner,
::v-deep .cell-editing .el-input-number__input,
::v-deep .cell-editing .el-date-editor input {
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
</style>

View File

@ -1,529 +0,0 @@
<template>
<div class="app-container">
<el-table :data="tableData" border style="width: 100%" @cell-click="handleCellClick"
:cell-class-name="cellClassName" :row-key="row => row.id" height="calc(100vh - 220px)" highlight-current-row
ref="tableRef">
<!-- 分单类别代号 -->
<el-table-column prop="categoryCode" label="分单类别代号" width="120">
<template #default="scope">
<template v-if="isEditing(scope.row, 'categoryCode')">
<el-input v-model="scope.row.categoryCode" size="small" @blur="handleSave(scope.row, 'categoryCode')"
@keyup.enter="handleSave(scope.row, 'categoryCode')" ref="getInputRef(scope.row.id, 'categoryCode')"
auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'categoryCode' })">
{{ scope.row.categoryCode }}
</span>
</template>
</template>
</el-table-column>
<!-- 类别名称 -->
<el-table-column prop="categoryName" label="类别名称" width="180">
<template #default="scope">
<template v-if="isEditing(scope.row, 'categoryName')">
<el-input v-model="scope.row.categoryName" size="small" @blur="handleSave(scope.row, 'categoryName')"
@keyup.enter="handleSave(scope.row, 'categoryName')" auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'categoryName' })">
{{ scope.row.categoryName }}
</span>
</template>
</template>
</el-table-column>
<!-- 类别简称 -->
<el-table-column prop="shortName" label="类别简称" width="120">
<template #default="scope">
<template v-if="isEditing(scope.row, 'shortName')">
<el-input v-model="scope.row.shortName" size="small" @blur="handleSave(scope.row, 'shortName')"
@keyup.enter="handleSave(scope.row, 'shortName')" auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'shortName' })">
{{ scope.row.shortName }}
</span>
</template>
</template>
</el-table-column>
<!-- 条码类别 -->
<el-table-column prop="barcodeType" label="条码类别" width="130">
<template #default="scope">
<template v-if="isEditing(scope.row, 'barcodeType')">
<el-select v-model="scope.row.barcodeType" size="small" @change="handleSave(scope.row, 'barcodeType')"
@blur="handleSave(scope.row, 'barcodeType')" auto-focus>
<el-option v-for="item in barcodeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'barcodeType' })">
{{ getOptionLabel(barcodeTypeOptions, scope.row.barcodeType) }}
</span>
</template>
</template>
</el-table-column>
<!-- 标本类型 -->
<el-table-column prop="specimenType" label="标本类型" width="140">
<template #default="scope">
<template v-if="isEditing(scope.row, 'specimenType')">
<el-select v-model="scope.row.specimenType" size="small" @change="handleSave(scope.row, 'specimenType')"
@blur="handleSave(scope.row, 'specimenType')" auto-focus>
<el-option v-for="item in specimenTypeOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'specimenType' })">
{{ getOptionLabel(specimenTypeOptions, scope.row.specimenType) }}
</span>
</template>
</template>
</el-table-column>
<!-- 标本采集说明 -->
<el-table-column prop="collectionInstructions" label="标本采集说明" width="220">
<template #default="scope">
<template v-if="isEditing(scope.row, 'collectionInstructions')">
<el-input v-model="scope.row.collectionInstructions" size="small" type="textarea" :rows="2"
@blur="handleSave(scope.row, 'collectionInstructions')"
@keyup.enter.ctrl="handleSave(scope.row, 'collectionInstructions')" auto-focus />
</template>
<template v-else>
<div class="multi-line-text"
@click.stop="handleCellClick(scope.row, { property: 'collectionInstructions' })">
{{ scope.row.collectionInstructions || '-' }}
</div>
</template>
</template>
</el-table-column>
<!-- 报告领取规则 -->
<el-table-column prop="reportCollectionRule" label="报告领取规则" width="160">
<template #default="scope">
<template v-if="isEditing(scope.row, 'reportCollectionRule')">
<el-select v-model="scope.row.reportCollectionRule" size="small"
@change="handleSave(scope.row, 'reportCollectionRule')"
@blur="handleSave(scope.row, 'reportCollectionRule')" auto-focus>
<el-option v-for="item in reportRuleOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'reportCollectionRule' })">
{{ getOptionLabel(reportRuleOptions, scope.row.reportCollectionRule) }}
</span>
</template>
</template>
</el-table-column>
<!-- 打印份数 -->
<el-table-column prop="printCopies" label="打印份数" width="100" align="center">
<template #default="scope">
<template v-if="isEditing(scope.row, 'printCopies')">
<el-input-number v-model="scope.row.printCopies" :min="1" :max="10" size="small"
@blur="handleSave(scope.row, 'printCopies')" @keyup.enter="handleSave(scope.row, 'printCopies')"
auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'printCopies' })">
{{ scope.row.printCopies }}
</span>
</template>
</template>
</el-table-column>
<!-- 专业组(样本数) -->
<el-table-column prop="deptSampleCount" label="专业组(样本数)" width="140" align="center">
<template #default="scope">
<template v-if="isEditing(scope.row, 'deptSampleCount')">
<el-input-number v-model="scope.row.deptSampleCount" :min="1" size="small"
@blur="handleSave(scope.row, 'deptSampleCount')" @keyup.enter="handleSave(scope.row, 'deptSampleCount')"
auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'deptSampleCount' })">
{{ scope.row.deptSampleCount }}
</span>
</template>
</template>
</el-table-column>
<!-- 专业组(周转时间) -->
<el-table-column prop="deptTurnaroundTime" label="专业组(周转时间)" width="160" align="center">
<template #default="scope">
<template v-if="isEditing(scope.row, 'deptTurnaroundTime')">
<el-input-number v-model="scope.row.deptTurnaroundTime" :min="0" size="small" suffix="分钟"
@blur="handleSave(scope.row, 'deptTurnaroundTime')"
@keyup.enter="handleSave(scope.row, 'deptTurnaroundTime')" auto-focus />
</template>
<template v-else>
<span @click.stop="handleCellClick(scope.row, { property: 'deptTurnaroundTime' })">
{{ scope.row.deptTurnaroundTime }} 分钟
</span>
</template>
</template>
</el-table-column>
<!-- 抗凝 -->
<el-table-column prop="anticoagulant" label="抗凝" width="100" align="center">
<template #default="scope">
<el-checkbox v-model="scope.row.anticoagulant" />
</template>
</el-table-column>
<!-- 血培 -->
<el-table-column prop="bloodCulture" label="血培" width="100" align="center">
<template #default="scope">
<el-checkbox v-model="scope.row.bloodCulture" />
</template>
</el-table-column>
<!-- 标识颜色 -->
<el-table-column prop="markerColor" label="标识颜色" width="140" align="center">
<template #default="scope">
<template v-if="isEditing(scope.row, 'markerColor')">
<el-color-picker v-model="scope.row.markerColor" size="small" @change="handleSave(scope.row, 'markerColor')"
@blur="handleSave(scope.row, 'markerColor')" auto-focus />
</template>
<template v-else>
<div class="color-display" @click.stop="handleCellClick(scope.row, { property: 'markerColor' })">
<span class="color-block" :style="{ backgroundColor: scope.row.markerColor }" />
<span class="color-code">{{ scope.row.markerColor }}</span>
</div>
</template>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref, reactive, nextTick } from 'vue';
import { ElMessage, } from 'element-plus';
// 选项数据
const barcodeTypeOptions = [
{ label: '一维条码', value: '1d' },
{ label: '二维码', value: '2d' },
{ label: 'RFID', value: 'rfid' },
{ label: '无', value: 'none' }
];
const specimenTypeOptions = [
{ label: '全血', value: 'whole_blood' },
{ label: '血清', value: 'serum' },
{ label: '血浆', value: 'plasma' },
{ label: '尿液', value: 'urine' },
{ label: '脑脊液', value: 'csf' },
{ label: '其他', value: 'other' }
];
const reportRuleOptions = [
{ label: '自助打印', value: 'self_print' },
{ label: '人工窗口', value: 'counter' },
{ label: '科室配送', value: 'dept_delivery' },
{ label: '线上查看', value: 'online' }
];
// 表格数据
const tableData = reactive([
{
id: 1,
categoryCode: 'BH001',
categoryName: '血常规检查',
shortName: '血常规',
barcodeType: '1d',
specimenType: 'whole_blood',
collectionInstructions: '空腹采血,采血量2ml,EDTA抗凝',
reportCollectionRule: 'self_print',
printCopies: 2,
deptSampleCount: 1,
deptTurnaroundTime: 30,
anticoagulant: false,
bloodCulture: false,
markerColor: '#409eff',
originalData: {}
},
{
id: 2,
categoryCode: 'BL002',
categoryName: '生化全项检查',
shortName: '生化全项',
barcodeType: '2d',
specimenType: 'serum',
collectionInstructions: '空腹12小时以上采血,采血量5ml,分离血清',
reportCollectionRule: 'counter',
printCopies: 1,
deptSampleCount: 1,
deptTurnaroundTime: 120,
anticoagulant: false,
bloodCulture: false,
markerColor: '#67c23a',
originalData: {}
}
]);
// 表格引用
const tableRef = ref(null);
// 输入框引用
const inputRefs = ref({});
// 当前编辑状态:{rowId: xxx, field: 'xxx'}
const editingState = ref(null);
// 设置输入框引用
const getInputRef = (rowId, field) => {
return (el) => {
if (el) {
inputRefs.value[`${rowId}-${field}`] = el;
}
};
};
// 判断是否处于编辑状态
const isEditing = (row, field) => {
return editingState.value && editingState.value.rowId === row.id && editingState.value.field === field;
};
// 获取选项标签
const getOptionLabel = (options, value) => {
const option = options.find(item => item.value === value);
return option ? option.label : '';
};
// 处理单元格点击 - 核心修复部分
const handleCellClick = (row, column) => {
// 忽略操作列
if (column.label === '操作') return;
const field = column.property;
// 如果点击的是当前编辑的单元格,不重复处理
if (isEditing(row, field)) {
return;
}
// 保存之前编辑的内容
if (editingState.value) {
const prevRow = tableData.find(r => r.id === editingState.value.rowId);
if (prevRow) {
handleSave(prevRow, editingState.value.field);
}
}
// 保存原始值用于恢复
row.originalData[field] = JSON.parse(JSON.stringify(row[field]));
// 设置当前编辑状态
editingState.value = {
rowId: row.id,
field: field
};
// 强制刷新UI后聚焦
nextTick(() => {
const inputKey = `${row.id}-${field}`;
const inputElement = inputRefs.value[inputKey]?.$el?.querySelector('input') ||
inputRefs.value[inputKey]?.$el;
if (inputElement) {
inputElement.focus();
}
});
};
// 保存编辑
const handleSave = (row, field) => {
// 非编辑状态不处理
if (!isEditing(row, field)) return;
let isValid = true;
let errorMessage = '';
// 字段验证
switch (field) {
case 'categoryCode':
if (!row[field]?.trim()) {
isValid = false;
errorMessage = '分单类别代号不能为空';
}
break;
case 'categoryName':
if (!row[field]?.trim()) {
isValid = false;
errorMessage = '类别名称不能为空';
}
break;
case 'shortName':
if (!row[field]?.trim()) {
isValid = false;
errorMessage = '类别简称不能为空';
}
break;
case 'printCopies':
case 'deptSampleCount':
if (row[field] < 1) {
isValid = false;
errorMessage = '数值必须大于0';
}
break;
case 'deptTurnaroundTime':
if (row[field] < 0) {
isValid = false;
errorMessage = '数值不能为负数';
}
break;
}
// 验证失败处理
if (!isValid) {
row[field] = row.originalData[field];
ElMessage.error(errorMessage);
// 保持编辑状态以便修正
return;
}
// 清除编辑状态
editingState.value = null;
ElMessage.success('数据已更新');
};
// 单元格样式
const cellClassName = ({ row, column }) => {
return isEditing(row, column.property)
? 'cell-editing'
: 'cell-editable';
};
// 新增项
const addNewItem = () => {
const newId = Math.max(...tableData.map(item => item.id), 0) + 1;
tableData.unshift({
id: newId,
categoryCode: `NEW${newId}`,
categoryName: '',
shortName: '',
barcodeType: '1d',
specimenType: 'other',
collectionInstructions: '',
reportCollectionRule: 'self_print',
printCopies: 1,
deptSampleCount: 1,
deptTurnaroundTime: 60,
anticoagulant: 'N',
bloodCulture: 'N',
markerColor: '#909399',
originalData: {}
});
ElMessage.info('已添加新类别,请完善信息');
};
</script>
<style scoped>
/* 保持与之前相同的样式 */
.editable-table-wrapper {
padding: 20px;
max-width: 1800px;
margin: 0 auto;
}
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.table-header h3 {
margin: 0;
color: #333;
font-size: 18px;
}
.add-btn {
margin-bottom: 5px;
}
.table-desc {
margin-top: 15px;
padding: 10px 15px;
background-color: #f5f7fa;
border-radius: 4px;
font-size: 14px;
color: #666;
}
/* 单元格样式优化 */
::v-deep .cell-editable {
cursor: pointer;
transition: background-color 0.2s;
}
::v-deep .cell-editable:hover {
background-color: #f0f7ff !important;
}
::v-deep .cell-editing {
background-color: #e6f7ff !important;
}
::v-deep .el-table .el-table__cell {
padding: 6px 0;
}
/* 输入控件样式 */
::v-deep .el-input,
::v-deep .el-input-number,
::v-deep .el-select,
::v-deep .el-color-picker,
::v-deep .el-textarea {
width: 90%;
margin: 0 auto;
}
::v-deep .el-textarea__inner {
min-height: 60px;
resize: vertical;
}
/* 多行文本和颜色显示样式 */
.multi-line-text {
white-space: pre-wrap;
word-break: break-all;
line-height: 1.4;
padding: 0 5px;
}
.color-display {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
}
.color-block {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 3px;
border: 1px solid #ddd;
}
.color-code {
font-size: 12px;
color: #666;
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -32,8 +32,6 @@
// "allowUnknownInTemplate": true // 允许模板中使用未知属性
// }
},
"jsx": "preserve",
"types": ["element-plus/global"],
"include": ["src/**/*","src/**/*.ts", "src/**/*.vue","src/**/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "auto-imports.d.ts"], // **表示任意目录,而 * 表示任意文件。这表明 src 目录中的所有文件都将被编译
"exclude": ["node_modules", "dist"] ,// 指示不需要编译的文件目录
}