增加模块、餐前餐后状态输入框

This commit is contained in:
Euni4U 2025-02-28 17:28:29 +08:00
parent 2bb287dda9
commit a5ffa9d636
5 changed files with 444 additions and 147 deletions

View File

@ -18,6 +18,9 @@ export interface itemsVO {
moduleID: number // 模块ID体检单元ID 模块名称ID
moduleName: string // 模块名称:体检单元
sectionID: string // 科室ID
groupname: string // 模块名称
groupcode: string // 模块ID
mealfrontorafter: string // 餐前餐后
}
// 检查项目 API

View File

@ -29,6 +29,7 @@ export interface ProfileVO {
loginIp: string
loginDate: Date
createTime: Date
deptId: string
}
export interface UserProfileUpdateReqVO {

View File

@ -3,62 +3,16 @@
<!-- 左侧人员列表 -->
<div class="patient-list">
<div class="list-header">
<div class="filter-options">
<div class="header-title">人员列表</div>
<!-- <label class="radio-label">
<input type="radio" name="status" checked/>
<span>未检</span>
</label>
<label class="radio-label">
<input type="radio" name="status"/>
<span>已检</span>
</label> -->
</div>
<div class="view-options">
<div class="view-buttons">
<button
v-for="period in timePeriods"
:key="period.value"
class="view-btn"
:class="{ active: selectedPeriod === period.value }"
@click="handlePeriodChange(period.value)"
>
{{ period.label }}
</button>
</div>
<!-- 添加日期选择器组件和搜索按钮 -->
<div v-if="showDatePicker" class="date-picker-container">
<div class="date-picker-wrapper">
<el-date-picker
v-model="customDateRange"
type="daterange"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:shortcuts="shortcuts"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</div>
<el-button
type="primary"
@click="handleDateSearch"
class="search-button"
>搜索</el-button>
</div>
</div>
<div class="search-box">
<!-- 简化体检编号搜索框 -->
<div class="search-box medical-sn-search">
<input
type="text"
v-model="searchQuery"
placeholder="请输入姓名"
@input="handleSearch"
v-model="medicalSnQuery"
placeholder="请输入体检编号"
@keyup.enter="handleMedicalSnSearch"
/>
<i class="el-icon-search search-icon"></i>
</div>
</div>
</div>
<div class="list-content">
@ -72,6 +26,13 @@
<div class="patient-info">
<span class="name">{{ patient.pname }}</span>
<span class="medical-sn">{{ patient.medicalSn }}</span>
<el-tag
:type="getStatusTagType(patient.status)"
size="small"
class="status-tag"
>
{{ getStatusText(patient.status) }}
</el-tag>
</div>
</div>
<!-- 将分页组件移到list-content内部底部 -->
@ -113,12 +74,13 @@
<label>姓名</label>
<span>{{ reportData.pname }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<label>性别</label>
<span>{{ reportData.gender }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<label>年龄</label>
<span>{{ age }}</span>
@ -127,14 +89,6 @@
<label>电话</label>
<span>{{ reportData.phoneNum }}</span>
</div>
<div class="info-item">
<label>国籍</label>
<span>{{ reportData.nationality }}</span>
</div>
<div class="info-item">
<label>民族</label>
<span>{{ reportData.nation }}</span>
</div>
</div>
</div>
</div>
@ -190,12 +144,15 @@
type="text"
v-model="item.value"
@change="handleResultChange(item)"
@click="checkEditPermission"
class="cell-input"
:disabled="isItemDisabled(item)"
:readonly="isReadOnly"
/>
</div>
<div class="table-cell" style="width: 10%">{{ item.unit }}</div>
<div class="table-cell" style="width: 15%">{{ item.reference }}</div>
<div class="table-cell" style="width: 15%">
{{ formatReference(item.reference) }}
</div>
<div class="table-cell" style="width: 10%">{{ item.note }}</div>
<div class="table-cell" style="width: 15%">{{ item.risk }}</div>
<div class="table-cell" style="width: 10%">
@ -212,7 +169,7 @@
</div>
<div class="table-cell" style="width: 10%">
<el-dropdown @command="handleOperation">
<el-button size="small">
<el-button size="small" :class="{ 'view-only': isReadOnly }">
更多操作
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
@ -253,6 +210,7 @@
v-model="examConclusion"
placeholder="输入多个以分号隔开"
class="summary-textarea"
:readonly="isReadOnly"
></textarea>
</div>
</div>
@ -266,11 +224,16 @@
</div>
<div class="right-section">
<div class="action-buttons">
<button class="action-btn">同步结果</button>
<button class="action-btn" @click="checkEditPermission">同步结果</button>
<button class="action-btn">报告预览</button>
<button class="action-btn">复检</button>
<button class="action-btn">弃检</button>
<button class="action-btn primary" @click="handleSaveResults">保存结果</button>
<button class="action-btn" @click="checkEditPermission">弃检</button>
<button
v-if="!isReadOnly"
class="action-btn primary"
@click="handleSaveResults"
>
保存结果
</button>
</div>
</div>
</div>
@ -425,6 +388,41 @@ const originalPatients = ref([]) // 保存原始患者列表
//
const patientDataCache = ref(new Map())
//
const medicalSnQuery = ref('')
//
const handleMedicalSnSearch = async () => {
if (!medicalSnQuery.value) {
ElMessage.warning('请输入体检编号')
return
}
try {
const params = {
medicalSn: medicalSnQuery.value,
pageNo: 1,
pageSize: 20
}
const res = await PatientApi.getPatientPage(params)
if (res.list && res.list.length > 0) {
patients.value = res.list
total.value = res.total
//
handlePatientSelect(res.list[0])
} else {
ElMessage.warning('未找到相关患者')
patients.value = []
total.value = 0
selectedPatient.value = null
}
} catch (error) {
console.error('查询失败:', error)
ElMessage.error('查询失败')
}
}
//
const getPatientList = async () => {
try {
@ -458,6 +456,7 @@ const getpatientitemData = async (medicalSn) => {
try {
const userProfile = await getUserProfile()
user.value = userProfile
console.log('当前登录用户信息:', userProfile)
} catch (userError) {
console.error('获取用户信息失败:', userError)
}
@ -489,7 +488,8 @@ const loadPatientData = async (patient) => {
})
try {
const [userData, patientData, itemsRes] = await Promise.all([
// ID
const [userProfile, patientData, itemsRes] = await Promise.all([
getUserProfile(),
PatientApi.getPatient(patient.id),
PatientitemsApi.getPatientitemsPage({
@ -499,14 +499,18 @@ const loadPatientData = async (patient) => {
})
])
user.value = userData
user.value = userProfile
const userDeptId = userProfile // ID
reportData.value = patientData
if (itemsRes.list && itemsRes.list.length > 0) {
examConclusion.value = itemsRes.list[0].analyse || ''
const itemsBySection = {}
itemsRes.list.forEach(item => {
//
const filteredItems = itemsRes.list.filter(item => item.sectionID == userProfile.deptId)
console.log('当前登录用户信息:',filteredItems )
filteredItems.forEach(item => {
const sectionType = '一般检查'
if (!itemsBySection[sectionType]) {
itemsBySection[sectionType] = []
@ -558,37 +562,59 @@ const loadPatientData = async (patient) => {
}
}
//
//
const getStatusNote = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const low = item.lowValue
const high = item.highValue
const [low, high] = item.reference.split('-').map(val => val === 'null' ? null : Number(val))
if (low === null || high === null) {
return ''
}
if (value < low) return '↓'
if (value > high) return '↑'
return '-'
}
//
const getRiskLevel = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const low = item.lowValue
const high = item.highValue
const [low, high] = item.reference.split('-').map(val => val === 'null' ? null : Number(val))
if (low === null || high === null) {
return ''
}
if (value < low) return '低于正常值'
if (value > high) return '高于正常值'
return '正常'
}
//
const getRowStatus = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const low = item.lowValue
const high = item.highValue
const [low, high] = item.reference.split('-').map(val => val === 'null' ? null : Number(val))
if (low === null || high === null) {
return ''
}
if (value > high) {
return 'danger'
}
else {
return ''
}
}
//
@ -694,16 +720,6 @@ onMounted(() => {
inspecttime: ''
}
customDateRange.value = []
//
const today = new Date()
selectedPeriod.value = 'today'
const todayStart = new Date(today.setHours(0, 0, 0, 0))
const todayEnd = new Date(today.setHours(23, 59, 59, 999))
customDateRange.value = [todayStart, todayEnd]
//
fetchPatientsByDate()
})
//
@ -929,38 +945,36 @@ const handleSearch = () => {
)
}
//
const isItemDisabled = (item) => {
// 使 itemStatus 2
return item.itemStatus === '2'
//
const isReadOnly = computed(() => {
return selectedPatient.value?.status === 1
})
//
const checkEditPermission = () => {
if (isReadOnly.value) {
ElMessage.warning('检查结果已保存,不可进行编辑')
return false
}
return true
}
//
const handleOperation = async ({ type, item }) => {
const handleOperation = ({ type, item }) => {
if (!checkEditPermission()) return
switch (type) {
case 'positive':
if (isItemDisabled(item)) {
ElMessage.warning('已弃检的项目不能修改')
return
}
item.positive = '阳性'
break
case 'negative':
if (isItemDisabled(item)) {
ElMessage.warning('已弃检的项目不能修改')
return
}
item.positive = '阴性'
break
case 'abandon':
// ,
if (item.itemStatus === '2') {
item.itemStatus = '0' //
item.itemStatus = '0'
ElMessage.success('已恢复正常状态')
return
}
// ,
} else {
ElMessageBox.confirm(
'确定要弃检该项目吗?弃检后将无法编辑该项目。',
'警告',
@ -970,54 +984,130 @@ const handleOperation = async ({ type, item }) => {
type: 'warning',
}
).then(() => {
item.itemStatus = '2' //
item.itemStatus = '2'
ElMessage.success('已设置为弃检')
}).catch(() => {
ElMessage.info('已取消弃检')
})
}
break
}
}
//
const handleResultChange = (item) => {
if (isItemDisabled(item)) {
ElMessage.warning('已弃检的项目不能修改')
if (!checkEditPermission()) {
item.value = item.originalValue || ''
return
}
item.itemStatus = '1' //
//
if (!item.reference || item.reference === 'null-null') {
item.note = ''
item.risk = ''
item.status = ''
return
}
const value = parseFloat(item.value)
const [low, high] = item.reference.split('-').map(Number)
const [low, high] = item.reference.split('-').map(val => val === 'null' ? null : Number(val))
if (low === null || high === null) {
item.note = ''
item.risk = ''
item.status = ''
return
}
item.note = getStatusNote({ itemResult: value, lowValue: low, highValue: high })
item.risk = getRiskLevel({ itemResult: value, lowValue: low, highValue: high })
item.status = getRowStatus({ itemResult: value, lowValue: low, highValue: high })
}
//
//
const getItemStatusText = (status) => {
const statusMap = {
'0': '未检查',
'1': '已检查',
'2': '已弃检',
'3': '待查'
}
return statusMap[status] || status
}
//
const handleSaveResults = async () => {
try {
//
const userProfile = await getUserProfile()
user.value = userProfile
//
const currentTime = new Date().getTime()
// 1.
const updatedItems = Object.values(examItems.value).flatMap(sectionItems =>
sectionItems.map(item => ({
id: item.id,
status: item.status,
itemResult: item.value || '',
positive: item.positive === '阳性' ? '1' : '0',
analyse: examConclusion.value,
inspectdoctor: user.value?.nickname || '',
itemStatus: item.itemStatus || '1', //
inspecttime: new Date().toISOString()
itemStatus: item.itemStatus,
inspecttime: currentTime
}))
)
console.log('发送的数据:', updatedItems)
await PatientitemsApi.updatePatientitemsBatch(updatedItems)
// 2.
if (selectedPatient.value) {
const patientData = {
...selectedPatient.value,
status: 1,
medicalDateTime: currentTime
}
await PatientApi.updatePatient(patientData)
// 3.
await getPatientList()
}
message.success('保存成功')
// 4.
selectedPatient.value = null
examItems.value = {}
examTabs.value = []
currentTab.value = ''
examConclusion.value = ''
patients.value = []
originalPatients.value = []
medicalSnQuery.value = '' //
searchQuery.value = '' //
reportData.value = {
medicalSn: '',
cardId: '',
pName: '',
gender: '',
birthday: '',
nationality: '',
nation: '',
race: '',
phoneNum: '',
status: 0,
reportType: '',
medicalDateTime: '',
chargeType: '',
totalPrice: 0,
headPicUrl: '',
summaryResult: '',
auditor: '',
auditorTime: ''
}
} catch (error) {
console.error('保存失败:', error)
message.error(`保存失败: ${error.message}`)
@ -1068,6 +1158,38 @@ const isImageExam = computed(() => {
})
})
//
const getStatusText = (status) => {
const statusMap = {
'0': '待检查',
'1': '已检查',
'2': '已弃检'
}
return statusMap[status] || '未知'
}
//
const getStatusTagType = (status) => {
const typeMap = {
'0': 'info', //
'1': 'success', // 绿
'2': 'danger' //
}
return typeMap[status] || ''
}
//
const formatReference = (reference) => {
if (!reference || reference === 'null-null') {
return '-'
}
const [low, high] = reference.split('-')
if (!low || !high || low === 'null' || high === 'null') {
return '-'
}
return `${low}-${high}`
}
</script>
<style scoped>
@ -1308,8 +1430,6 @@ const isImageExam = computed(() => {
flex: 1;
}
.exam-tabs {
display: flex;
}
@ -1448,6 +1568,10 @@ const isImageExam = computed(() => {
font-size: 14px;
line-height: 1.5;
background: #fff;
&:disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.summary-textarea:focus {
@ -1634,7 +1758,6 @@ const isImageExam = computed(() => {
.no-signature {
color: #909399;
font-size: 14px;
margin: 0 10px;
}
/* 添加图片展示区域样式 */
@ -1740,9 +1863,10 @@ const isImageExam = computed(() => {
/* 添加禁用状态的样式 */
.cell-input:disabled {
background-color: #ebeef5;
background-color: #f5f7fa;
cursor: not-allowed;
color: #606266;
border: none;
}
/* 修改弃检行的样式判断 */
@ -1771,4 +1895,103 @@ const isImageExam = computed(() => {
left: 5%;
}
/* 更新搜索框样式 */
.medical-sn-search {
margin-top: 10px;
}
.medical-sn-search input {
width: 100%;
padding: 6px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 13px;
}
.medical-sn-search input:focus {
border-color: #409EFF;
outline: none;
}
.status-tag {
margin-left: 8px;
font-size: 12px;
}
.patient-info {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.medical-sn {
color: #909399;
font-size: 12px;
margin-right: 4px;
}
.action-btn:disabled {
background-color: #a0cfff;
cursor: not-allowed;
opacity: 0.7;
}
:deep(.el-dropdown.is-disabled) {
opacity: 0.7;
cursor: not-allowed;
}
:deep(.el-button.is-disabled) {
background-color: #a0cfff;
cursor: not-allowed;
opacity: 0.7;
}
/* 修改只读输入框样式 */
.cell-input[readonly] {
background-color: transparent;
cursor: not-allowed;
color: #606266;
}
/* 保持按钮样式正常 */
.action-btn {
padding: 6px 16px;
border: none;
border-radius: 4px;
background: #40B6FF;
color: white;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.action-btn:hover {
opacity: 0.9;
}
.action-btn.primary {
background: #40B6FF;
}
/* 只读状态的输入框样式 */
.cell-input[readonly] {
background-color: transparent;
cursor: not-allowed;
color: #606266;
}
/* 只读状态的文本框样式 */
.summary-textarea[readonly] {
background-color: #f5f7fa;
cursor: not-allowed;
}
/* 只读状态下的按钮样式 */
.view-only {
opacity: 0.7;
cursor: not-allowed;
}
</style>

View File

@ -107,6 +107,21 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="模块名称" prop="groupname">
<el-input v-model="formData.groupname" placeholder="请输入模块名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="餐前餐后" prop="mealfrontorafter">
<el-select v-model="formData.mealfrontorafter" placeholder="请选择状态" clearable>
<el-option label="餐前" value="餐前" />
<el-option label="餐后" value="餐后" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
@ -141,7 +156,10 @@ const formData = ref<Partial<itemsVO>>({
highValue: undefined,
lowValue: undefined,
moduleID: undefined,
sectionID: ''
sectionID: '',
groupname: '',
mealfrontorafter: '',
groupcode: ''
})
//
@ -186,9 +204,10 @@ const handleSubmit = async () => {
formData.value.sectionID = section.split('|')[0]
formData.value.section = section.split('|')[1]
}
formData.value.groupcode = Date.now().toString()
await itemsApi.createitems(formData.value as itemsVO)
ElMessage.success('添加成功')
// success
emit('success')
handleClose()
} catch (error) {
@ -212,7 +231,11 @@ const handleClose = () => {
moduleName: '',
highValue: undefined,
lowValue: undefined,
moduleID: undefined
moduleID: undefined,
sectionID: '',
groupname: '',
mealfrontorafter: '',
groupcode: ''
}
visible.value = false
}

View File

@ -99,6 +99,22 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="模块名称" prop="groupname">
<el-input v-model="formData.groupname" placeholder="请输入模块名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="餐前餐后" prop="mealfrontorafter">
<el-select v-model="formData.mealfrontorafter" placeholder="请选择状态" clearable>
<el-option label="餐前" value="餐前" />
<el-option label="餐后" value="餐后" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
@ -123,7 +139,22 @@ const visible = ref(false)
const formRef = ref<FormInstance>()
const departmentOptions = ref<{ value: string; label: string }[]>([])
const formData = ref<Partial<itemsVO>>({})
const formData = ref<Partial<itemsVO>>({
itemName: '',
itemCode: '',
price: undefined,
discounted: undefined,
section: '',
unit: '',
moduleName: '',
highValue: undefined,
lowValue: undefined,
moduleID: undefined,
sectionID: '',
groupname: '',
mealfrontorafter: '',
groupcode: ''
})
const formRules = {
section: [{ required: true, message: '请选择所属科室', trigger: 'change' }],
@ -151,7 +182,6 @@ const handleSubmit = async () => {
await formRef.value.validate(async (valid) => {
if (valid) {
try {
if (formData.value.moduleName) {
const moduleName = formData.value.moduleName
@ -159,11 +189,13 @@ const handleSubmit = async () => {
formData.value.moduleID = parseInt(moduleName.split('|')[1])
}
if (formData.value.section) {
const section = formData.value.section
formData.value.section = section.split('|')[0]
formData.value.sectionID = section.split('|')[1]
}
// groupcode
formData.value.groupcode = Date.now().toString()
console.log('section', formData.value.sectionID)
await itemsApi.updateitems(formData.value as itemsVO)
ElMessage.success('修改成功')
@ -179,7 +211,22 @@ const handleSubmit = async () => {
const handleClose = () => {
formRef.value?.resetFields()
formData.value = {}
formData.value = {
itemName: '',
itemCode: '',
price: undefined,
discounted: undefined,
section: '',
unit: '',
moduleName: '',
highValue: undefined,
lowValue: undefined,
moduleID: undefined,
sectionID: '',
groupname: '',
mealfrontorafter: '',
groupcode: ''
}
visible.value = false
}