收费项目维护模块,优化条码类别模块
This commit is contained in:
parent
f69122ff6d
commit
e61104d7c3
@ -18,7 +18,7 @@
|
|||||||
"axios": "0.27.2",
|
"axios": "0.27.2",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"echarts": "5.4.3",
|
"echarts": "5.4.3",
|
||||||
"element-plus": "2.4.3",
|
"element-plus": "^2.11.2",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"fuse.js": "6.6.2",
|
"fuse.js": "6.6.2",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
|
|||||||
@ -83,3 +83,4 @@ export function reportFsresult(query?: Object) {
|
|||||||
data: query,
|
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;
|
const num = typeof decimal === 'string' ? parseFloat(decimal) : decimal;
|
||||||
|
|
||||||
if (isNaN(num)) {
|
if (isNaN(num)) {
|
||||||
return '#FFFFFF';
|
return '#FFFFFF';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 十进制转十六进制并转为大写
|
// 十进制转十六进制并转为大写
|
||||||
let hex = Math.floor(num).toString(16).toUpperCase();
|
let hex = Math.floor(num).toString(16).toUpperCase();
|
||||||
|
let rgbHex = ''
|
||||||
// 确保十六进制字符串为6位,不足则补0
|
// 确保十六进制字符串为6位,不足则补0
|
||||||
if (hex.length < 6) {
|
if (hex.length < 6) {
|
||||||
hex = hex.padStart(6, '0');
|
hex = hex.padStart(6, '0');
|
||||||
@ -28,11 +29,18 @@ function decimalToHexColor(decimal: number | string): string {
|
|||||||
const r = hex.substring(4, 6);
|
const r = hex.substring(4, 6);
|
||||||
const g = hex.substring(2, 4);
|
const g = hex.substring(2, 4);
|
||||||
const b = hex.substring(0, 2);
|
const b = hex.substring(0, 2);
|
||||||
const rgbHex = r + g + b;
|
rgbHex = r + g + b;
|
||||||
|
|
||||||
return `#${rgbHex}`;
|
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)
|
* @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) => {
|
const filterNode = (value, data) => {
|
||||||
console.log(value, data);
|
|
||||||
|
|
||||||
if (!value) return true
|
if (!value) return true
|
||||||
return data.zdmc.includes(value)
|
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 // 允许模板中使用未知属性
|
// "allowUnknownInTemplate": true // 允许模板中使用未知属性
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
"jsx": "preserve",
|
|
||||||
"types": ["element-plus/global"],
|
"types": ["element-plus/global"],
|
||||||
"include": ["src/**/*","src/**/*.ts", "src/**/*.vue","src/**/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "auto-imports.d.ts"], // **表示任意目录,而 * 表示任意文件。这表明 src 目录中的所有文件都将被编译
|
"include": ["src/**/*","src/**/*.ts", "src/**/*.vue","src/**/**/*.vue", "src/**/*.tsx", "src/**/*.d.ts", "auto-imports.d.ts"], // **表示任意目录,而 * 表示任意文件。这表明 src 目录中的所有文件都将被编译
|
||||||
"exclude": ["node_modules", "dist"] ,// 指示不需要编译的文件目录
|
"exclude": ["node_modules", "dist"] ,// 指示不需要编译的文件目录
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user