Files
his/openhis-ui-vue3/src/views/basicmanage/outpatientNoManagement/index.vue

1086 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div class="outpatient-no-management-wrapper">
<!-- Windows XP风格窗口布局全屏显示 -->
<div class="outpatient-no-management">
<!--标题栏32px高 -->
<div class="title-bar">
<span class="title-text">门诊号码管理</span>
</div>
<!-- 功能按钮区40px高 -->
<div class="button-bar">
<el-row :gutter="10">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="onAdd">新设(A)</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="onDelete">删除(D)</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Check" @click="() => onSave()">保存(S)</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Close" @click="onClose">关闭(X)</el-button>
</el-col>
<el-col v-if="canToggleViewAll" :span="4">
<el-switch
v-model="viewAll"
active-text="查看全部"
inactive-text="仅本人"
@change="getList"
/>
</el-col>
</el-row>
</div>
<!-- 表格内容区自适应剩余高度 -->
<div class="table-content">
<el-table
v-loading="loading"
:data="tableData"
@selection-change="handleSelectionChange"
:row-class-name="tableRowClassName"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="操作员" prop="operatorName" min-width="120" />
<el-table-column label="员工工号" prop="staffNo" min-width="120" />
<el-table-column label="领用日期" prop="receiveDate" min-width="140">
<template #default="{ row }">
{{ formatReceiveDate(row.receiveDate) }}
</template>
</el-table-column>
<el-table-column label="起始号码" prop="startNo" min-width="140" />
<el-table-column label="终止号码" prop="endNo" min-width="140" />
<el-table-column label="使用号码" prop="usedNo" min-width="140" />
<el-table-column label="操作" width="120" align="center" fixed="right">
<template #default="{ row }">
<el-button
type="primary"
link
size="small"
@click="handleEdit(row)"
>
编辑
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
<!-- 编辑弹窗 -->
<el-dialog
v-model="editDialogVisible"
title="编辑门诊号码段"
width="600px"
:close-on-click-modal="false"
>
<el-form
ref="editFormRef"
:model="editForm"
:rules="editFormRules"
label-width="120px"
>
<el-form-item label="操作员" prop="operatorName">
<el-input v-model="editForm.operatorName" disabled />
</el-form-item>
<el-form-item label="员工工号" prop="staffNo">
<el-input v-model.trim="editForm.staffNo" />
</el-form-item>
<el-form-item label="领用日期" prop="receiveDate">
<el-date-picker
v-model="editForm.receiveDate"
type="date"
value-format="YYYY.MM.DD"
placeholder="选择日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="起始号码" prop="startNo">
<el-input
v-model.trim="editForm.startNo"
@input="onEditFormStartNoChange"
@blur="validateEditFormField('startNo')"
/>
</el-form-item>
<el-form-item label="终止号码" prop="endNo">
<el-input
v-model.trim="editForm.endNo"
@blur="validateEditFormField('endNo')"
/>
</el-form-item>
<el-form-item label="使用号码" prop="usedNo">
<el-input
v-model.trim="editForm.usedNo"
@blur="validateEditFormField('usedNo')"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveEditForm">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup name="outpatientNoManagement">
import { ref, reactive, toRefs, onActivated, getCurrentInstance } from 'vue'
import useUserStore from '@/store/modules/user'
import { getConfigKey } from '@/api/system/config'
import { logQuery, logCreate, logUpdate, logDelete } from './components/operationLog'
import { listOutpatientNo, addOutpatientNo, updateOutpatientNo, deleteOutpatientNo } from './components/outpatientNumber'
const { proxy } = getCurrentInstance()
const userStore = useUserStore()
// 获取当前用户信息(用于日志记录)
const getUserInfo = () => ({
id: userStore.id,
name: userStore.name || userStore.nickName
})
// 格式化领用日期为 YYYY.MM.DD 格式(用于显示)
function formatReceiveDate(dateStr) {
if (!dateStr) return ''
// 如果是 YYYY-MM-DD 格式,转换为 YYYY.MM.DD
if (dateStr.includes('-')) {
return dateStr.replace(/-/g, '.')
}
// 如果已经是 YYYY.MM.DD 格式,直接返回
if (dateStr.includes('.')) {
return dateStr
}
return dateStr
}
// 将日期格式从 YYYY.MM.DD 转换为 yyyy-MM-dd用于发送到后端
function convertDateForBackend(dateStr) {
if (!dateStr) return null
// 如果是 YYYY.MM.DD 格式,转换为 yyyy-MM-dd
if (dateStr.includes('.')) {
return dateStr.replace(/\./g, '-')
}
// 如果已经是 yyyy-MM-dd 格式,直接返回
if (dateStr.includes('-')) {
return dateStr
}
return dateStr
}
const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const ids = ref([])
const multiple = ref(true)
const viewAll = ref(false)
const canToggleViewAll = ref(false)
// 编辑弹窗相关
const editDialogVisible = ref(false)
const editFormRef = ref(null)
const editForm = reactive({
id: null,
operatorId: null,
operatorName: '',
staffNo: '',
receiveDate: '',
startNo: '',
endNo: '',
usedNo: '',
_originalData: null,
})
// 编辑表单验证规则
const editFormRules = {
staffNo: [{ required: true, message: '请输入员工工号', trigger: 'blur' }],
receiveDate: [{ required: true, message: '请选择领用日期', trigger: 'change' }],
startNo: [{ required: true, message: '请输入起始号码', trigger: 'blur' }],
endNo: [{ required: true, message: '请输入终止号码', trigger: 'blur' }],
usedNo: [{ required: true, message: '请输入使用号码', trigger: 'blur' }],
}
const data = reactive({
queryParams: {
pageNo: 1,
pageSize: 10,
onlySelf: true,
},
})
const { queryParams } = toRefs(data)
initConfig()
getList()
// 解决从标签页关闭后再次进入页面空白的问题:
// 当页面被 keep-alive 缓存后再次激活,主动刷新列表
onActivated(() => {
getList()
})
async function initConfig() {
try {
const res = await getConfigKey('outpatient_no_view_all')
canToggleViewAll.value = (res?.msg === 'Y' || res?.data === 'Y')
} catch (e) {
canToggleViewAll.value = false
}
}
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id)
multiple.value = !selection.length
}
function onAdd() {
const now = new Date()
const yyyy = now.getFullYear()
const mm = String(now.getMonth() + 1).padStart(2, '0')
const dd = String(now.getDate()).padStart(2, '0')
// 打开编辑弹窗,用于新增
editForm.id = undefined
editForm.operatorId = userStore.id
editForm.operatorName = userStore.name || userStore.nickName
editForm.staffNo = userStore.id
editForm.receiveDate = `${yyyy}.${mm}.${dd}`
editForm.startNo = ''
editForm.endNo = ''
editForm.usedNo = ''
editForm._originalData = null
editDialogVisible.value = true
}
// 编辑行 - 打开编辑弹窗
function handleEdit(row) {
// 复制行数据到编辑表单
editForm.id = row.id
editForm.operatorId = row.operatorId
editForm.operatorName = row.operatorName
editForm.staffNo = row.staffNo
editForm.receiveDate = formatReceiveDate(row.receiveDate)
editForm.startNo = row.startNo
editForm.endNo = row.endNo
editForm.usedNo = row.usedNo
editForm._originalData = { ...row }
editDialogVisible.value = true
}
// 编辑表单中起始号码变化时自动设置使用号码
function onEditFormStartNoChange() {
if (!editForm.id && editForm.startNo) {
editForm.usedNo = editForm.startNo
}
}
// 验证编辑表单字段
function validateEditFormField(field) {
if (!isTailDigitsValid(editForm[field])) {
const msg = `最大位数为12位且必须以数字结尾`
alertWarn(msg)
return false
}
return true
}
// 保存编辑表单
async function handleSaveEditForm() {
// 表单验证
if (!editFormRef.value) return
try {
const valid = await editFormRef.value.validate()
if (!valid) return
} catch (error) {
return
}
// 字段验证
if (!validateEditFormField('startNo') || !validateEditFormField('endNo') || !validateEditFormField('usedNo')) {
return
}
// 构建验证用的行对象
const validateRowData = {
startNo: editForm.startNo,
endNo: editForm.endNo,
usedNo: editForm.usedNo,
}
// 验证行数据(编辑时排除当前记录的 id避免误判为重复
const rowIndex = editForm.id ? tableData.value.findIndex(r => r.id === editForm.id) : -1
if (!validateRow(validateRowData, rowIndex, editForm.id)) {
return
}
// 准备保存的数据
const saveData = {
id: editForm.id,
operatorId: editForm.operatorId,
operatorName: editForm.operatorName,
staffNo: editForm.staffNo,
receiveDate: convertDateForBackend(editForm.receiveDate),
startNo: editForm.startNo,
endNo: editForm.endNo,
usedNo: editForm.usedNo,
}
try {
let res
if (saveData.id) {
// 更新
res = await updateOutpatientNo(saveData)
} else {
// 新增
res = await addOutpatientNo(saveData)
}
if (res.code === 200) {
proxy.$modal.msgSuccess('保存成功')
editDialogVisible.value = false
getList()
} else {
// 显示后端返回的错误信息
const errorMsg = res.msg || res.message || '保存失败'
proxy.$modal.msgError(errorMsg)
if (saveData.id) {
logUpdate(saveData, false, errorMsg, getUserInfo())
} else {
logCreate(saveData, false, errorMsg, getUserInfo())
}
}
} catch (error) {
console.error('保存失败:', error)
// 从错误对象中提取错误信息
let errorMsg = '保存失败'
// 优先从 response.data.msg 获取
if (error.response?.data?.msg) {
errorMsg = error.response.data.msg
}
// 其次从 error.message 获取request.js 会通过 new Error(msg) 抛出)
else if (error.message) {
// 如果 error.message 包含 "Error: " 前缀,去掉它
errorMsg = error.message.replace(/^Error:\s*/, '')
}
// 最后尝试从 error.msg 获取
else if (error.msg) {
errorMsg = error.msg
}
// 显示错误信息
proxy.$modal.msgError(errorMsg)
// 记录日志
if (saveData.id) {
logUpdate(saveData, false, errorMsg, getUserInfo())
} else {
logCreate(saveData, false, errorMsg, getUserInfo())
}
}
}
// 新增时,起始号码变化时自动设置使用号码为起始号码
function onStartNoChange(row) {
if (!row.id && row._editing) {
row.usedNo = row.startNo
}
}
function onClose() {
// 检查是否有未保存的数据变动
const hasUnsavedChanges = tableData.value.some(row => row._dirty || row._editing)
if (hasUnsavedChanges) {
// 有未保存的数据,提示用户
const message = '窗口数据有变动是否进行保存操作?'
if (proxy.$modal?.confirm) {
proxy.$modal.confirm(message).then(() => {
// 用户选择保存
onSave()
// 等待保存完成后关闭页面
setTimeout(() => {
proxy.$tab.closePage()
}, 800)
}).catch(() => {
// 用户选择不保存,直接关闭
proxy.$tab.closePage()
})
} else {
// 降级方案:使用原生 confirm
if (confirm(message)) {
onSave()
setTimeout(() => {
proxy.$tab.closePage()
}, 800)
} else {
proxy.$tab.closePage()
}
}
} else {
// 没有未保存的数据,直接关闭
proxy.$tab.closePage()
}
}
function tableRowClassName({ row }) {
return row._error ? 'error-row' : ''
}
// 字母前缀识别规则 - 从末位往前找到第一个字母
function extractPrefix(value) {
if (!value) return ''
const chars = value.split('')
for (let i = chars.length - 1; i >= 0; i--) {
if (/[A-Za-z]/.test(chars[i])) {
return value.slice(0, i + 1) // 包含找到的字母
}
}
return ''
}
function extractTailNumber(value) {
if (!value) return NaN
const m = value.match(/(\d+)$/)
if (!m) return NaN
return parseInt(m[1], 10)
}
function lengthWithinLimit(value) {
if (!value) return false
const m = value.match(/(\d+)$/)
if (!m) return false
return m[1].length <= 12
}
function rangesOverlap(aStart, aEnd, bStart, bEnd) {
return Math.max(aStart, bStart) <= Math.min(aEnd, bEnd)
}
function alertWarn(msg) {
if (proxy.$modal && proxy.$modal.alertWarning) {
proxy.$modal.alertWarning(msg)
} else if (proxy.$message) {
proxy.$message.warning(msg)
}
}
// 校验必须以数字结尾且尾部数字长度≤12
function isTailDigitsValid(value) {
const m = String(value || '').match(/(\d+)$/)
return !!m && m[1].length <= 12
}
function validateNumField(row, field, rowIndex) {
if (!isTailDigitsValid(row[field])) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中最大位数为12位且必须以数字结尾` : '最大位数为12位且必须以数字结尾'
alertWarn(msg)
row._error = true
row._warned = row._warned || {}
row._warned[field] = true
return false
}
row._error = false
row._warned = row._warned || {}
row._warned[field] = false
return true
}
function onNumberInput(row, field) {
row._warned = row._warned || {}
const valid = isTailDigitsValid(row[field])
if (!valid && !row._warned[field]) {
alertWarn('最大位数为12位且必须以数字结尾')
row._warned[field] = true
}
if (valid) {
row._warned[field] = false
}
}
function validateRow(row, rowIndex, excludeId = null) {
row._error = false
if (!lengthWithinLimit(row.startNo) || !lengthWithinLimit(row.endNo) || !lengthWithinLimit(row.usedNo)) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中最大位数为12位且必须以数字结尾` : '最大位数为12位且必须以数字结尾'
alertWarn(msg)
row._error = true
return false
}
if ((row.startNo?.length || 0) !== (row.endNo?.length || 0)) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中,起始号码与终止号码长度必须一致,请修改!` : '起始号码与终止号码长度必须一致'
alertWarn(msg)
row._error = true
return false
}
const p1 = extractPrefix(row.startNo)
const p2 = extractPrefix(row.endNo)
const p3 = extractPrefix(row.usedNo)
if (!(p1 === p2 && p2 === p3)) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码的字母前缀必须相同,请修改!` : '行数据中,门诊号码的字母前缀必须相同,请修改!'
alertWarn(msg)
row._error = true
return false
}
const sNum = extractTailNumber(row.startNo)
const eNum = extractTailNumber(row.endNo)
if (Number.isNaN(sNum) || Number.isNaN(eNum) || sNum > eNum) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中,起始/终止号码不合法` : '起始/终止号码不合法'
alertWarn(msg)
row._error = true
return false
}
// 放宽:不再强制"使用号码"必须处于起始与终止范围内
const prefix = p1
for (let i = 0; i < tableData.value.length; i++) {
const other = tableData.value[i]
// 跳过自身:通过 rowIndex、row 对象比较或 excludeId 排除
if ((typeof rowIndex === 'number' && i === rowIndex) ||
other === row ||
!other.startNo ||
!other.endNo ||
(excludeId && other.id === excludeId)) continue
if (extractPrefix(other.startNo) !== prefix) continue
const os = extractTailNumber(other.startNo)
const oe = extractTailNumber(other.endNo)
if (!Number.isNaN(os) && !Number.isNaN(oe)) {
if (rangesOverlap(sNum, eNum, os, oe)) {
const idxInTable = typeof rowIndex === 'number' ? rowIndex : tableData.value.indexOf(row)
const lineNo = idxInTable >= 0 ? idxInTable + 1 : undefined
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码和【${i + 1}】行的门诊号码有冲突,请修改!` : '门诊号码设置重复!'
alertWarn(msg)
row._error = true
return false
}
}
}
return true
}
async function onSave(row) {
const rows = row ? [row] : tableData.value.filter(r => ids.value.includes(r.id) || r._dirty || r._editing)
if (!rows.length) {
proxy.$modal.msgWarning('没有可保存的数据')
return
}
// 前端校验
for (const r of rows) {
const idx = tableData.value.indexOf(r)
if (!validateRow(r, idx, r.id)) return
}
// 准备保存的数据(将日期格式转换为后端需要的格式)
const saveData = rows.map((r) => ({
id: r.id,
operatorId: r.operatorId,
operatorName: r.operatorName,
staffNo: r.staffNo,
receiveDate: convertDateForBackend(r.receiveDate), // 转换为 yyyy-MM-dd 格式
startNo: r.startNo,
endNo: r.endNo,
usedNo: r.usedNo,
}))
// 批量保存
let successCount = 0
let failCount = 0
for (const record of saveData) {
try {
let res
if (record.id) {
// 更新
res = await updateOutpatientNo(record)
if (res.code === 200) {
logUpdate(record, true, null, getUserInfo())
successCount++
} else {
const errorMsg = res.msg || res.message || '保存失败'
proxy.$modal.msgError(errorMsg)
logUpdate(record, false, errorMsg, getUserInfo())
failCount++
}
} else {
// 新增
res = await addOutpatientNo(record)
if (res.code === 200) {
logCreate(record, true, null, getUserInfo())
successCount++
} else {
const errorMsg = res.msg || res.message || '保存失败'
proxy.$modal.msgError(errorMsg)
logCreate(record, false, errorMsg, getUserInfo())
failCount++
}
}
} catch (error) {
console.error('保存失败:', error)
// 从错误对象中提取错误信息
let errorMsg = '保存失败'
if (error.response?.data?.msg) {
errorMsg = error.response.data.msg
} else if (error.message) {
errorMsg = error.message
} else if (error.msg) {
errorMsg = error.msg
}
proxy.$modal.msgError(errorMsg)
if (record.id) {
logUpdate(record, false, errorMsg, getUserInfo())
} else {
logCreate(record, false, errorMsg, getUserInfo())
}
failCount++
}
}
if (successCount > 0) {
proxy.$modal.msgSuccess(`保存成功${successCount}`)
// 保存成功后,退出编辑状态
rows.forEach(r => {
r._editing = false
r._dirty = false
r._originalData = null // 清除原始数据
})
}
if (failCount > 0) {
proxy.$modal.msgError(`保存失败${failCount}`)
}
getList()
}
async function onDelete() {
console.log('删除操作 - 选中的ID列表:', ids.value)
console.log('删除操作 - 表格数据:', tableData.value.map(r => ({ id: r.id, operatorId: r.operatorId })))
const rows = tableData.value.filter((r) => ids.value.includes(r.id))
console.log('删除操作 - 筛选后的行数据:', rows.map(r => ({ id: r.id, operatorId: r.operatorId })))
if (!rows.length) {
proxy.$modal.msgWarning('请选择要删除的数据')
return
}
// 前端预校验(归属权+使用状态)
for (const r of rows) {
console.log('检查删除权限 - 行数据:', {
id: r.id,
operatorId: r.operatorId,
operatorIdType: typeof r.operatorId,
userStoreId: userStore.id,
userStoreIdType: typeof userStore.id,
usedNo: r.usedNo,
startNo: r.startNo,
usedNoType: typeof r.usedNo,
startNoType: typeof r.startNo
})
const canDeleteSelf = String(r.operatorId) === String(userStore.id)
// 确保字符串比较,避免类型问题
const neverUsed = String(r.usedNo || '') === String(r.startNo || '')
if (!canDeleteSelf) {
console.warn('删除权限检查失败:', {
operatorId: r.operatorId,
userStoreId: userStore.id,
canDeleteSelf
})
alertWarn('只能删除自己维护的门诊号码段')
logDelete(rows, false, '只能删除自己维护的门诊号码段', getUserInfo())
return
}
if (!neverUsed) {
console.warn('使用状态检查失败:', {
usedNo: r.usedNo,
startNo: r.startNo,
neverUsed
})
alertWarn('已有门诊号码段已有使用的门诊号码,请核对!')
logDelete(rows, false, '已有门诊号码段已有使用的门诊号码', getUserInfo())
return
}
}
const doRealDelete = async () => {
try {
// 处理大整数 ID保持为字符串或使用 BigInt避免精度丢失
// JavaScript 的 Number.MAX_SAFE_INTEGER = 9007199254740991
// 如果 ID 超过这个值,转换为数字会丢失精度
const idsToDelete = rows
.map((r) => r.id)
.filter(id => id != null && id !== undefined)
.map(id => {
// 如果 ID 是字符串,检查是否需要转换为数字
if (typeof id === 'string') {
// 尝试转换为数字,但如果超过安全整数范围,保持为字符串
const numId = parseInt(id, 10)
if (!isNaN(numId) && numId <= Number.MAX_SAFE_INTEGER) {
return numId
}
// 大整数保持为字符串,后端应该能处理
return id
}
// 如果已经是数字,检查是否超过安全范围
if (typeof id === 'number') {
if (id > Number.MAX_SAFE_INTEGER) {
// 超过安全范围,转换为字符串
return String(id)
}
return id
}
// 其他类型,尝试转换
return id
})
.filter(id => id != null && id !== undefined)
if (idsToDelete.length === 0) {
proxy.$modal.msgWarning('没有可删除的数据')
return
}
console.log('准备删除的ID列表:', idsToDelete)
console.log('删除请求数据:', JSON.stringify({ ids: idsToDelete }))
console.log('删除请求数据类型:', idsToDelete.map(id => ({ value: id, type: typeof id, stringValue: String(id) })))
const res = await deleteOutpatientNo({ ids: idsToDelete })
console.log('删除响应:', res)
console.log('删除响应code:', res?.code)
console.log('删除响应msg:', res?.msg)
if (res && (res.code === 200 || res.code === 0)) {
logDelete(rows, true, null, getUserInfo())
proxy.$modal.msgSuccess('删除成功')
getList()
} else {
const errorMsg = res?.msg || res?.message || '删除失败'
logDelete(rows, false, errorMsg, getUserInfo())
proxy.$modal.msgError(errorMsg)
}
} catch (error) {
console.error('删除失败:', error)
// 从错误对象中提取错误信息
let errorMsg = '删除失败'
// 优先从 response.data.msg 获取
if (error.response?.data?.msg) {
errorMsg = error.response.data.msg
}
// 其次从 error.message 获取request.js 会通过 new Error(msg) 抛出)
else if (error.message) {
// 如果 error.message 包含 "Error: " 前缀,去掉它
errorMsg = error.message.replace(/^Error:\s*/, '')
}
// 最后尝试从 error.msg 获取
else if (error.msg) {
errorMsg = error.msg
}
// 显示错误信息(参考 PackageManagement 的实现方式)
proxy.$modal.msgError('删除失败: ' + errorMsg)
// 记录日志
logDelete(rows, false, errorMsg, getUserInfo())
}
}
if (proxy.$modal?.confirm) {
proxy.$modal.confirm('是否确认删除选中数据项?').then(doRealDelete).catch(() => {
// 用户取消删除,不记录日志
})
} else {
doRealDelete()
}
}
function getList() {
loading.value = true
queryParams.value.onlySelf = !viewAll.value
// 调用后端API
listOutpatientNo(queryParams.value).then((res) => {
if (res.code === 200) {
tableData.value = (res.data?.records || res.data || []).map((it) => {
// 处理大整数 ID如果 ID 超过 JavaScript 安全整数范围,保持为字符串
let id = it.id
if (typeof id === 'number' && id > Number.MAX_SAFE_INTEGER) {
// 数字超过安全范围,转换为字符串以避免精度丢失
id = String(id)
} else if (typeof id === 'number') {
// 数字在安全范围内,保持为数字
id = id
} else {
// 已经是字符串或其他类型,保持原样
id = id
}
return {
...it,
id: id, // 确保 ID 正确处理
_editing: false,
_error: false,
_dirty: false,
// 确保日期格式正确:后端返回 yyyy-MM-dd转换为 YYYY.MM.DD 用于显示
receiveDate: it.receiveDate ? formatReceiveDate(it.receiveDate) : ''
}
})
total.value = res.data?.total || res.data?.length || 0
// 记录查询操作日志
logQuery(total.value, getUserInfo())
} else {
proxy.$modal.msgError(res.msg || '查询失败')
}
loading.value = false
}).catch((error) => {
console.error('查询门诊号码段失败:', error)
proxy.$modal.msgError('查询失败,请稍后重试')
loading.value = false
})
}
</script>
<style scoped>
/*Windows XP风格布局 - 全屏显示 */
/* 外层容器 - 全屏显示 */
.outpatient-no-management-wrapper {
width: 100%;
height: calc(100vh - 84px);
background-color: #f0f0f0;
padding: 0;
margin: 0;
}
/* 主容器 - 全屏显示 */
.outpatient-no-management {
width: 100%;
height: 100%;
background-color: #D4D0C8;
border: 1px solid #000000;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 标题栏32px高背景色#D4D0C8 */
.title-bar {
height: 32px;
background: linear-gradient(to bottom, #0055E5 0%, #0F3D8C 100%);
border-bottom: 1px solid #000000;
display: flex;
align-items: center;
padding: 0 8px;
}
/* 标题文本14px/700左对齐 */
.title-text {
font-size: 14px;
font-weight: 700;
color: #FFFFFF;
letter-spacing: 0.5px;
}
/* 功能按钮区40px高 */
.button-bar {
height: 40px;
background-color: #D4D0C8;
border-bottom: 1px solid #808080;
display: flex;
align-items: center;
padding: 0 8px;
}
.button-bar .el-row {
width: 100%;
}
/* 按钮样式90x32px1px边框圆角0背景色#EFEFEF */
.button-bar :deep(.el-button) {
width: 90px;
height: 32px;
border-radius: 0;
border: 1px solid #808080;
font-size: 13px;
padding: 0;
}
/* 新设按钮 - 主要操作 */
.button-bar :deep(.el-button--primary) {
background: linear-gradient(to bottom, #FFFFFF 0%, #EFEFEF 50%, #DFDFDF 100%);
color: #000000;
border-top: 1px solid #FFFFFF;
border-left: 1px solid #FFFFFF;
border-right: 1px solid #808080;
border-bottom: 1px solid #808080;
}
.button-bar :deep(.el-button--primary:hover) {
background: linear-gradient(to bottom, #FFFEF8 0%, #F5F4EF 50%, #E5E4DF 100%);
}
/* 删除按钮 */
.button-bar :deep(.el-button--danger) {
background: linear-gradient(to bottom, #FFFFFF 0%, #EFEFEF 50%, #DFDFDF 100%);
color: #000000;
border-top: 1px solid #FFFFFF;
border-left: 1px solid #FFFFFF;
border-right: 1px solid #808080;
border-bottom: 1px solid #808080;
}
/* 保存按钮 */
.button-bar :deep(.el-button--success) {
background: linear-gradient(to bottom, #FFFFFF 0%, #EFEFEF 50%, #DFDFDF 100%);
color: #000000;
border-top: 1px solid #FFFFFF;
border-left: 1px solid #FFFFFF;
border-right: 1px solid #808080;
border-bottom: 1px solid #808080;
}
/* 关闭按钮(红色背景,白色文字) */
.button-bar :deep(.el-button--warning) {
background: linear-gradient(to bottom, #FF6B6B 0%, #EE5A5A 50%, #DD4949 100%);
color: #FFFFFF;
font-weight: 600;
border-top: 1px solid #FF9999;
border-left: 1px solid #FF9999;
border-right: 1px solid #AA3333;
border-bottom: 1px solid #AA3333;
}
.button-bar :deep(.el-button--warning:hover) {
background: linear-gradient(to bottom, #FF7B7B 0%, #FE6A6A 50%, #ED5959 100%);
}
/* 按钮禁用状态 */
.button-bar :deep(.el-button:disabled) {
background: #D4D0C8;
color: #808080;
cursor: not-allowed;
}
/*表格内容区(自适应剩余高度) */
.table-content {
flex: 1;
background-color: #FFFFFF;
padding: 8px;
overflow: auto;
min-height: 0;
display: flex;
flex-direction: column;
}
/* 表格样式1px实线边框#CCCCCC表头背景#F0F0F0 */
.table-content :deep(.el-table) {
border: 1px solid #CCCCCC;
font-size: 13px;
flex: 1;
display: flex;
flex-direction: column;
}
.table-content :deep(.el-table th) {
background: linear-gradient(to bottom, #FFFFFF 0%, #F0F0F0 100%);
border: 1px solid #CCCCCC;
color: #000000;
font-weight: 600;
font-size: 13px;
padding: 8px 4px;
}
.table-content :deep(.el-table td) {
border: 1px solid #CCCCCC;
padding: 6px 4px;
font-size: 13px;
}
.table-content :deep(.el-table__body tr:hover > td) {
background-color: #E5F3FF !important;
}
/* 错误行样式 */
:deep(.error-row) {
--el-table-tr-bg-color: #fff7e6;
}
/* 分页样式 */
.table-content :deep(.pagination-container) {
margin-top: 10px;
padding: 10px 0;
border-top: 1px solid #CCCCCC;
}
/* 输入框样式 */
.table-content :deep(.el-input__inner) {
border: 1px solid #7FB4FF;
border-radius: 0;
font-size: 13px;
}
.table-content :deep(.el-input__inner:focus) {
border: 2px solid #0055E5;
}
/* 日期选择器样式 */
.table-content :deep(.el-date-editor) {
width: 100%;
}
/* 开关样式 */
.button-bar :deep(.el-switch) {
height: 24px;
}
/* 滚动条样式Windows XP风格 */
.table-content::-webkit-scrollbar {
width: 16px;
height: 16px;
}
.table-content::-webkit-scrollbar-track {
background-color: #D4D0C8;
border: 1px solid #808080;
}
.table-content::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, #FFFFFF 0%, #EFEFEF 50%, #DFDFDF 100%);
border: 1px solid #808080;
}
.table-content::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom, #FFFEF8 0%, #F5F4EF 50%, #E5E4DF 100%);
}
/* 表格容器样式调整 */
.table-content :deep(.el-table__body-wrapper) {
flex: 1;
overflow: auto;
}
</style>