收费项目维护模块,优化条码类别模块
This commit is contained in:
parent
f69122ff6d
commit
e61104d7c3
@ -18,7 +18,7 @@
|
||||
"axios": "0.27.2",
|
||||
"clipboard": "^2.0.11",
|
||||
"echarts": "5.4.3",
|
||||
"element-plus": "2.4.3",
|
||||
"element-plus": "^2.11.2",
|
||||
"file-saver": "2.0.5",
|
||||
"fuse.js": "6.6.2",
|
||||
"jquery": "^3.7.1",
|
||||
|
||||
@ -83,3 +83,4 @@ export function reportFsresult(query?: Object) {
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
80
src/api/mzcx/index.ts
Normal file
80
src/api/mzcx/index.ts
Normal file
@ -0,0 +1,80 @@
|
||||
//@ts-ignore js语法检查忽略
|
||||
import request from '@/utils/request';
|
||||
|
||||
|
||||
// 查询条码类别
|
||||
export function feeitemclassList(query?: Object) {
|
||||
return request({
|
||||
url: 'feeitemclass/query',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
// 报告领取规则
|
||||
export function rptgetrules(query?: Object) {
|
||||
return request({
|
||||
url: '/rptgetrule/query',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
// 新增条码类别
|
||||
export function feeitemclassAdd(query?: Object) {
|
||||
return request({
|
||||
url: '/feeitemclass/add',
|
||||
method: 'post',
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
// 修改条码类别
|
||||
export function feeitemclassUpdate(query?: Object) {
|
||||
return request({
|
||||
url: '/feeitemclass/update',
|
||||
method: 'post',
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
// 删除条码类别
|
||||
export function feeitemclassDel(query?: Object) {
|
||||
return request({
|
||||
url: '/feeitemclass/del',
|
||||
method: 'delete',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 收费项目维护列表
|
||||
export function xmfeeList(query?: Object) {
|
||||
return request({
|
||||
url: 'xmfee/query',
|
||||
method: 'get',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
// 收费项目新增
|
||||
export function xmfeeadd(query?: Object) {
|
||||
return request({
|
||||
url: 'xmfee/addXmfee',
|
||||
method: 'post',
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
// 收费项目修改
|
||||
export function xmfeeUpdate(query?: Object) {
|
||||
return request({
|
||||
url: 'xmfee/update',
|
||||
method: 'post',
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
// 收费项目删除
|
||||
export function xmfeeDel(query?: Object) {
|
||||
return request({
|
||||
url: 'xmfee/del',
|
||||
method: 'delete',
|
||||
params: query,
|
||||
});
|
||||
}
|
||||
@ -12,13 +12,14 @@ function decimalToHexColor(decimal: number | string): string {
|
||||
|
||||
// 统一转换为数字类型
|
||||
const num = typeof decimal === 'string' ? parseFloat(decimal) : decimal;
|
||||
|
||||
if (isNaN(num)) {
|
||||
return '#FFFFFF';
|
||||
}
|
||||
|
||||
// 十进制转十六进制并转为大写
|
||||
let hex = Math.floor(num).toString(16).toUpperCase();
|
||||
|
||||
let rgbHex = ''
|
||||
// 确保十六进制字符串为6位,不足则补0
|
||||
if (hex.length < 6) {
|
||||
hex = hex.padStart(6, '0');
|
||||
@ -28,11 +29,18 @@ function decimalToHexColor(decimal: number | string): string {
|
||||
const r = hex.substring(4, 6);
|
||||
const g = hex.substring(2, 4);
|
||||
const b = hex.substring(0, 2);
|
||||
const rgbHex = r + g + b;
|
||||
|
||||
rgbHex = r + g + b;
|
||||
return `#${rgbHex}`;
|
||||
}
|
||||
|
||||
|
||||
// 处理颜色转换为十进制数字
|
||||
const convertHexToNumber = (hex: string) => {
|
||||
if (!hex) return
|
||||
hex = hex.replace('#', '');
|
||||
const bgr = hex.slice(4, 6) + hex.slice(2, 4) + hex.slice(0, 2);
|
||||
return parseInt(bgr, 16);
|
||||
};
|
||||
/**
|
||||
* 根据背景色计算对比度文字颜色(黑/白)
|
||||
* @param bgColor 十六进制背景色(如#FFFF80)
|
||||
@ -79,5 +87,5 @@ function base64ToBlob(base64: string) {
|
||||
}
|
||||
|
||||
|
||||
export const classCom = { decimalToHexColor, getContrastTextColor, printPDF }
|
||||
export const classCom = { decimalToHexColor, convertHexToNumber, getContrastTextColor, printPDF }
|
||||
|
||||
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -67,8 +67,6 @@ watch(zdlbmc, (val) => {
|
||||
})
|
||||
|
||||
const filterNode = (value, data) => {
|
||||
console.log(value, data);
|
||||
|
||||
if (!value) return true
|
||||
return data.zdmc.includes(value)
|
||||
}
|
||||
|
||||
636
src/views/mzcx/blood/index.vue
Normal file
636
src/views/mzcx/blood/index.vue
Normal file
@ -0,0 +1,636 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="table-header">
|
||||
|
||||
<el-button type="primary" @click="handleQuery" class="add-btn"> 查询 </el-button>
|
||||
<el-button type="primary" @click="addNewItem" class="add-btn"> 新增 </el-button>
|
||||
<el-button type="success" @click="save" class="add-btn"> 保存 </el-button>
|
||||
|
||||
</div>
|
||||
<el-table :data="tableData" border style="width: 100%" @cell-click="handleCellClick"
|
||||
:cell-class-name="cellClassName" :row-key="(row: any) => row.id" height="calc(100vh - 260px)"
|
||||
highlight-current-row ref="tableRef">
|
||||
<!-- 分单类别代号 -->
|
||||
<el-table-column prop="sflbdh" label="分单类别代号" width="110">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sflbdh')">
|
||||
<el-input v-model="scope.row.sflbdh" size="small" @blur="handleSave(scope.row, 'sflbdh')"
|
||||
@keyup.enter="handleSave(scope.row, 'sflbdh')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'sflbdh' })">
|
||||
{{ scope.row.sflbdh }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 类别名称 -->
|
||||
<el-table-column prop="sflbmc" label="类别名称" width="150">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sflbmc')">
|
||||
<el-input v-model="scope.row.sflbmc" size="small" @blur="handleSave(scope.row, 'sflbmc')"
|
||||
@keyup.enter="handleSave(scope.row, 'sflbmc')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'sflbmc' })">
|
||||
{{ scope.row.sflbmc }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 类别简称 -->
|
||||
<el-table-column prop="sflbjc" label="类别简称" width="120">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sflbjc')">
|
||||
<el-input v-model="scope.row.sflbjc" size="small" @blur="handleSave(scope.row, 'sflbjc')"
|
||||
@keyup.enter="handleSave(scope.row, 'sflbjc')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'sflbjc' })">
|
||||
{{ scope.row.sflbjc }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 条码类别 -->
|
||||
<el-table-column prop="txmlb" label="条码类别" width="110">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'txmlb')">
|
||||
<el-input v-model="scope.row.txmlb" size="small" @blur="handleSave(scope.row, 'txmlb')"
|
||||
@keyup.enter="handleSave(scope.row, 'txmlb')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'txmlb' })">
|
||||
{{ scope.row.txmlb }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 标本类型 -->
|
||||
<el-table-column prop="yblx" label="标本类型" width="140">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'yblx')">
|
||||
<el-select v-model="scope.row.yblx" size="small" @change="handleSave(scope.row, 'yblx')"
|
||||
@blur="handleSave(scope.row, 'yblx')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.BT" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'yblx' })">
|
||||
{{ scope.row.yblx }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 标本采集说明 -->
|
||||
<el-table-column prop="sampletips" label="标本采集说明" width="220">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sampletips')">
|
||||
<el-input v-model="scope.row.sampletips" size="small" @blur="handleSave(scope.row, 'sampletips')"
|
||||
@keyup.enter.ctrl="handleSave(scope.row, 'sampletips')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="multi-line-text" @click.stop="handleCellClick(scope.row, { property: 'sampletips' })">
|
||||
{{ scope.row.sampletips }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 报告领取规则 -->
|
||||
<el-table-column prop="bglqdh" label="报告领取规则" width="160">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'bglqdh')">
|
||||
<el-select v-model="scope.row.bglqdh" size="small" @change="handleSave(scope.row, 'bglqdh')" filterable
|
||||
@blur="handleSave(scope.row, 'bglqdh')" auto-focus>
|
||||
<el-option v-for="item in reportRuleOptions" :key="item.bglqdh" :label="item.bglqmc"
|
||||
:value="item.bglqdh" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'bglqdh' })">
|
||||
{{ getOptionLabel(reportRuleOptions, scope.row.bglqdh) }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 打印份数 -->
|
||||
<el-table-column prop="printcnt" label="打印份数" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'printcnt')">
|
||||
<el-input-number v-model="scope.row.printcnt" :min="1" :max="9" size="small"
|
||||
@blur="handleSave(scope.row, 'printcnt')" @keyup.enter="handleSave(scope.row, 'printcnt')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'printcnt' })">
|
||||
{{ scope.row.printcnt }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 专业组(样本数) -->
|
||||
<el-table-column prop="lisgroup1" label="专业组(样本数)" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'lisgroup1')">
|
||||
<el-select v-model="scope.row.lisgroup1" size="small" @change="handleSave(scope.row, 'lisgroup1')"
|
||||
@blur="handleSave(scope.row, 'lisgroup1')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.LISGROUP1" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'lisgroup1' })">
|
||||
{{ scope.row.lisgroup1 }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 专业组(周转时间) -->
|
||||
<el-table-column prop="lisgroup2" label="专业组(周转时间)" width="160" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'lisgroup2')">
|
||||
<el-select v-model="scope.row.lisgroup2" size="small" @change="handleSave(scope.row, 'lisgroup2')"
|
||||
@blur="handleSave(scope.row, 'lisgroup2')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.LISGROUP2" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'lisgroup2' })">
|
||||
{{ scope.row.lisgroup2 }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 抗凝 -->
|
||||
<el-table-column prop="kn" label="抗凝" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.kn" :true-value="'1'" :false-value="'0'" @change="handleSave(scope.row, 'kn')"
|
||||
:ref="getInputRef(scope.row.id, 'kn')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 血培 -->
|
||||
<el-table-column prop="xpy" label="血培" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row.xpy" :true-value="'1'" :false-value="'0'"
|
||||
@change="handleSave(scope.row, 'xpy')" :ref="getInputRef(scope.row.id, 'xpy')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 标识颜色 -->
|
||||
<el-table-column prop="bkcolor" label="标识颜色" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'bkcolor')">
|
||||
<el-color-picker v-model="scope.row.bkcolor" size="small" @change="handleSave(scope.row, 'bkcolor')"
|
||||
@blur="handleSave(scope.row, 'bkcolor')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="color-display" @click.stop="handleCellClick(scope.row, { property: 'bkcolor' })">
|
||||
<span class="color-block" :style="{ backgroundColor: scope.row.bkcolor }" />
|
||||
<span class="color-code">{{ scope.row.bkcolor }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 操作列 -->
|
||||
<el-table-column label="操作" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination :total="total" v-model:page="pageNum" v-model:limit="pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, nextTick, onMounted, toRaw, computed } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { feeitemclassList, rptgetrules, feeitemclassAdd, feeitemclassUpdate, feeitemclassDel } from '@/api/mzcx/index';
|
||||
import { classCom } from '@/utils/classCom';
|
||||
// @ts-ignore
|
||||
import { comDict } from '@/utils/dict'
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(0);
|
||||
|
||||
|
||||
const reportRuleOptions = ref<{ bglqdh: string, bglqmc: string, bz: string }[]>([]);
|
||||
|
||||
interface tableDataItem {
|
||||
id: string,
|
||||
sflbdh: string,
|
||||
sflbmc: string,
|
||||
sflbjc: string,
|
||||
txmlb: string,
|
||||
yblx: string,
|
||||
sampletips: string,
|
||||
bglqdh: number,
|
||||
printcnt: number,
|
||||
lisgroup1: string,
|
||||
lisgroup2: string,
|
||||
kn: string,
|
||||
xpy: string,
|
||||
bkcolor: string,
|
||||
originalData: object,
|
||||
flag: boolean,
|
||||
status: boolean
|
||||
}
|
||||
// 表格数据
|
||||
const tableData = ref<tableDataItem[]>([]);
|
||||
|
||||
const inputRefs = ref<Record<string, any>>({});
|
||||
// 表格引用
|
||||
const tableRef = ref(null);
|
||||
|
||||
const editingState = ref({ rowId: '', field: '' });
|
||||
|
||||
// 设置输入框引用
|
||||
const getInputRef = (rowId: string, field: string) => {
|
||||
return (el: any) => {
|
||||
if (el) {
|
||||
inputRefs.value[`${rowId}-${field}`] = el;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 判断是否处于编辑状态
|
||||
const isEditing = (row: any, field: string) => {
|
||||
return editingState.value && editingState.value.rowId === row.id && editingState.value.field === field;
|
||||
};
|
||||
|
||||
// 获取选项标签
|
||||
const getOptionLabel = (options: any, value: string) => {
|
||||
const option = options.find((item: any) => item.bglqdh === value);
|
||||
return option ? option.bglqmc : '';
|
||||
};
|
||||
|
||||
// 处理单元格点击 - 核心修复部分
|
||||
const handleCellClick = (row: any, column: any) => {
|
||||
// 忽略操作列
|
||||
if (column.label === '操作') return;
|
||||
|
||||
const field = column.property;
|
||||
|
||||
// 如果点击的是当前编辑的单元格,不重复处理
|
||||
if (isEditing(row, field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存之前编辑的内容
|
||||
if (editingState.value) {
|
||||
const prevRow = tableData.value.find((r: any) => 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: any, field: string) => {
|
||||
// 非编辑状态不处理
|
||||
if (!isEditing(row, field)) return;
|
||||
|
||||
let isValid = true;
|
||||
let errorMessage = '';
|
||||
|
||||
// 字段验证
|
||||
switch (field) {
|
||||
case 'sflbdh':
|
||||
if (!row[field]?.trim()) {
|
||||
isValid = false;
|
||||
errorMessage = '分单类别代号不能为空';
|
||||
} else {
|
||||
// 验证重复(排除当前行自身)
|
||||
const isDuplicate = tableData.value.some((item: any) => {
|
||||
return item.sflbdh === row.sflbdh && item.id !== row.id;
|
||||
});
|
||||
if (isDuplicate) {
|
||||
isValid = false;
|
||||
errorMessage = '分单类别代号已存在';
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case 'sflbmc':
|
||||
// if (!row[field]?.trim()) {
|
||||
// isValid = false;
|
||||
// errorMessage = '类别名称不能为空';
|
||||
// }
|
||||
// break;
|
||||
// case 'sflbjc':
|
||||
// if (!row[field]?.trim()) {
|
||||
// isValid = false;
|
||||
// errorMessage = '类别简称不能为空';
|
||||
// }
|
||||
// break;
|
||||
case 'printcnt':
|
||||
if (row[field] < 1) {
|
||||
isValid = false;
|
||||
errorMessage = '数值必须大于0';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bkcolor':
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 验证失败处理
|
||||
if (!isValid) {
|
||||
row[field] = row.originalData[field];
|
||||
ElMessage.error(errorMessage);
|
||||
// 保持编辑状态以便修正
|
||||
return;
|
||||
}
|
||||
|
||||
// 对比原始数据判断是否有变化
|
||||
if (!row.status) {
|
||||
row.status = JSON.stringify(row[field]) !== JSON.stringify(row.originalData[field]);
|
||||
}
|
||||
|
||||
|
||||
// 清除编辑状态
|
||||
editingState.value = { rowId: '', field: '' };
|
||||
|
||||
console.log('originalData==>', row);
|
||||
|
||||
|
||||
};
|
||||
|
||||
interface OperateLists {
|
||||
addList: any[];
|
||||
updateList: any[];
|
||||
}
|
||||
// 保存
|
||||
const save = () => {
|
||||
const { addList, updateList } = tableData.value.reduce<OperateLists>((acc, item) => {
|
||||
const { originalData, id, status, flag, bkcolor, ...restData } = item;
|
||||
const submitData = { ...restData, bkcolor: classCom.convertHexToNumber(bkcolor) };
|
||||
if (status) {
|
||||
flag ? acc.addList.push(submitData) : acc.updateList.push(submitData);
|
||||
}
|
||||
return acc;
|
||||
}, { addList: [], updateList: [] });
|
||||
|
||||
console.log('新增列表:', addList);
|
||||
console.log('更新列表:', updateList);
|
||||
if (addList.length > 0) {
|
||||
feeitemclassAdd(addList).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
ElMessage.success(res.msg);
|
||||
getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (updateList.length > 0) {
|
||||
feeitemclassUpdate(updateList).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
ElMessage.success(res.msg);
|
||||
getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// 单元格样式
|
||||
const cellClassName = ({ row, column }: { row: any, column: any }) => {
|
||||
return isEditing(row, column.property)
|
||||
? 'cell-editing'
|
||||
: 'cell-editable';
|
||||
};
|
||||
|
||||
// 新增项
|
||||
const addNewItem = () => {
|
||||
const newId = Array.from({ length: 4 }, () => Math.floor(Math.random() * 10)).join('');
|
||||
tableData.value.unshift({
|
||||
id: newId,
|
||||
sflbdh: `NEW${newId}`,
|
||||
sflbmc: 'test',
|
||||
sflbjc: '',
|
||||
txmlb: '',
|
||||
yblx: '',
|
||||
sampletips: '',
|
||||
bglqdh: 1,
|
||||
printcnt: 1,
|
||||
lisgroup1: '',
|
||||
lisgroup2: '',
|
||||
kn: '1',
|
||||
xpy: '0',
|
||||
bkcolor: '#FFFFFF',
|
||||
originalData: {},
|
||||
flag: true,
|
||||
status: true
|
||||
});
|
||||
// ElMessage.info('已添加新类别,请完善信息');
|
||||
};
|
||||
// 删除项
|
||||
const handleDelete = (row: any) => {
|
||||
ElMessageBox.confirm(`确定删除该${row.sflbdh}吗?`, "提示", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
beforeClose: (action, instance, done) => {
|
||||
if (action === "confirm") {
|
||||
feeitemclassDel({ sflbdh: row.sflbdh }).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
getList()
|
||||
ElMessage.success('删除成功');
|
||||
done();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
},
|
||||
}).catch(() => { });
|
||||
|
||||
};
|
||||
const handleQuery = () => {
|
||||
pageNum.value = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
|
||||
const getList = () => {
|
||||
feeitemclassList({ pageSize: pageSize.value, pageNum: pageNum.value }).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
tableData.value = res.rows
|
||||
total.value = res.total
|
||||
tableData.value.forEach((item: any) => {
|
||||
item.originalData = {}
|
||||
item.id = item.sflbdh
|
||||
item.status = false
|
||||
item.bkcolor = classCom.decimalToHexColor(item.bkcolor)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getRules = () => {
|
||||
rptgetrules().then((res: any) => {
|
||||
reportRuleOptions.value = res.data
|
||||
})
|
||||
}
|
||||
getList()
|
||||
getRules()
|
||||
|
||||
interface DictData {
|
||||
BT?: Array<any>;
|
||||
LISGROUP1?: Array<any>;
|
||||
LISGROUP2?: Array<any>;
|
||||
[key: string]: any[] | undefined; // 添加索引签名以支持动态访问
|
||||
}
|
||||
|
||||
|
||||
// 字典数据存储
|
||||
const dictData = ref<DictData>({});
|
||||
onMounted(async () => {
|
||||
// 加载病人来源字典
|
||||
const dictRefs = await comDict('BT', 'LISGROUP1', 'LISGROUP2');
|
||||
|
||||
// 从 ref 中获取实际数据
|
||||
dictData.value = {
|
||||
BT: toRaw(dictRefs.BT.value) || [],
|
||||
LISGROUP1: toRaw(dictRefs.LISGROUP1.value) || [],
|
||||
LISGROUP2: toRaw(dictRefs.LISGROUP2.value) || [],
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 字典格式化方法
|
||||
const formatDict = (v: string, dictType: string) => {
|
||||
return dictData.value[dictType]?.find((item: any) => item.value == v)?.label;
|
||||
};
|
||||
</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>
|
||||
711
src/views/mzcx/charge/index.vue
Normal file
711
src/views/mzcx/charge/index.vue
Normal file
@ -0,0 +1,711 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="table-header">
|
||||
<div>
|
||||
项目检索: <el-input v-model="queryParams.sfxmdh" @blur="handleQuery" @keyup.enter="handleQuery" auto-focus
|
||||
style="width: 200px;margin-right: 10px;" />
|
||||
|
||||
<el-button type="primary" @click="handleQuery" class="add-btn"> 查询 </el-button>
|
||||
<el-button type="primary" @click="addNewItem" class="add-btn"> 新增 </el-button>
|
||||
<el-button type="success" @click="save" class="add-btn"> 保存 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="tableData" border style="width: 100%" @cell-click="handleCellClick" :cell-style="cellStyle"
|
||||
:row-key="(row: any) => row.id" height="calc(100vh - 260px)" highlight-current-row ref="tableRef">
|
||||
<!-- 收费项目代号 -->
|
||||
<el-table-column prop="sfxmdh" label="收费项目代号" width="110">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sfxmdh')">
|
||||
<el-input v-model="scope.row.sfxmdh" size="small" @blur="handleSave(scope.row, 'sfxmdh')"
|
||||
@keyup.enter="handleSave(scope.row, 'sfxmdh')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'sfxmdh' })">
|
||||
{{ scope.row.sfxmdh }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 收费项目名称 -->
|
||||
<el-table-column prop="sfxmmc" label="收费项目名称" width="150">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'sfxmmc')">
|
||||
<el-input v-model="scope.row.sfxmmc" size="small" @blur="handleSave(scope.row, 'sfxmmc')"
|
||||
@keyup.enter="handleSave(scope.row, 'sfxmmc')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'sfxmmc' })">
|
||||
{{ scope.row.sfxmmc }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 简称 -->
|
||||
<el-table-column prop="bz" label="简称" width="120">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'bz')">
|
||||
<el-input v-model="scope.row.bz" size="small" @blur="handleSave(scope.row, 'bz')"
|
||||
@keyup.enter="handleSave(scope.row, 'bz')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'bz' })">
|
||||
{{ scope.row.bz }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 价格 -->
|
||||
<el-table-column prop="dj" label="价格" width="150" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'dj')">
|
||||
<el-input-number v-model="scope.row.dj" :min="1" :max="100" size="small" @blur="handleSave(scope.row, 'dj')"
|
||||
@keyup.enter="handleSave(scope.row, 'dj')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'dj' })">
|
||||
{{ scope.row.dj }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 规格 -->
|
||||
<el-table-column prop="spec" label="规格" width="120">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'spec')">
|
||||
<el-input v-model="scope.row.spec" size="small" @blur="handleSave(scope.row, 'spec')"
|
||||
@keyup.enter="handleSave(scope.row, 'spec')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'spec' })">
|
||||
{{ scope.row.spec }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 科室 -->
|
||||
<el-table-column prop="dept" label="科室" width="150">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'dept')">
|
||||
<el-select v-model="scope.row.dept" size="small" @change="handleSave(scope.row, 'dept')"
|
||||
@blur="handleSave(scope.row, 'dept')" auto-focus filterable style="width: 100%;">
|
||||
<el-option v-for="item in dictData.DP" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'dept' })">
|
||||
{{ formatDict(scope.row.dept, 'DP') }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 采集样本 -->
|
||||
<el-table-column prop="yblx" label="采集样本" width="140">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'yblx')">
|
||||
<el-select v-model="scope.row.yblx" size="small" @change="handleSave(scope.row, 'yblx')"
|
||||
@blur="handleSave(scope.row, 'yblx')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.BT" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'yblx' })">
|
||||
{{ scope.row.yblx }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 报告天数 -->
|
||||
<el-table-column prop="bgts" label="报告天数" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'bgts')">
|
||||
<el-input-number v-model="scope.row.bgts" size="small" @blur="handleSave(scope.row, 'bgts')"
|
||||
@keyup.enter="handleSave(scope.row, 'bgts')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'bgts' })">
|
||||
{{ scope.row.bgts }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 助记符 -->
|
||||
<el-table-column prop="zjf" label="助记符" width="150" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'zjf')">
|
||||
<el-input v-model="scope.row.zjf" size="small" @blur="handleSave(scope.row, 'zjf')"
|
||||
@keyup.enter.ctrl="handleSave(scope.row, 'zjf')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="multi-line-text" @click.stop="handleCellClick(scope.row, { property: 'zjf' })">
|
||||
{{ scope.row.zjf }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 报告领取规则 -->
|
||||
<el-table-column prop="bglqdh" label="报告领取规则" width="160">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'bglqdh')">
|
||||
<el-select v-model="scope.row.bglqdh" size="small" @change="handleSave(scope.row, 'bglqdh')" filterable
|
||||
@blur="handleSave(scope.row, 'bglqdh')" auto-focus>
|
||||
<el-option v-for="item in reportRuleOptions" :key="item.bglqdh" :label="item.bglqmc"
|
||||
:value="item.bglqdh" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'bglqdh' })">
|
||||
{{ getOptionLabel(reportRuleOptions, scope.row.bglqdh) }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 条码分类 -->
|
||||
<el-table-column prop="sflbmc" label="条码分类" width="130">
|
||||
<template #default="scope">
|
||||
<!-- <template v-if="isEditing(scope.row, 'sflbmc')">
|
||||
<el-select v-model="scope.row.sflbmc" size="small" @change="handleSave(scope.row, 'sflbmc')"
|
||||
@blur="handleSave(scope.row, 'sflbmc')" auto-focus>
|
||||
<el-option v-for="item in sflbmcOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</template> -->
|
||||
{{ scope.row.sflbmc }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 专业组(样本数) -->
|
||||
<el-table-column prop="lisgroup1" label="专业组(样本数)" width="140" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'lisgroup1')">
|
||||
<el-select v-model="scope.row.lisgroup1" size="small" @change="handleSave(scope.row, 'lisgroup1')"
|
||||
@blur="handleSave(scope.row, 'lisgroup1')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.LISGROUP1" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'lisgroup1' })">
|
||||
{{ scope.row.lisgroup1 }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 专业组(周转时间) -->
|
||||
<el-table-column prop="lisgroup2" label="专业组(周转时间)" width="160" align="center">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'lisgroup2')">
|
||||
<el-select v-model="scope.row.lisgroup2" size="small" @change="handleSave(scope.row, 'lisgroup2')"
|
||||
@blur="handleSave(scope.row, 'lisgroup2')" auto-focus filterable>
|
||||
<el-option v-for="item in dictData.LISGROUP2" :key="item.label" :label="item.label" :value="item.label" />
|
||||
</el-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span @click.stop="handleCellClick(scope.row, { property: 'lisgroup2' })">
|
||||
{{ scope.row.lisgroup2 }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 适应症 -->
|
||||
<el-table-column prop="indication" label="适应症" width="220">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'indication')">
|
||||
<el-input v-model="scope.row.indication" size="small" type="textarea" :rows="2"
|
||||
@blur="handleSave(scope.row, 'indication')" @keyup.enter.ctrl="handleSave(scope.row, 'indication')"
|
||||
auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="multi-line-text" @click.stop="handleCellClick(scope.row, { property: 'indication' })">
|
||||
{{ scope.row.indication }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 作用 -->
|
||||
<el-table-column prop="affect" label="作用" width="220">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'affect')">
|
||||
<el-input v-model="scope.row.affect" size="small" type="textarea" :rows="2"
|
||||
@blur="handleSave(scope.row, 'affect')" @keyup.enter.ctrl="handleSave(scope.row, 'affect')" auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="multi-line-text" @click.stop="handleCellClick(scope.row, { property: 'affect' })">
|
||||
{{ scope.row.affect }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 采集要求 -->
|
||||
<el-table-column prop="attention" label="采集要求" width="220">
|
||||
<template #default="scope">
|
||||
<template v-if="isEditing(scope.row, 'attention')">
|
||||
<el-input v-model="scope.row.attention" size="small" type="textarea" :rows="2"
|
||||
@blur="handleSave(scope.row, 'attention')" @keyup.enter.ctrl="handleSave(scope.row, 'attention')"
|
||||
auto-focus />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="multi-line-text" @click.stop="handleCellClick(scope.row, { property: 'attention' })">
|
||||
{{ scope.row.attention }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<el-table-column label="操作" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, nextTick, onMounted, toRaw, computed } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { xmfeeList, rptgetrules, xmfeeadd, xmfeeUpdate, xmfeeDel } from '@/api/mzcx/index';
|
||||
import { classCom } from '@/utils/classCom';
|
||||
// @ts-ignore
|
||||
import { comDict } from '@/utils/dict'
|
||||
const total = ref(0);
|
||||
|
||||
|
||||
const deptOptions = [
|
||||
{ label: '全部', value: '' }
|
||||
]
|
||||
|
||||
const queryParams = ref({
|
||||
sfxmdh: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
yljg: 1
|
||||
})
|
||||
|
||||
const reportRuleOptions = ref<{ bglqdh: string, bglqmc: string, bz: string }[]>([]);
|
||||
|
||||
interface tableDataItem {
|
||||
id: string,
|
||||
sfxmdh: string,
|
||||
sfxmmc: string,
|
||||
bz: string,
|
||||
dj: string,
|
||||
dept: string,
|
||||
yblx: string,
|
||||
zjf: string,
|
||||
spec: string,
|
||||
bgts: string,
|
||||
sflbmc: string,
|
||||
bglqdh: number,
|
||||
lisgroup1: string,
|
||||
lisgroup2: string,
|
||||
indication: string,
|
||||
affect: string,
|
||||
attention: string,
|
||||
originalData: object,
|
||||
flag: boolean,
|
||||
status: boolean,
|
||||
yljg: number
|
||||
}
|
||||
// 表格数据
|
||||
const tableData = ref<tableDataItem[]>([]);
|
||||
|
||||
const inputRefs = ref<Record<string, any>>({});
|
||||
// 表格引用
|
||||
const tableRef = ref(null);
|
||||
|
||||
const editingState = ref({ rowId: '', field: '' });
|
||||
|
||||
// 设置输入框引用
|
||||
const getInputRef = (rowId: string, field: string) => {
|
||||
return (el: any) => {
|
||||
if (el) {
|
||||
inputRefs.value[`${rowId}-${field}`] = el;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 判断是否处于编辑状态
|
||||
const isEditing = (row: any, field: string) => {
|
||||
return editingState.value && editingState.value.rowId === row.id && editingState.value.field === field;
|
||||
};
|
||||
|
||||
// 获取选项标签
|
||||
const getOptionLabel = (options: any, value: string) => {
|
||||
const option = options.find((item: any) => item.bglqdh === value);
|
||||
return option ? option.bglqmc : '';
|
||||
};
|
||||
|
||||
// 处理单元格点击 - 核心修复部分
|
||||
const handleCellClick = (row: any, column: any) => {
|
||||
// 忽略操作列
|
||||
if (column.label === '操作') return;
|
||||
|
||||
const field = column.property;
|
||||
|
||||
// 如果点击的是当前编辑的单元格,不重复处理
|
||||
if (isEditing(row, field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存之前编辑的内容
|
||||
if (editingState.value) {
|
||||
const prevRow = tableData.value.find((r: any) => 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: any, field: string) => {
|
||||
// 非编辑状态不处理
|
||||
if (!isEditing(row, field)) return;
|
||||
|
||||
let isValid = true;
|
||||
let errorMessage = '';
|
||||
|
||||
// 字段验证
|
||||
switch (field) {
|
||||
case 'sfxmdh':
|
||||
if (!row[field]?.trim()) {
|
||||
isValid = false;
|
||||
errorMessage = '收费项目代号不能为空';
|
||||
}
|
||||
break;
|
||||
// case 'sfxmmc':
|
||||
// if (!row[field]?.trim()) {
|
||||
// isValid = false;
|
||||
// errorMessage = '收费项目名称不能为空';
|
||||
// }
|
||||
// break;
|
||||
// case 'bz':
|
||||
// if (!row[field]?.trim()) {
|
||||
// isValid = false;
|
||||
// errorMessage = '简称不能为空';
|
||||
// }
|
||||
// break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 验证失败处理
|
||||
if (!isValid) {
|
||||
row[field] = row.originalData[field];
|
||||
ElMessage.error(errorMessage);
|
||||
// 保持编辑状态以便修正
|
||||
return;
|
||||
}
|
||||
|
||||
// 对比原始数据判断是否有变化
|
||||
if (!row.status) {
|
||||
row.status = JSON.stringify(row[field]) !== JSON.stringify(row.originalData[field]);
|
||||
}
|
||||
// 清除编辑状态
|
||||
editingState.value = { rowId: '', field: '' };
|
||||
|
||||
console.log('originalData==>', row);
|
||||
};
|
||||
interface OperateLists {
|
||||
addList: any[];
|
||||
updateList: any[];
|
||||
}
|
||||
// 保存
|
||||
const save = () => {
|
||||
const { addList, updateList } = tableData.value.reduce<OperateLists>((acc, item) => {
|
||||
const { originalData, id, status, flag, ...restData } = item;
|
||||
const submitData = { ...restData, };
|
||||
if (status) {
|
||||
flag ? acc.addList.push(submitData) : acc.updateList.push(submitData);
|
||||
}
|
||||
return acc;
|
||||
}, { addList: [], updateList: [] });
|
||||
|
||||
console.log('新增列表:', addList);
|
||||
console.log('更新列表:', updateList);
|
||||
if (addList.length > 0) {
|
||||
xmfeeadd(addList).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
ElMessage.success(res.msg);
|
||||
getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (updateList.length > 0) {
|
||||
xmfeeUpdate(updateList).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
ElMessage.success(res.msg);
|
||||
getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 单元格样式
|
||||
const cellClassName = ({ row, column }: { row: any, column: any }) => {
|
||||
return isEditing(row, column.property)
|
||||
? 'cell-editing'
|
||||
: 'cell-editable';
|
||||
};
|
||||
|
||||
// 单元格样式
|
||||
const cellStyle = ({ row, column, rowIndex, columnIndex }: {
|
||||
row: any;
|
||||
column: any;
|
||||
rowIndex: number;
|
||||
columnIndex: number;
|
||||
}) => {
|
||||
if (column.label == "条码分类") {
|
||||
const bgColor = classCom.decimalToHexColor(row.bkcolor);
|
||||
const textColor = classCom.getContrastTextColor(bgColor);
|
||||
return {
|
||||
backgroundColor: `${bgColor} !important`,
|
||||
color: textColor,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 新增项
|
||||
const addNewItem = () => {
|
||||
const newId = Array.from({ length: 14 }, () => Math.floor(Math.random() * 10)).join('');
|
||||
tableData.value.unshift({
|
||||
id: newId,
|
||||
sfxmdh: `NEW${newId}`,
|
||||
sfxmmc: 'test',
|
||||
bz: '',
|
||||
dj: '',
|
||||
spec: '',
|
||||
dept: '',
|
||||
yblx: '',
|
||||
bgts: '',
|
||||
zjf: '',
|
||||
bglqdh: 1,
|
||||
sflbmc: '',
|
||||
indication: '',
|
||||
affect: '',
|
||||
attention: '',
|
||||
lisgroup1: '',
|
||||
lisgroup2: '',
|
||||
originalData: {},
|
||||
flag: true,
|
||||
yljg: 1,
|
||||
status: true,
|
||||
});
|
||||
// ElMessage.info('已添加新类别,请完善信息');
|
||||
};
|
||||
// 删除项
|
||||
const handleDelete = (row: any) => {
|
||||
ElMessageBox.confirm(`确定删除该${row.sfxmdh}吗?`, "提示", {
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
beforeClose: (action, instance, done) => {
|
||||
if (action === "confirm") {
|
||||
xmfeeDel({ sfxmdh: row.sfxmdh }).then((res: any) => {
|
||||
if (res.code == 0) {
|
||||
getList()
|
||||
ElMessage.success('删除成功');
|
||||
done();
|
||||
}
|
||||
})
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
},
|
||||
}).catch(() => { });
|
||||
|
||||
};
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
|
||||
const getList = () => {
|
||||
xmfeeList(queryParams.value).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
tableData.value = res.rows
|
||||
total.value = res.total
|
||||
tableData.value.forEach((item: any) => {
|
||||
item.originalData = {}
|
||||
item.id = item.sfxmdh
|
||||
item.status = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getRules = () => {
|
||||
rptgetrules().then((res: any) => {
|
||||
reportRuleOptions.value = res.data
|
||||
})
|
||||
}
|
||||
getList()
|
||||
getRules()
|
||||
|
||||
interface DictData {
|
||||
BT?: Array<any>;
|
||||
DP?: Array<any>;
|
||||
LISGROUP1?: Array<any>;
|
||||
LISGROUP2?: Array<any>;
|
||||
[key: string]: any[] | undefined; // 添加索引签名以支持动态访问
|
||||
}
|
||||
|
||||
|
||||
// 字典数据存储
|
||||
const dictData = ref<DictData>({});
|
||||
onMounted(async () => {
|
||||
console.log('classCom ==>', classCom.decimalToHexColor("16777215"));
|
||||
// 加载病人来源字典
|
||||
const dictRefs = await comDict('BT', 'DP', 'LISGROUP1', 'LISGROUP2');
|
||||
|
||||
// 从 ref 中获取实际数据
|
||||
dictData.value = {
|
||||
BT: toRaw(dictRefs.BT.value) || [],
|
||||
DP: toRaw(dictRefs.DP.value) || [],
|
||||
LISGROUP1: toRaw(dictRefs.LISGROUP1.value) || [],
|
||||
LISGROUP2: toRaw(dictRefs.LISGROUP2.value) || [],
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 字典格式化方法
|
||||
const formatDict = (v: string, dictType: string) => {
|
||||
return dictData.value[dictType]?.find((item: any) => item.value == v)?.label;
|
||||
};
|
||||
</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>
|
||||
@ -32,7 +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"] ,// 指示不需要编译的文件目录
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user