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

824 lines
24 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>
<!-- Windows XP风格窗口布局600px固定宽度 -->
<div class="outpatient-no-management-wrapper">
<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 }">
<el-date-picker
v-if="row._editing"
v-model="row.receiveDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
/>
<span v-else>{{ row.receiveDate }}</span>
</template>
</el-table-column>
<el-table-column label="起始号码" prop="startNo" min-width="140">
<template #default="{ row }">
<el-input
v-if="row._editing"
v-model.trim="row.startNo"
@input="() => onStartNoChange(row)"
@blur="() => validateNumField(row, 'startNo')"
/>
<span v-else>{{ row.startNo }}</span>
</template>
</el-table-column>
<el-table-column label="终止号码" prop="endNo" min-width="140">
<template #default="{ row }">
<el-input
v-if="row._editing"
v-model.trim="row.endNo"
@blur="() => validateNumField(row, 'endNo')"
/>
<span v-else>{{ row.endNo }}</span>
</template>
</el-table-column>
<el-table-column label="使用号码" prop="usedNo" min-width="140">
<template #default="{ row }">
<el-input
v-if="row._editing"
v-model.trim="row.usedNo"
@blur="() => validateNumField(row, 'usedNo')"
/>
<span v-else>{{ row.usedNo }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="scope">
<el-button type="primary" link icon="Edit" @click="() => openEdit(scope.row, scope.$index)">编辑</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>
</div>
<!-- 编辑弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" append-to-body>
<el-form label-width="100px">
<el-form-item label="操作员">
<el-input v-model="editForm.operatorName" disabled />
</el-form-item>
<el-form-item label="员工工号">
<el-input v-model="editForm.staffNo" disabled />
</el-form-item>
<el-form-item label="领用日期">
<el-date-picker v-model="editForm.receiveDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
</el-form-item>
<el-form-item label="起始号码">
<el-input v-model.trim="editForm.startNo" @blur="() => validateNumField(editForm, 'startNo')" />
</el-form-item>
<el-form-item label="终止号码">
<el-input v-model.trim="editForm.endNo" @blur="() => validateNumField(editForm, 'endNo')" />
</el-form-item>
<el-form-item label="使用号码">
<el-input v-model.trim="editForm.usedNo" @blur="() => validateNumField(editForm, 'usedNo')" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmEdit"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup name="outpatientNoManagement">
import useUserStore from '@/store/modules/user'
import { getConfigKey } from '@/api/system/config'
import { logQuery, logCreate, logUpdate, logDelete } from './components/operationLog'
const { proxy } = getCurrentInstance()
const userStore = useUserStore()
// 获取当前用户信息(用于日志记录)
const getUserInfo = () => ({
id: userStore.id,
name: userStore.name || userStore.nickName
})
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 dialogVisible = ref(false)
const dialogTitle = ref('编辑门诊号码段')
const editIndex = ref(-1)
const editForm = reactive({
receiveDate: '',
startNo: '',
endNo: '',
usedNo: '',
operatorName: '',
staffNo: '',
})
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')
tableData.value.push({
id: undefined,
operatorId: userStore.id,
operatorName: userStore.name || userStore.nickName,
staffNo: userStore.id,
receiveDate: `${yyyy}-${mm}-${dd}`,
startNo: '',
endNo: '',
usedNo: '',
_editing: true,
_error: false,
})
}
// 新增时,起始号码变化时自动设置使用号码为起始号码
function onStartNoChange(row) {
if (!row.id && row._editing) {
row.usedNo = row.startNo
}
}
function onClose() {
proxy.$tab.closePage()
}
function tableRowClassName({ row }) {
return row._error ? 'error-row' : ''
}
function openEdit(row, index) {
editIndex.value = index
dialogTitle.value = '编辑门诊号码段'
editForm.receiveDate = row.receiveDate
editForm.startNo = row.startNo
editForm.endNo = row.endNo
editForm.usedNo = row.usedNo
editForm.operatorName = row.operatorName
editForm.staffNo = row.staffNo
dialogVisible.value = true
}
function confirmEdit() {
const tmp = { ...tableData.value[editIndex.value], ...editForm }
if (!validateRow(tmp, editIndex.value)) return
tableData.value[editIndex.value] = {
...tableData.value[editIndex.value],
...editForm,
_dirty: true, // 标记为已修改,顶部保存时提交
}
dialogVisible.value = false
}
// 字母前缀识别规则 - 从末位往前找到第一个字母
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 : (editIndex.value >= 0 ? editIndex.value + 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) {
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 : (editIndex.value >= 0 ? editIndex.value + 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 : (editIndex.value >= 0 ? editIndex.value + 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 : (editIndex.value >= 0 ? editIndex.value + 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 : (editIndex.value >= 0 ? editIndex.value + 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]
// 跳过自身:当从弹窗校验时 row 为临时对象,需用下标判断
if ((typeof rowIndex === 'number' && i === rowIndex) || other === row || !other.startNo || !other.endNo) 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 : (editIndex.value >= 0 ? editIndex.value + 1 : undefined)
const msg = lineNo ? `第【${lineNo}】行数据中,门诊号码和【${i + 1}】行的门诊号码有冲突,请修改!` : '门诊号码设置重复!'
alertWarn(msg)
row._error = true
return false
}
}
}
return true
}
function onSave(row) {
const rows = row ? [row] : tableData.value.filter(r => ids.value.includes(r.id) || r._dirty || r._editing)
if (!rows.length) return
for (const r of rows) {
const idx = tableData.value.indexOf(r)
if (!validateRow(r, idx)) return
}
// 准备保存的数据
const saveData = rows.map((r) => ({
id: r.id,
operatorId: r.operatorId,
operatorName: r.operatorName,
staffNo: r.staffNo,
receiveDate: r.receiveDate,
startNo: r.startNo,
endNo: r.endNo,
usedNo: r.usedNo,
}))
const ok = lcUpsertMany(saveData)
if (!ok) {
// 记录失败的操作日志
for (const record of saveData) {
if (record.id) {
logUpdate(record, false, '门诊号码设置重复', getUserInfo())
} else {
logCreate(record, false, '门诊号码设置重复', getUserInfo())
}
}
return
}
// 记录成功的操作日志
for (const record of saveData) {
if (record.id) {
logUpdate(record, true, null, getUserInfo())
} else {
logCreate(record, true, null, getUserInfo())
}
}
if (proxy.$modal?.alertSuccess) {
proxy.$modal.alertSuccess('保存成功!')
} else {
proxy.$message.success('保存成功')
}
getList()
}
function onDelete() {
const rows = tableData.value.filter((r) => ids.value.includes(r.id))
if (!rows.length) return
// 双重校验(归属权+使用状态)
for (const r of rows) {
const canDeleteSelf = String(r.operatorId) === String(userStore.id)
const neverUsed = r.usedNo === r.startNo
if (!canDeleteSelf) {
// 权限不足提示
alertWarn('只能删除自己维护的门诊号码段')
logDelete(rows, false, '只能删除自己维护的门诊号码段', getUserInfo())
return
}
if (!neverUsed) {
// 已使用提示
alertWarn('已有门诊号码段已有使用的门诊号码,请核对!')
logDelete(rows, false, '已有门诊号码段已有使用的门诊号码', getUserInfo())
return
}
}
const doRealDelete = () => {
lcDeleteByIds(rows.map((r) => r.id))
//记录成功的删除操作日志
logDelete(rows, true, null, getUserInfo())
if (proxy.$modal?.alertSuccess) {
proxy.$modal.alertSuccess('删除成功')
} else {
proxy.$message.success('删除成功')
}
getList()
}
if (proxy.$modal?.confirm) {
proxy.$modal.confirm('是否确认删除选中数据项?').then(doRealDelete).catch(() => {
// 用户取消删除,不记录日志
})
} else {
doRealDelete()
}
}
function getList() {
loading.value = true
queryParams.value.onlySelf = !viewAll.value
const res = lcList({ ...queryParams.value })
tableData.value = res.records.map((it) => ({
...it,
_editing: false,
_error: false,
_dirty: false,
}))
total.value = res.total
loading.value = false
// 记录查询操作日志
logQuery(total.value, getUserInfo())
}
// 纯前端本地持久化方法localStorage
const STORAGE_KEY = 'ohis_outpatient_no_segments'
function lcReadAll() {
try {
const raw = localStorage.getItem(STORAGE_KEY)
const arr = raw ? JSON.parse(raw) : []
return Array.isArray(arr) ? arr : []
} catch (e) {
return []
}
}
function lcWriteAll(list) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(list || []))
}
function lcList({ pageNo = 1, pageSize = 10, onlySelf = true }) {
const all = lcReadAll()
const filtered = onlySelf ? all.filter((x) => String(x.operatorId) === String(userStore.id)) : all
const start = (pageNo - 1) * pageSize
const end = start + pageSize
return { records: filtered.slice(start, end), total: filtered.length, all }
}
function checkOverlapAll(row, all) {
const prefix = extractPrefix(row.startNo)
const sNum = extractTailNumber(row.startNo)
const eNum = extractTailNumber(row.endNo)
for (const it of all) {
if (row.id && it.id === row.id) continue
if (!it.startNo || !it.endNo) continue
if (extractPrefix(it.startNo) !== prefix) continue
const os = extractTailNumber(it.startNo)
const oe = extractTailNumber(it.endNo)
if (!Number.isNaN(os) && !Number.isNaN(oe)) {
if (rangesOverlap(sNum, eNum, os, oe)) return true
}
}
return false
}
function lcUpsertMany(rows) {
const all = lcReadAll()
for (const r of rows) {
if (checkOverlapAll(r, all)) {
alertWarn('门诊号码设置重复!')
return false
}
if (!r.id) {
r.id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
}
const idx = all.findIndex((x) => x.id === r.id)
if (idx >= 0) all[idx] = { ...all[idx], ...r }
else all.push({ ...r })
}
lcWriteAll(all)
return true
}
function lcDeleteByIds(idList) {
const all = lcReadAll()
const remain = all.filter((x) => !idList.includes(x.id))
lcWriteAll(remain)
}
</script>
<style scoped>
/*Windows XP风格布局 */
/* 外层容器 - 居中显示 */
.outpatient-no-management-wrapper {
display: flex;
justify-content: center;
align-items: flex-start;
min-height: calc(100vh - 100px);
padding: 20px;
background-color: #f0f0f0;
}
/* 主容器 - 600px固定宽度 */
.outpatient-no-management {
width: 600px;
background-color: #D4D0C8;
border: 1px solid #000000;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
min-height: 500px;
}
/* 标题栏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: 400px;
}
/* 表格样式1px实线边框#CCCCCC表头背景#F0F0F0 */
.table-content :deep(.el-table) {
border: 1px solid #CCCCCC;
font-size: 13px;
}
.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%);
}
/* 编辑弹窗样式 */
:deep(.el-dialog) {
border-radius: 0;
border: 2px solid #0055E5;
}
:deep(.el-dialog__header) {
background: linear-gradient(to bottom, #0055E5 0%, #0F3D8C 100%);
padding: 10px 15px;
margin: 0;
}
:deep(.el-dialog__title) {
color: #FFFFFF;
font-weight: 700;
font-size: 14px;
}
:deep(.el-dialog__close) {
color: #FFFFFF;
}
/* 响应式调整 */
@media (max-width: 650px) {
.outpatient-no-management {
width: 100%;
min-height: 100vh;
}
.outpatient-no-management-wrapper {
padding: 0;
}
}
</style>