docs(release-notes): 添加住院护士站划价功能说明和发版记录

- 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程
- 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑
- 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点
- 记录了住院相关功能的新增和门诊业务流程的修复
```
This commit is contained in:
2025-12-25 14:13:14 +08:00
parent 85fcb7c2e2
commit abc0674531
920 changed files with 107068 additions and 14495 deletions

View File

@@ -2,7 +2,7 @@
<div class="recordBill">
<div :id="'exeSheetTitle' + printData.id" class="printView_header">
<div style="text-align: center; height: 60px">
呼和浩特市第一医院医嘱执行单
长春市朝阳区中医院医嘱执行单
</div>
<div>
<span style="display: inline-block; width: 100px">床号{{ printData.patientInfo.encounterLocationName }}</span>

View File

@@ -2,7 +2,7 @@
<div class="recordBill">
<div id="div1" class="printView_header">
<div style="text-align: center; font-size: 20px; height: 40px">
呼和浩特市第一医院输液执行单
长春市朝阳区中医院输液执行单
</div>
<div>
<span>座位{{ printData.patientInfo.encounterLocationName }}</span>

View File

@@ -1,6 +1,6 @@
<template>
<div class="printTicket">
<p>xx人民医院</p>
<p>长春市朝阳区中医院</p>
<div>
<span>姓名</span>
<span>{{ printData.patientName }}</span>
@@ -21,11 +21,11 @@
<span>分诊时间</span>
<span>{{ printData.triageTime }}</span>
</div>
<img ref="refQr" style="position: absolute; top: 10px; left: 100px">
<img ref="refQr" style="position: absolute; top: 10px; left: 100px" />
</div>
</template>
<script>
import JsBarcode from 'jsbarcode'
import JsBarcode from 'jsbarcode';
export default {
name: 'TriageTicket',
props: {
@@ -37,41 +37,33 @@ export default {
dept: '',
triageLevel: '',
triageTime: '',
hisId: ''
}
}
}
hisId: '',
};
},
},
},
data() {
return {
}
return {};
},
updated() {
JsBarcode(this.$refs.refQr,
this.printData.hisId,
{
format: 'CODE128',
lineColor: '#000',
background: '#fff',
displayValue: false,
height: 30,
margin: 2
})
JsBarcode(this.$refs.refQr, this.printData.hisId, {
format: 'CODE128',
lineColor: '#000',
background: '#fff',
displayValue: false,
height: 30,
margin: 2,
});
},
mounted() {
},
methods: {
}
}
mounted() {},
methods: {},
};
</script>
<style>
.printTicket{
display: block;
width: 300px;
height: 200px;
border: 1px solid #A3A3A3;
}
.printTicket {
display: block;
width: 300px;
height: 200px;
border: 1px solid #a3a3a3;
}
</style>

View File

@@ -0,0 +1,51 @@
<template>
<div class="page-container">
<div v-if="$slots.header" class="page-header">
<slot name="header" />
</div>
<div class="page-content">
<slot />
</div>
<div v-if="$slots.footer" class="page-footer">
<slot name="footer" />
</div>
</div>
</template>
<style scoped lang="scss">
.page-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 16px;
box-sizing: border-box;
}
.page-header {
flex-shrink: 0;
display: flex;
justify-content: flex-end;
align-items: center;
margin-bottom: 16px;
}
.page-content {
flex: 1;
min-height: 0;
overflow-y: auto;
}
.page-footer {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid #ebeef5;
}
</style>

View File

@@ -0,0 +1,12 @@
import request from '@/utils/request';
/**
* 获取住院患者列表
*/
export function getPatientList(queryParams) {
return request({
url: '/reg-doctorstation/advice-manage/reg-patient-zk',
method: 'get',
params: queryParams,
});
}

View File

@@ -0,0 +1,695 @@
<template>
<div class="patientList-container" :class="{ 'patientList-container-unexpand': !currentExpand }">
<div
class="patientList-operate"
:class="{ 'patientList-operate-unexpand': !currentExpand }"
v-if="currentExpand"
>
<el-input
class="patientList-search-input"
placeholder="床号/住院号/姓名"
v-model="searchKeyword"
@keyup.enter="handleSearch"
:prefix-icon="Search"
/>
<el-button class="icon-btn" circle @click="handleRefresh" type="text" plain>
<el-icon icon-class="Refresh" size="24" :class="{ 'is-rotating': refreshing }">
<Refresh />
</el-icon>
</el-button>
</div>
<transition name="patient-list-toggle" mode="out-in">
<div key="expanded" class="patientList-list" v-if="currentExpand">
<div class="patient-cards" v-loading="isLoading">
<template v-if="filteredCardData && filteredCardData.length > 0">
<el-scrollbar ref="expandScrollbarRef" class="patient-cards-scrollbar">
<div
class="patient-card"
v-for="item in filteredCardData"
:key="item.encounterId"
:id="item.encounterId"
@click="handleItemClick(item)"
:class="{ actived: activeCardId === item.encounterId }"
>
<div class="patient-card-header">
<div class="header-top">
<div class="bed-container">
<div class="bed">
<div class="bed-info">
<div v-if="item.houseName" class="house-name">{{ item.houseName }}</div>
<div class="bed-name">{{ item.bedName || '未分床' }}</div>
</div>
</div>
</div>
<el-space>
<el-tag
v-if="item.statusEnum_enumText"
size="small"
class="payer-tag-status"
effect="light"
:style="getStatusStyle(item.statusEnum)"
>
{{ item.statusEnum_enumText }}
</el-tag>
<el-tag
v-if="item.contractName"
size="small"
class="payer-tag"
effect="light"
>
{{ item.contractName }}
</el-tag>
</el-space>
</div>
<div class="header-bottom">
<span class="bus-no">住院号{{ item.busNo || '-' }}</span>
<span class="insurance-type" v-if="item.insutype_dictText">
险种类型{{ item.insutype_dictText }}
</span>
</div>
</div>
<div class="doctor-parent-line" />
<div class="patient-card-body">
<div class="personal-info-container">
<div class="name-container">
<div class="name">
<el-text :text="item.patientName" tclass="name" width="auto">
{{ item.patientName || '-' }}
</el-text>
</div>
<div class="age">
<el-tag
size="small"
class="age-tag"
effect="plain"
:class="{ 'age-tag-female': item.genderEnum_enumText === '女性' }"
>
{{ item.genderEnum_enumText || '-' }}
<span v-if="item.age"> · {{ item.age }}</span>
</el-tag>
</div>
</div>
</div>
</div>
</div>
</el-scrollbar>
</template>
<el-empty v-else description="暂无数据" />
</div>
</div>
<div
key="collapsed"
class="patientList-list"
v-else
v-loading="isLoading"
:class="{ 'patientList-list-unexpand': !currentExpand }"
>
<el-scrollbar ref="contractScrollbarRef" class="patient-cards-scrollbar">
<template v-if="filteredCardData && filteredCardData.length > 0">
<el-tooltip
v-for="item in filteredCardData"
:show-after="200"
:key="item.encounterId"
:show-arrow="true"
placement="right"
effect="light"
:offset="4"
>
<template #content>
<div class="card-tooltip">
<div class="card-tooltip-main">
<span class="card-tooltip-bed">{{ item.bedName }}</span>
<span class="card-tooltip-name">{{ item.patientName }}</span>
</div>
<div class="card-tooltip-sex">
<span class="card-tooltip-sex-text">
{{ item.genderEnum_enumText || '-' }}
<span v-if="item.age"> · {{ item.age }}</span>
</span>
</div>
</div>
</template>
<div>
<div
class="card-small"
:class="{ 'patient-active': activeCardId === item.encounterId }"
@click="handleSmallCardClick(item)"
:key="item.encounterId"
>
{{ item.bedName }}
</div>
<div class="patient-card-small-border"></div>
</div>
</el-tooltip>
</template>
<el-empty v-else description="暂无数据" :image-size="50" />
</el-scrollbar>
</div>
</transition>
<div
class="patientList-toggle-btn-wrap"
:class="{ 'patientList-toggle-btn-wrap-unexpand': !currentExpand }"
>
<el-button class="icon-btn" circle @click="updateExpand">
<el-icon class="svg-sty-menu" size="24">
<Expand v-if="!currentExpand" />
<Fold v-if="currentExpand" />
</el-icon>
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { Search, Refresh, Expand, Fold } from '@element-plus/icons-vue';
import type { ElScrollbar } from 'element-plus';
interface PatientCardItem {
encounterId: string;
bedName?: string;
busNo?: string;
patientName?: string;
genderEnum_enumText?: string;
age?: number | string;
contractName?: string;
[key: string]: any;
}
interface Props {
// 过滤后的卡片数据
filteredCardData?: PatientCardItem[];
// 当前激活的卡片ID
activeCardId?: string;
// 是否展开(不传则为不受控模式,组件内部自己管理)
expand?: boolean;
// 加载状态
loading?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
filteredCardData: () => [],
activeCardId: '',
expand: undefined,
loading: false,
});
interface Emits {
(e: 'item-click', item: PatientCardItem): void;
(e: 'search', keyword: string): void;
(e: 'refresh'): void;
(e: 'update:expand', value: boolean): void;
}
const emit = defineEmits<Emits>();
const searchKeyword = ref<string>('');
const refreshing = ref<boolean>(false);
const refreshLoading = ref<boolean>(false);
const internalExpand = ref<boolean>(true);
const isControlled = computed<boolean>(() => props.expand !== undefined);
const currentExpand = computed<boolean>(() => {
return isControlled.value ? props.expand! : internalExpand.value;
});
const isLoading = computed<boolean>(() => {
return props.loading || refreshLoading.value;
});
const handleItemClick = (item: PatientCardItem): void => {
emit('item-click', item);
};
const handleSmallCardClick = (item: PatientCardItem): void => {
emit('item-click', item);
};
const handleSearch = (): void => {
emit('search', searchKeyword.value);
};
const handleRefresh = (): void => {
if (refreshing.value) return;
refreshing.value = true;
refreshLoading.value = true;
emit('refresh');
setTimeout(() => {
refreshing.value = false;
}, 600);
setTimeout(() => {
if (!props.loading) {
refreshLoading.value = false;
}
}, 500);
};
const updateExpand = (): void => {
const newValue = !currentExpand.value;
if (isControlled.value) {
emit('update:expand', newValue);
} else {
internalExpand.value = newValue;
}
};
// 根据状态枚举值返回文本颜色
const getStatusColor = (statusEnum?: number): string => {
if (statusEnum === undefined || statusEnum === null) {
return '';
}
switch (statusEnum) {
case 2: // REGISTERED - 待入科
return '#E6A23C'; // 橙色
case 3: // AWAITING_DISCHARGE - 待出院
return '#F56C6C'; // 红色
case 4: // DISCHARGED_FROM_HOSPITAL - 待出院结算
return '#909399'; // 灰色
case 5: // ADMITTED_TO_THE_HOSPITAL - 已入院
return '#67C23A'; // 绿色
case 6: // PENDING_TRANSFER - 待转科
return '#409EFF'; // 蓝色
default:
return '';
}
};
// 根据状态枚举值返回带透明背景的样式
const getStatusStyle = (statusEnum?: number): Record<string, string> => {
const color = getStatusColor(statusEnum);
if (!color) {
return {};
}
// 不同状态对应的半透明背景色
let backgroundColor = '';
switch (statusEnum) {
case 2: // 橙色
backgroundColor = 'rgba(230, 162, 60, 0.12)';
break;
case 3: // 红色
backgroundColor = 'rgba(245, 108, 108, 0.12)';
break;
case 4: // 灰色
backgroundColor = 'rgba(144, 147, 153, 0.12)';
break;
case 5: // 绿色
backgroundColor = 'rgba(103, 194, 58, 0.12)';
break;
case 6: // 蓝色
backgroundColor = 'rgba(64, 158, 255, 0.12)';
break;
default:
backgroundColor = 'rgba(148, 163, 184, 0.12)';
}
return {
color,
backgroundColor,
borderColor: 'transparent',
};
};
// 保险类型映射表
const insuranceTypeMap: Record<number, string> = {
310: '职工基本医疗保险',
320: '公务员医疗补助',
330: '大额医疗费用补助',
340: '离休人员医疗保障',
350: '一至六级残废军人医疗补助',
360: '老红军医疗保障',
370: '企业补充医疗保险',
380: '新型农村合作医疗',
390: '城乡居民基本医疗保险',
391: '城镇居民基本医疗保险',
392: '城乡居民大病医疗保险',
399: '其他特殊人员医疗保障',
410: '长期照护保险',
};
watch(
() => props.loading,
(newLoading) => {
if (!newLoading && refreshLoading.value) {
refreshLoading.value = false;
}
}
);
</script>
<style lang="scss" scoped>
.patient-card {
width: 100%;
overflow: hidden;
background-color: #fff;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.04);
box-shadow: 0 2px 6px 0 rgba(15, 35, 52, 0.12);
cursor: pointer;
transition: transform 0.2s ease;
&:hover {
box-shadow: 0 4px 12px rgba(15, 35, 52, 0.18);
transform: translateY(-1px);
}
&.actived {
background-color: rgba(7, 155, 140, 0.06);
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px rgba(7, 155, 140, 0.3), 0 4px 14px rgba(7, 155, 140, 0.25);
}
.patient-card-header {
display: flex;
flex-direction: column;
padding: 10px 12px 4px;
.header-top {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.bed-container {
display: flex;
flex: 1;
align-items: center;
min-width: 0;
.bed {
flex-grow: 0;
flex-shrink: 1;
min-width: 0;
.bed-info {
display: flex;
flex-direction: column;
line-height: 1.4;
.house-name {
color: #1f2933;
font-weight: 600;
font-size: 16px;
white-space: normal;
word-break: break-all;
}
.bed-name {
color: #1f2933;
font-weight: 600;
font-size: 16px;
white-space: normal;
word-break: break-all;
}
}
}
}
.payer-tag {
max-width: 120px;
font-size: 12px;
border-radius: 999px;
font-weight: bolder;
}
.payer-tag-status {
font-weight: bolder;
border-radius: 999px;
}
}
.header-bottom {
margin-top: 4px;
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 2px;
color: #6b7280;
font-size: 12px;
.bus-no {
white-space: nowrap;
}
.insurance-type {
white-space: nowrap;
}
}
}
.doctor-parent-line {
margin: 6px 12px 0;
border-bottom: 1px dashed #e5e7eb;
}
.patient-card-body {
padding: 8px 12px 10px;
.personal-info-container {
display: block;
.name-container {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
width: 100%;
.name {
color: #111827;
font-weight: 600;
font-size: 16px;
}
.age {
flex-shrink: 0;
.age-tag {
border-radius: 999px;
padding: 0 8px;
}
.age-tag-female {
border-color: rgb(255, 55, 158);
color: rgb(255, 126, 184);
}
}
}
}
}
}
.patientList-container {
height: 100%;
display: flex;
flex-direction: column;
height: 100%;
border-right: 1px solid #ebeef5;
background-color: #ffffff;
width: 240px;
min-width: 240px;
&-unexpand {
width: 84px;
min-width: 84px;
}
.patientList-operate {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 44px;
border-bottom: 1px solid #ebeef5;
flex: none;
padding: 0 0 0 8px;
&-unexpand {
justify-content: space-around;
}
}
.patientList-list {
display: flex;
flex: 1;
flex-direction: column;
height: 0;
width: 240px;
&-unexpand {
width: 84px;
}
.search-operate {
padding: 0 8px;
height: 48px;
display: flex;
align-items: center;
flex: none;
}
.patient-cards {
flex: 1;
padding: 0 8px;
overflow: hidden;
:deep(.patient-cards-scrollbar) {
width: 100%;
height: 100%;
.el-scrollbar__bar {
width: 0;
}
}
}
.card-small {
height: 44px;
padding: 0 10px 0 12px;
overflow: hidden;
font-size: 14px;
line-height: 44px;
white-space: nowrap;
text-overflow: ellipsis;
border-right: none;
cursor: pointer;
}
.patient-active {
background-color: #e6f7ff;
font-weight: 600;
color: var(--el-color-primary);
}
.patient-card-small-border {
display: block;
width: 100%;
height: 2px;
background-color: #f1faff;
}
}
}
.patientList-toggle-btn-wrap {
display: flex;
justify-content: flex-end;
padding: 4px 16px 8px;
&-unexpand {
justify-content: center;
}
}
.patient-list-toggle-enter-active,
.patient-list-toggle-leave-active {
transition: transform 0.2s ease;
}
.patient-list-toggle-enter-from,
.patient-list-toggle-leave-to {
opacity: 0;
transform: translateY(-8px);
}
.card-tooltip {
display: inline-flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
max-width: 220px;
padding: 6px 10px;
border-radius: 6px;
background-color: #ffffff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
}
.card-tooltip-main {
display: flex;
flex-direction: column;
margin-right: 8px;
}
.card-tooltip-bed {
font-size: 15px;
font-weight: 600;
color: #111827;
margin-bottom: 2px;
}
.card-tooltip-name {
font-size: 13px;
color: #4b5563;
}
.card-tooltip-sex {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
.card-tooltip-sex-text {
font-size: 12px;
color: #6b7280;
}
.svg-gray {
fill: var(--hip-color-text-unit);
}
.icon-btn {
border: none;
background-color: transparent;
box-shadow: none;
padding: 4px;
}
.is-rotating {
animation: patient-refresh-rotate 0.6s linear;
}
@keyframes patient-refresh-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
:deep(.scrollbar) {
width: 100%;
height: 100%;
.el-scrollbar__bar {
width: 0;
}
}
.f-16 {
font-weight: 600;
font-size: 16px;
}
.f-14 {
font-size: 14px;
}
.empty-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
.empty-text-sty {
margin-top: 0;
}
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<BasePatientList
:filtered-card-data="filteredCardData"
:active-card-id="cardId"
:loading="queryloading"
@item-click="handleItemClick"
@search="handleSearch"
@refresh="getList"
/>
</template>
<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import BasePatientList from './index.vue';
import { getPatientList } from '@/views/inpatientDoctor/home/components/api';
defineOptions({
name: 'PatientListWithData',
});
const props = defineProps({
/** 接口 status 参数,默认 5在院 */
status: {
type: [String, Number],
default: undefined,
},
/** 首次加载自动选中第一条 */
autoSelectFirst: {
type: Boolean,
default: true,
},
/** 外部已选中的患者信息(用于避免重复自动选中) */
selectedPatient: {
type: Object,
default: null,
},
/**
* 选中患者时回调(给你外部写 store 用)
* (patient) => void
*/
onSelect: {
type: Function,
default: null,
},
});
const emit = defineEmits(['item-click']);
// 这段逻辑就是你说的 “@index.vue (4-11) 那套带数据的”
const searchData = reactive({
keyword: '',
patientType: 1,
type: 1,
timeLimit: 3,
});
const cardId = ref('');
const cardAllData = ref([]);
const isFirstLoad = ref(true);
const queryloading = ref(false);
const filteredCardData = computed(() => cardAllData.value);
const getList = () => {
queryloading.value = true;
getPatientList({ status: props.status, searchKey: searchData.keyword })
.then((res) => {
cardAllData.value = res?.data?.records || [];
})
.finally(() => {
queryloading.value = false;
});
};
watch(
() => filteredCardData.value,
(newData) => {
if (!props.autoSelectFirst) return;
if (
newData &&
newData.length > 0 &&
!cardId.value &&
isFirstLoad.value &&
!props.selectedPatient?.encounterId
) {
const firstPatient = newData[0];
if (firstPatient?.encounterId) {
handleItemClick(firstPatient);
isFirstLoad.value = false;
}
}
},
{ immediate: true }
);
const handleItemClick = (node) => {
cardId.value = node.encounterId;
props.onSelect?.(node);
emit('item-click', node);
};
const handleSearch = (keyword) => {
searchData.keyword = keyword;
getList();
};
onMounted(() => {
getList();
});
</script>

View File

@@ -0,0 +1,318 @@
<template>
<div class="pending-patient-list">
<div class="patient-cards" v-loading="loading">
<template v-if="list && list.length > 0">
<el-scrollbar class="patient-cards-scrollbar">
<div
class="patient-card"
v-for="(item, index) in list"
:key="item[idKey] ?? index"
:class="{ actived: !!item.active || activeId === item[idKey] }"
draggable="true"
@click="emit('item-click', item, index)"
@dblclick="emit('item-dblclick', item)"
@dragstart="(e) => emit('dragstart', e, item)"
@dragend="(e) => emit('dragend', e)"
>
<div class="patient-card-header">
<div class="header-top">
<div class="bed-container">
<div class="bed">
<el-text truncated tclass="bed-font" width="auto">
{{ item.bedName || '-' }}
</el-text>
</div>
</div>
<div class="header-tags">
<el-tag v-if="item.contractName" size="small" class="payer-tag" effect="light">
{{ item.contractName }}
</el-tag>
<el-tag
v-if="item.encounterStatus_enumText"
size="small"
class="status-tag"
effect="light"
:class="getStatusClass(item)"
>
{{ item.encounterStatus_enumText }}
</el-tag>
</div>
</div>
<div class="header-bottom">
<span class="bus-no">住院号{{ item.busNo || '-' }}</span>
</div>
<div class="meta">
<div class="meta-row">
<span class="meta-label">入院时间</span>
<span class="meta-value">{{
item.startTime ? formatDate(item.startTime) : '-'
}}</span>
</div>
<div class="meta-row">
<span class="meta-label">入科时间</span>
<span class="meta-value">{{
item.admissionTime ? formatDate(item.admissionTime) : '-'
}}</span>
</div>
</div>
</div>
<div class="doctor-parent-line" />
<div class="patient-card-body">
<div class="personal-info-container">
<div class="name-container">
<div class="name">
<el-text :text="item.patientName" tclass="name" width="auto">
{{ item.patientName || '-' }}
</el-text>
</div>
<div class="age">
<el-tag
size="small"
class="age-tag"
effect="plain"
:class="{
'age-tag-female': item.genderEnum_enumText === '女性',
'age-tag-male': item.genderEnum_enumText === '男性',
}"
>
{{ item.genderEnum_enumText || '-' }}
<span v-if="item.age"> · {{ item.age }}</span>
<span v-if="item.priorityEnum_enumText">
· {{ item.priorityEnum_enumText }}</span
>
</el-tag>
</div>
</div>
</div>
<div class="meta"></div>
</div>
</div>
</el-scrollbar>
</template>
<el-empty v-else description="暂无数据" />
</div>
</div>
</template>
<script setup lang="ts">
import { formatDate } from '@/utils/index';
withDefaults(
defineProps<{
list: any[];
activeId?: string | number;
idKey?: string;
loading?: boolean;
}>(),
{
list: () => [],
activeId: '',
idKey: 'id',
loading: false,
}
);
const emit = defineEmits<{
(e: 'item-click', item: any, index: number): void;
(e: 'item-dblclick', item: any): void;
(e: 'dragstart', event: DragEvent, item: any): void;
(e: 'dragend', event: DragEvent): void;
}>();
const getStatusClass = (item: any) => {
if (item?.encounterStatus == 2) return 'status-tag--blue';
if (item?.encounterStatus == 5) return 'status-tag--green';
return '';
};
</script>
<style scoped lang="scss" name="PendingPatientList">
.pending-patient-list {
height: 100%;
display: flex;
flex-direction: column;
min-height: 0;
min-width: 240px;
width: 240px;
}
.patient-cards {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
:deep(.patient-cards-scrollbar) {
width: 100%;
height: 100%;
.el-scrollbar__bar {
width: 0;
}
}
}
.patient-card {
width: 100%;
overflow: hidden;
background-color: #fff;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.04);
box-shadow: 0 2px 6px 0 rgba(15, 35, 52, 0.12);
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
&:hover {
box-shadow: 0 4px 12px rgba(15, 35, 52, 0.18);
transform: translateY(-1px);
}
&.actived {
background-color: rgba(7, 155, 140, 0.06);
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px rgba(7, 155, 140, 0.3), 0 4px 14px rgba(7, 155, 140, 0.25);
}
}
.patient-card-header {
display: flex;
flex-direction: column;
padding: 10px 12px 4px;
.header-top {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.bed-container {
display: flex;
flex: 1;
align-items: center;
min-width: 0;
.bed {
flex-grow: 0;
flex-shrink: 1;
min-width: 0;
:deep(.bed-font) {
color: #1f2933;
font-weight: 600;
font-size: 16px;
}
}
}
.payer-tag {
max-width: 120px;
font-size: 12px;
border-radius: 999px;
}
.header-tags {
flex-shrink: 0;
display: flex;
align-items: flex-end;
justify-content: flex-end;
gap: 6px;
}
}
.header-bottom {
margin-top: 4px;
width: 100%;
display: flex;
justify-content: flex-start;
color: #6b7280;
font-size: 12px;
.bus-no {
white-space: nowrap;
}
}
}
.doctor-parent-line {
margin: 6px 12px 0;
border-bottom: 1px dashed #e5e7eb;
}
.patient-card-body {
padding: 8px 12px 10px;
}
.personal-info-container {
display: block;
.name-container {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
width: 100%;
.name {
color: #111827;
font-weight: 600;
font-size: 14px;
}
.age {
flex-shrink: 0;
}
}
}
.age-tag {
border-radius: 999px;
padding: 0 8px;
}
.age-tag-female {
border-color: rgb(255, 55, 158);
color: rgb(255, 126, 184);
}
.age-tag-male {
border-color: #91d5ff;
color: #1677ff;
}
.status-tag {
border-radius: 999px;
padding: 0 8px;
flex-shrink: 0;
font-weight: 600;
}
.status-tag--blue {
border-color: #91d5ff;
background-color: #1677ff;
color: white;
}
.status-tag--green {
border-color: #b7eb8f;
background-color: #389e0d;
color: white;
}
.meta {
margin-top: 6px;
color: #6b7280;
font-size: 12px;
line-height: 18px;
}
.meta-row {
display: flex;
}
.meta-label {
flex-shrink: 0;
}
</style>

View File

@@ -0,0 +1,338 @@
{
"panels": [
{
"index": 0,
"name": 1,
"paperType": "自定义",
"height": 80,
"width": 279,
"paperList": {
"type": "自定义",
"width": 279,
"height": 80
},
"panelPageRule": "none",
"paperHeader": 0,
"paperFooter": 422.3622047244095,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.7,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "36px",
"rotate": 25,
"width": 413,
"height": 310,
"timestamp": true,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 15,
"height": 16.5,
"width": 792,
"title": "长春市朝阳区中医院预交金收据",
"coordinateSync": false,
"widthHeightSync": false,
"fontWeight": "bold",
"letterSpacing": 0.75,
"textAlign": "center",
"qrCodeLevel": 0,
"fontSize": 15,
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 46.5,
"height": 14,
"width": 151.5,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "patientName",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 295.5,
"top": 48,
"height": 14,
"width": 148.5,
"title": "住院号",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "encounterNosd",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 480,
"top": 48,
"height": 14,
"width": 162,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "inHospitalOrgName",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 73.5,
"height": 14,
"width": 153,
"title": "ID号",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "patientId",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 295.5,
"top": 73.5,
"height": 14,
"width": 147,
"title": "医保类别",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "contractName",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 480,
"top": 73.5,
"height": 14,
"width": 163.5,
"title": "时间",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "currentTime",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 105,
"height": 25,
"width": 120,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"textAlign": "center",
"textContentVerticalAlign": "middle",
"borderLeft": "solid",
"borderTop": "solid",
"borderRight": "solid",
"borderBottom": "solid",
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 231,
"top": 105,
"height": 25,
"width": 393,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"textAlign": "center",
"textContentVerticalAlign": "middle",
"borderTop": "solid",
"borderRight": "solid",
"borderBottom": "solid",
"qrCodeLevel": 0,
"field": "balanceAmount",
"hideTitle": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 129,
"height": 30,
"width": 120,
"title": "人民币(大写)",
"coordinateSync": false,
"widthHeightSync": false,
"textAlign": "center",
"textContentVerticalAlign": "middle",
"borderLeft": "solid",
"borderTop": "solid",
"borderRight": "solid",
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 231,
"top": 129,
"height": 30,
"width": 393,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"textAlign": "center",
"textContentVerticalAlign": "middle",
"borderTop": "solid",
"borderRight": "solid",
"qrCodeLevel": 0,
"field": "amountInWords",
"hideTitle": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 159,
"height": 30,
"width": 513,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"textAlign": "center",
"textContentVerticalAlign": "middle",
"borderLeft": "solid",
"borderRight": "solid",
"borderBottom": "solid",
"qrCodeLevel": 0,
"field": "paymentDetails",
"hideTitle": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 198,
"height": 14,
"width": 120,
"title": "签章",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "patientNamesfs",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 297,
"top": 198,
"height": 14,
"width": 132,
"title": "交款人",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "patientNameada",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 481.5,
"top": 198,
"height": 14,
"width": 124.5,
"title": "收款人",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"field": "cashier",
"fontFamily": "Microsoft YaHei"
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,454 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A5",
"height": 210,
"width": 148,
"paperList": {
"type": "A5",
"width": 148,
"height": 210
},
"paperHeader": 0,
"paperFooter": 592.4409448818898,
"orient": 1,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.01,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "10px",
"rotate": 25,
"width": 100,
"height": 100,
"timestamp": false,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 420,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 50,
"height": 20,
"width": 420,
"title": "处置单",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 154.5,
"top": 75,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 75,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 76.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 100.5,
"height": 13.5,
"width": 99,
"title": "开单医生",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 27,
"top": 102,
"height": 13.5,
"width": 99,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "departmentName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 154.5,
"top": 102,
"height": 13.5,
"width": 120,
"title": "费用性质",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 130.5,
"height": 13.5,
"width": 174,
"title": "门诊号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "encounterNo",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 222,
"top": 130.5,
"height": 13.5,
"width": 165,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 156,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28,
"top": 166.5,
"height": 9.75,
"width": 120,
"title": "Rp",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true,
"fontSize": 18,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 15,
"top": 190.5,
"height": 36,
"width": 390,
"title": "undefined+beforeDragIn",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"textAlign": "center",
"tableBorder": "border",
"tableHeaderFontWeight": "500",
"field": "prescriptionList",
"columns": [
[
{
"title": "项目名",
"width": 116.47241770689429,
"field": "itemName",
"checked": true,
"columnId": "itemName",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "单价",
"width": 95.6749835266735,
"field": "unitPrice",
"checked": true,
"columnId": "unitPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"width": 87.60415049837947,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "执行次数",
"width": 90.24844826805275,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
},
{
"options": {
"left": 10.5,
"top": 508.5,
"height": 13.5,
"width": 100,
"title": "医师",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "发药:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 214.5,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "划价:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 319,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "调配:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 532.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 289,
"top": 551.5,
"height": 13.5,
"width": 120,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "medTotalAmount",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

View File

@@ -0,0 +1,454 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A5",
"height": 210,
"width": 148,
"paperList": {
"type": "A5",
"width": 148,
"height": 210
},
"paperHeader": 0,
"paperFooter": 592.4409448818898,
"orient": 1,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.01,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "10px",
"rotate": 25,
"width": 100,
"height": 100,
"timestamp": false,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 420,
"title": "长春市红旗中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 50,
"height": 20,
"width": 420,
"title": "处置单",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 154.5,
"top": 75,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 75,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 76.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 100.5,
"height": 13.5,
"width": 99,
"title": "开单医生",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 27,
"top": 102,
"height": 13.5,
"width": 99,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "departmentName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 154.5,
"top": 102,
"height": 13.5,
"width": 120,
"title": "费用性质",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 130.5,
"height": 13.5,
"width": 174,
"title": "门诊号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "encounterNo",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 222,
"top": 130.5,
"height": 13.5,
"width": 165,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 156,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28,
"top": 166.5,
"height": 9.75,
"width": 120,
"title": "Rp",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true,
"fontSize": 18,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 15,
"top": 190.5,
"height": 36,
"width": 390,
"title": "undefined+beforeDragIn",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"textAlign": "center",
"tableBorder": "border",
"tableHeaderFontWeight": "500",
"field": "prescriptionList",
"columns": [
[
{
"title": "项目名",
"width": 116.47241770689429,
"field": "itemName",
"checked": true,
"columnId": "itemName",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "单价",
"width": 95.6749835266735,
"field": "unitPrice",
"checked": true,
"columnId": "unitPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"width": 87.60415049837947,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "执行次数",
"width": 90.24844826805275,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
},
{
"options": {
"left": 10.5,
"top": 508.5,
"height": 13.5,
"width": 100,
"title": "医师",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "发药:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 214.5,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "划价:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 319,
"top": 509.0000066757202,
"height": 13.5,
"width": 100,
"title": "调配:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 532.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 289,
"top": 551.5,
"height": 13.5,
"width": 120,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "medTotalAmount",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,701 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A4",
"height": 297,
"width": 210,
"paperList": {
"type": "自定义",
"width": 80,
"height": 60
},
"paperHeader": 166.5,
"paperFooter": 760.5,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"expandCss": "",
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.7,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "36px",
"rotate": 25,
"width": 413,
"height": 310,
"timestamp": true,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 595.5,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 54.5,
"height": 20,
"width": 595.5,
"title": "门诊病历",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 235.5,
"top": 81,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 429,
"top": 81,
"height": 13.5,
"width": 160.5,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 24,
"top": 82.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 24,
"top": 108,
"height": 13.5,
"width": 190.5,
"title": "电话",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "phone"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 235.5,
"top": 108,
"height": 13.5,
"width": 175.5,
"title": "医保类型",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 429,
"top": 108,
"height": 13.5,
"width": 162,
"title": "病历号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "busNo"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 24,
"top": 132,
"height": 13.5,
"width": 200,
"title": "就诊日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "onsetDate"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 235.5,
"top": 132,
"height": 13.5,
"width": 175.5,
"title": "就诊科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 429,
"top": 132,
"height": 13.5,
"width": 162,
"title": "接诊医生",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 163.5,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 25.5,
"top": 171,
"height": 13.5,
"width": 50,
"title": "主诉",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 187.5,
"height": 33,
"width": 550,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "complaint",
"lHeight": 50
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 231,
"height": 13.5,
"width": 50,
"title": "现病史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 253,
"height": 42,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "presentIllness",
"title": "无",
"lHeight": 30
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 305,
"height": 13.5,
"width": 50,
"title": "既往史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 324,
"height": 30,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "pastIllness",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 366,
"height": 13.5,
"width": 50,
"title": "过敏史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 384,
"height": 22.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "allergyHistory",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 412.5,
"height": 13.5,
"width": 50,
"title": "家族史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 432,
"height": 22.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "familyHistory",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 465,
"height": 13.5,
"width": 50,
"title": "个人史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 486,
"height": 28.5,
"width": 550,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "personalHistory",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 522.2500162124634,
"height": 13.5,
"width": 82.5,
"title": "体格检查",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 544.7500162124634,
"height": 30,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"title": "长文",
"lHeight": 20,
"formatter": "function(title, value, options, templateData, target, paperNo) {\n // 获取所有体检数据\n const bloodHigh = templateData.bloodHigh || '';\n const bloodLow = templateData.bloodLow || '';\n const breathe = templateData.breathe || '';\n const temperature = templateData.temperature || '';\n const pulse = templateData.pulse || '';\n \n // 格式化每个字段\n \n let formattedTemperature = '';\n if (temperature && !isNaN(temperature)) {\n formattedTemperature = 'T' + temperature + '℃';\n }\n \n let formattedPulse = '';\n if (pulse && !isNaN(pulse)) {\n formattedPulse = 'P' + pulse + '次/分';\n }\n let formattedR = '';\n if (breathe && !isNaN(breathe)) {\n formattedR = 'R' + breathe + '次/分';\n }\n \n let formattedBP = '';\n if (bloodHigh && !isNaN(bloodHigh)) {\n formattedBP = 'BP' + bloodHigh +'/'+bloodLow+ 'mmHg';\n }\n \n \n // 组合所有信息\n const result = [\n formattedR,\n formattedBP,\n formattedTemperature,\n formattedPulse\n ].filter(item => item !== '').join(' ');\n \n return result;\n}\n\n"
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 582,
"height": 13.5,
"width": 79.5,
"title": "辅助检查",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 601.5,
"height": 30,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "auxiliaryExam",
"title": "长文",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 640.5,
"height": 13.5,
"width": 79.5,
"title": "诊断",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 661.5,
"height": 28.5,
"width": 550,
"title": "无",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "diagnosisText",
"lHeight": 30
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 694.7431640625,
"height": 13.5,
"width": 79.5,
"title": "处置",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 720,
"height": 28.5,
"width": 550,
"title": "无",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "treatment",
"lHeight": 30
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 9,
"top": 766.5,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28.5,
"top": 787.5,
"height": 13.5,
"width": 223.5,
"title": "医生签字:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 399,
"top": 787.5,
"height": 13.5,
"width": 186,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true,
"field": "reqTime"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 28.5,
"top": 810,
"height": 19.5,
"width": 556.5,
"title": "为了您和家人的健康,请勿吸烟!如需戒烟帮助,请到戒烟干预室咨询。",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true,
"fontSize": 12,
"letterSpacing": 1.5,
"textAlign": "center"
},
"printElementType": {
"title": "长文",
"type": "longText"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

View File

@@ -0,0 +1,599 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A5",
"height": 210,
"width": 148,
"paperList": {
"type": "A5",
"width": 148,
"height": 210
},
"paperHeader": 0,
"paperFooter": 592.4409448818898,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"expandCss": "",
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.01,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "10px",
"rotate": 0,
"width": 100,
"height": 100,
"timestamp": false,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 420,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 50,
"height": 20,
"width": 420,
"title": "处方签",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 90,
"height": 13.5,
"width": 100,
"title": "医保编号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 283,
"top": 90,
"height": 13.5,
"width": 117,
"title": "就诊类型",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "orgId_dictText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 117,
"height": 13.5,
"width": 100,
"title": "处方编号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "prescriptionNo",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 283,
"top": 117,
"height": 13.5,
"width": 117,
"title": "病人性质",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 138,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 160.5,
"top": 153,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 153,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 154.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 27,
"top": 177,
"height": 13.5,
"width": 132,
"title": "地址:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 160.5,
"top": 178.5,
"height": 13.5,
"width": 99,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "departmentName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 178.5,
"height": 13.5,
"width": 99,
"title": "电话",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 205.5,
"height": 13.5,
"width": 189,
"title": "门诊号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "encounterNo"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 219,
"top": 205.5,
"height": 13.5,
"width": 198,
"title": "开具日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 232.5,
"height": 13.5,
"width": 381,
"title": "临床诊断",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "conditionName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 256.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28,
"top": 282,
"height": 9.75,
"width": 120,
"title": "Rp",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true,
"fontSize": 18,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 15,
"top": 306,
"height": 36,
"width": 390,
"title": "undefined+beforeDragIn",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"textAlign": "center",
"tableBorder": "border",
"tableHeaderFontWeight": "500",
"field": "prescriptionList",
"columns": [
[
{
"title": "名称",
"width": 55.386224315781,
"field": "itemName",
"checked": true,
"columnId": "itemName",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "规格",
"width": 59.41840807183531,
"field": "totalVolume",
"checked": true,
"columnId": "totalVolume",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "产地",
"width": 79.59183673469389,
"field": "manufacturerText",
"checked": true,
"columnId": "manufacturerText",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "单价",
"width": 45.49640338326492,
"field": "unitPrice",
"checked": true,
"columnId": "unitPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"width": 41.658473534111906,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "金额",
"width": 42.9159186212175,
"field": "totalPrice",
"checked": true,
"columnId": "totalPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "等级",
"width": 65.53273533909551,
"field": "contractName",
"checked": true,
"columnId": "contractName",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
},
{
"options": {
"left": 25.5,
"top": 379.5,
"height": 13.5,
"width": 241.5,
"title": "用法",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 18,
"top": 513,
"height": 13.5,
"width": 80,
"title": "医师",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 124.5,
"top": 513,
"height": 13.5,
"width": 80,
"title": "发药",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 222,
"top": 513,
"height": 13.5,
"width": 80,
"title": "划价",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 310.5,
"top": 513,
"height": 13.5,
"width": 80,
"title": "调配",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 532.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 289,
"top": 551.5,
"height": 13.5,
"width": 120,
"title": "总金额",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "medTotalAmount"
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

View File

@@ -0,0 +1,407 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A4",
"height": 297,
"width": 210,
"paperList": {
"type": "A4",
"width": 210,
"height": 297
},
"paperHeader": 0,
"paperFooter": 837,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"expandCss": "",
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.7,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "36px",
"rotate": 25,
"width": 413,
"height": 310,
"timestamp": true,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 595.5,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 54.5,
"height": 20,
"width": 595.5,
"title": "手术记录",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 81,
"height": 13.5,
"width": 190.5,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 460.5,
"top": 81,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 82.5,
"height": 13.5,
"width": 193.5,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 108,
"height": 13.5,
"width": 192,
"title": "医保",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 108,
"height": 13.5,
"width": 190.5,
"title": "电话",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "phone"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 460.5,
"top": 108,
"height": 13.5,
"width": 99,
"title": "医生",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 460.5,
"top": 132.99999618530273,
"height": 13.5,
"width": 124.5,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "department"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 133.5,
"height": 13.5,
"width": 196.5,
"title": "病历号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "busNo"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 133.5,
"height": 13.5,
"width": 200,
"title": "手术日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "operationDate"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 157.5,
"height": 61.5,
"width": 550.5,
"title": "诊断",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "busNosds"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 226.5,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 25.5,
"top": 250.5,
"height": 13.5,
"width": 81,
"title": "详细记录",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 271.5,
"height": 493.5,
"width": 550,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "surgicalDetails",
"lHeight": 60,
"formatter": "function(title, value, options, templateData, target, paperNo) {\n // 返回原始值,让组件自动处理高度\n return value;\n}",
"styler": "function(value, options, target, templateData, paperNo) {\n return { \n 'word-wrap': 'break-word',\n 'word-break': 'break-all',\n 'white-space': 'normal',\n 'line-height': '1.4',\n 'overflow': 'visible'\n };\n}"
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 9,
"top": 774,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28.5,
"top": 787.5,
"height": 13.5,
"width": 223.5,
"title": "病人或家人签字:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 399,
"top": 787.5,
"height": 13.5,
"width": 186,
"title": "医生签字:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 399,
"top": 811.5,
"height": 13.5,
"width": 186,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 28.5,
"top": 813,
"height": 13.5,
"width": 222,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,290 @@
{
"panels": [
{
"index": 1,
"name": 2,
"paperType": "自定义",
"height": 60,
"width": 80,
"paperList": {
"type": "自定义",
"width": 80,
"height": 60
},
"paperHeader": 0,
"paperFooter": 166.5,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.7,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "36px",
"rotate": 25,
"width": 413,
"height": 310,
"timestamp": true,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 6,
"top": 7.5,
"height": 10,
"width": 69,
"title": "病区",
"field": "patientName",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 81,
"top": 7.5,
"height": 10,
"width": 52.5,
"title": "姓名",
"field": "patientName",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 147,
"top": 7.5,
"height": 10,
"width": 72,
"title": "床位号",
"field": "bedNo",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 6,
"top": 22,
"height": 12,
"width": 81,
"title": "频次 qd",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 8.25,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 147,
"top": 24,
"height": 10,
"width": 70.5,
"title": "日期",
"field": "date",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 4.5,
"top": 45,
"height": 30,
"width": 216,
"title": "undefined+beforeDragIn",
"field": "infuseData",
"coordinateSync": false,
"widthHeightSync": false,
"tableHeaderBackground": "#ffffff",
"tableBodyCellBorder": "noBorder",
"rowsColumnsMerge": "function(data, col, colIndex, rowIndex, tableData, printData){ \n // 合并前三列 (columnIndex 0-2)\n if (colIndex >= 0 && colIndex <= 2) {\n // 第一列显示合并后的单元格\n if (colIndex === 0) {\n return [1, 3]; // rowspan=1, colspan=3\n } \n // 其他两列不显示(被合并)\n else {\n return [0, 0]; // rowspan=0, colspan=0\n }\n }\n // 其他列正常显示\n return [1, 1]; // rowspan=1, colspan=1\n}",
"tableBodyRowBorder": "topBottomBorder",
"fontSize": 7.5,
"tableHeaderRepeat": "first",
"maxRows": 3,
"tableHeaderRowHeight": 6,
"tableHeaderFontSize": 6.75,
"columns": [
[
{
"title": "用法",
"titleSync": false,
"halign": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 51.988373079128756,
"field": "data",
"checked": true,
"columnId": "data",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "剂量",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 55.016471480350916,
"checked": true,
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "滴速",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 55.31961796101854,
"field": "",
"checked": true,
"columnId": "",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"formatter2": "function(value,row,index,options,rowIndex,column){ return value + ' ' + row.unitCode_dictText; }",
"width": 53.6755374795018,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
},
{
"options": {
"left": 10,
"top": 144,
"height": 9,
"width": 210,
"borderWidth": "0.75",
"title": "undefined+beforeDragIn",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 10,
"top": 153,
"height": 9.75,
"width": 82.5,
"title": "执行人",
"field": "prepareName",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 111,
"top": 153,
"height": 9.75,
"width": 82.5,
"title": "时间",
"field": "date",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 151.5,
"paperNumberTop": 91
}
]
}

View File

@@ -0,0 +1,245 @@
{
"panels": [
{
"index": 1,
"name": 2,
"paperType": "自定义",
"height": 34,
"width": 58,
"paperList": {
"type": "自定义",
"width": 60,
"height": 40
},
"paperHeader": 0,
"paperFooter": 91.5,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"expandCss": "",
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.01,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "10px",
"rotate": 25,
"width": 100,
"height": 100,
"timestamp": false,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 6,
"top": 7.5,
"height": 10,
"width": 51,
"title": "文本",
"field": "patientName",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"hideTitle": true,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 70,
"top": 7.5,
"height": 10,
"width": 33,
"title": "文本",
"field": "genderEnum_enumText",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"hideTitle": true,
"fontSize": 7.5,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 119,
"top": 7.5,
"height": 10,
"width": 45,
"title": "文本",
"field": "age",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"hideTitle": true,
"fontSize": 7.5,
"fontWeight": "bold",
"textAlign": "right"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 6,
"top": 19.5,
"height": 12,
"width": 81,
"title": "频次 qd",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"fontSize": 8.25,
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 93,
"top": 19.5,
"height": 10,
"width": 70.5,
"title": "文本",
"field": "date",
"coordinateSync": false,
"widthHeightSync": false,
"qrCodeLevel": 0,
"hideTitle": true,
"fontSize": 7.5,
"fontWeight": "bold",
"textAlign": "right"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 4.5,
"top": 36,
"height": 30,
"width": 156,
"title": "undefined+beforeDragIn",
"field": "infuseData",
"coordinateSync": false,
"widthHeightSync": false,
"tableHeaderBackground": "#ffffff",
"tableBodyCellBorder": "noBorder",
"rowsColumnsMerge": "function(data, col, colIndex, rowIndex, tableData, printData){ \n // 合并前三列 (columnIndex 0-2)\n if (colIndex >= 0 && colIndex <= 2) {\n // 第一列显示合并后的单元格\n if (colIndex === 0) {\n return [1, 3]; // rowspan=1, colspan=3\n } \n // 其他两列不显示(被合并)\n else {\n return [0, 0]; // rowspan=0, colspan=0\n }\n }\n // 其他列正常显示\n return [1, 1]; // rowspan=1, colspan=1\n}",
"tableBodyRowBorder": "topBottomBorder",
"fontSize": 7.5,
"tableHeaderRepeat": "first",
"maxRows": 3,
"tableHeaderRowHeight": 6,
"tableHeaderFontSize": 6.75,
"columns": [
[
{
"title": "用法",
"titleSync": false,
"halign": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 37.54715833492632,
"field": "data",
"checked": true,
"columnId": "data",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "剂量",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 39.4492016246979,
"checked": true,
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "速度",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"width": 40.23797408295783,
"checked": true,
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"titleSync": false,
"align": "center",
"tableQRCodeLevel": 0,
"tableSummaryTitle": true,
"tableSummary": "",
"formatter2": "function(value,row,index,options,rowIndex,column){ return value + ' ' + row.unitCode_dictText; }",
"width": 38.765665957417966,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
}
],
"paperNumberLeft": 151.5,
"paperNumberTop": 91
}
]
}

View File

@@ -0,0 +1,734 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A4",
"height": 297,
"width": 210,
"paperList": {
"type": "A4",
"width": 210,
"height": 297
},
"paperHeader": 217.5,
"paperFooter": 771,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.7,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "36px",
"rotate": 25,
"width": 413,
"height": 310,
"timestamp": true,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 595.5,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 54.5,
"height": 20,
"width": 595.5,
"title": "门诊病历",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 81,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 460.5,
"top": 81,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 82.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 108,
"height": 13.5,
"width": 99,
"title": "医保",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 108,
"height": 13.5,
"width": 190.5,
"title": "电话",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "phone"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 460.5,
"top": 108,
"height": 13.5,
"width": 99,
"title": "医生",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 133.5,
"height": 13.5,
"width": 196.5,
"title": "病历号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "busNo"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 247.5,
"top": 133.5,
"height": 13.5,
"width": 200,
"title": "发病日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "onsetDate"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 159,
"height": 13.5,
"width": 50,
"title": "诊断",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "vxc"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 174,
"height": 30,
"width": 550,
"hideTitle": true,
"field": "diagnosisText",
"title": "无",
"lHeight": 20,
"formatter": "function(title, value, options, templateData, target, paperNo) {\n return value || '无';\n}",
"styler": "function(value, options, target, templateData, paperNo) {\n return { \n 'word-wrap': 'break-word',\n 'word-break': 'break-all',\n 'white-space': 'normal',\n 'line-height': '1.4'\n };\n}",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 10,
"top": 210,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 25.5,
"top": 217.5,
"height": 13.5,
"width": 50,
"title": "主诉",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 235.5,
"height": 33,
"width": 550,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "complaint",
"lHeight": 50
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 277.5,
"height": 13.5,
"width": 50,
"title": "现病史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 299.5,
"height": 31.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "presentIllness",
"title": "无",
"lHeight": 30
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 341,
"height": 13.5,
"width": 50,
"title": "既往史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 360,
"height": 25.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "pastIllness",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 396,
"height": 13.5,
"width": 50,
"title": "过敏史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 414,
"height": 33,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "allergyHistory",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 462,
"height": 13.5,
"width": 50,
"title": "家族史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 481.5,
"height": 22.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "familyHistory",
"title": "无",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 514.5,
"height": 13.5,
"width": 50,
"title": "个人史",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 535.5,
"height": 28.5,
"width": 550,
"title": " ",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "personalHistory",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 571.7500162124634,
"height": 13.5,
"width": 50,
"title": "体检",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 594.2500162124634,
"height": 30,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"title": "长文",
"lHeight": 20,
"formatter": "function(title, value, options, templateData, target, paperNo) {\n // 获取所有体检数据\n const height = templateData.height || '';\n const weight = templateData.weight || '';\n const temperature = templateData.temperature || '';\n const pulse = templateData.pulse || '';\n \n // 格式化每个字段\n let formattedHeight = '';\n if (height && !isNaN(height)) {\n formattedHeight = '身高:' + height + 'cm';\n }\n \n let formattedWeight = '';\n if (weight && !isNaN(weight)) {\n formattedWeight = '体重:' + weight + 'kg';\n }\n \n let formattedTemperature = '';\n if (temperature && !isNaN(temperature)) {\n formattedTemperature = '体温:' + temperature + '℃';\n }\n \n let formattedPulse = '';\n if (pulse && !isNaN(pulse)) {\n formattedPulse = '脉搏:' + pulse + '次/分';\n }\n \n // 组合所有信息\n const result = [\n formattedHeight,\n formattedWeight,\n formattedTemperature,\n formattedPulse\n ].filter(item => item !== '').join(' ');\n \n return result;\n}\n\n"
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 631.5,
"height": 13.5,
"width": 79.5,
"title": "辅助检查",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 651,
"height": 22.5,
"width": 550,
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "auxiliaryExam",
"title": "长文",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 678.2431640625,
"height": 13.5,
"width": 50,
"title": "处置",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 700.5,
"height": 21,
"width": 550,
"title": "无",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "treatment",
"lHeight": 30
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 25.5,
"top": 730,
"height": 13.5,
"width": 50,
"title": "治疗",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "physicalExamdsd",
"fontWeight": "bold"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 747,
"height": 25.5,
"width": 550,
"title": "无",
"coordinateSync": false,
"widthHeightSync": false,
"hideTitle": true,
"field": "physicalExam",
"lHeight": 20
},
"printElementType": {
"title": "长文",
"type": "longText"
}
},
{
"options": {
"left": 9,
"top": 774,
"height": 9,
"width": 576,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28.5,
"top": 787.5,
"height": 13.5,
"width": 223.5,
"title": "病人或家人签字:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 399,
"top": 787.5,
"height": 13.5,
"width": 186,
"title": "医生签字:",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 399,
"top": 811.5,
"height": 13.5,
"width": 186,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 28.5,
"top": 813,
"height": 13.5,
"width": 222,
"title": "日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime"
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,632 @@
{
"panels": [
{
"index": 1,
"name": 3,
"paperType": "A5",
"height": 210,
"width": 148,
"paperList": {
"type": "A5",
"width": 148,
"height": 210
},
"paperHeader": 0,
"paperFooter": 592.4409448818898,
"paperNumberDisabled": true,
"paperNumberContinue": true,
"panelAngle": 0,
"overPrintOptions": {
"content": "",
"opacity": 0.01,
"type": 1
},
"watermarkOptions": {
"content": "",
"fillStyle": "rgba(87, 13, 248, 0.5)",
"fontSize": "10px",
"rotate": 0,
"width": 100,
"height": 100,
"timestamp": false,
"format": "YYYY-MM-DD HH:mm"
},
"panelLayoutOptions": {
"layoutType": "column",
"layoutRowGap": 0,
"layoutColumnGap": 0
},
"printElements": [
{
"options": {
"left": 0,
"top": 22.5,
"height": 19.5,
"width": 420,
"title": "长春市朝阳区中医院",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 20.25,
"qrCodeLevel": 0,
"textAlign": "center",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 0,
"top": 50,
"height": 20,
"width": 420,
"title": "处方签",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 13.5,
"textAlign": "center",
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 90,
"height": 13.5,
"width": 100,
"title": "医保编号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 283,
"top": 90,
"height": 13.5,
"width": 117,
"title": "就诊类型",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "orgId_dictText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 117,
"height": 13.5,
"width": 100,
"title": "处方编号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "prescriptionNo",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 283,
"top": 117,
"height": 13.5,
"width": 117,
"title": "病人性质",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "contractName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 138,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 142.5,
"top": 153,
"height": 13.5,
"width": 100,
"title": "性别",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "genderEnum_enumText",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 153,
"height": 13.5,
"width": 99,
"title": "年龄",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "age",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 26,
"top": 154.5,
"height": 13.5,
"width": 100,
"title": "姓名",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "patientName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 142.5,
"top": 178.5,
"height": 13.5,
"width": 99,
"title": "科室",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "departmentName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 288,
"top": 178.5,
"height": 13.5,
"width": 99,
"title": "电话",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 180,
"height": 13.5,
"width": 100,
"title": "门诊号",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "encounterNo",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 205.5,
"height": 13.5,
"width": 141,
"title": "地址",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 195,
"top": 205.5,
"height": 13.5,
"width": 210,
"title": "开具日期",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "reqTime",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 25.5,
"top": 232.5,
"height": 13.5,
"width": 367.5,
"title": "临床诊断",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "conditionName"
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 256.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 28,
"top": 282,
"height": 9.75,
"width": 120,
"title": "Rp",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true,
"fontSize": 18,
"qrCodeLevel": 0
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 15,
"top": 306,
"height": 36,
"width": 390,
"title": "undefined+beforeDragIn",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"textAlign": "center",
"tableBorder": "border",
"tableHeaderFontWeight": "500",
"field": "prescriptionList",
"columns": [
[
{
"title": "名称",
"width": 55.386224315781,
"field": "itemName",
"checked": true,
"columnId": "itemName",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "规格",
"width": 59.41840807183531,
"field": "totalVolume",
"checked": true,
"columnId": "totalVolume",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "厂家",
"width": 79.59183673469389,
"checked": true,
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "单价",
"width": 45.49640338326492,
"field": "unitPrice",
"checked": true,
"columnId": "unitPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "数量",
"width": 41.658473534111906,
"field": "quantity",
"checked": true,
"columnId": "quantity",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "金额",
"width": 42.9159186212175,
"field": "totalPrice",
"checked": true,
"columnId": "totalPrice",
"fixed": false,
"rowspan": 1,
"colspan": 1
},
{
"title": "等级",
"width": 65.53273533909551,
"field": "contractName",
"checked": true,
"columnId": "contractName",
"fixed": false,
"rowspan": 1,
"colspan": 1
}
]
]
},
"printElementType": {
"title": "表格",
"type": "table",
"editable": true,
"columnDisplayEditable": true,
"columnDisplayIndexEditable": true,
"columnTitleEditable": true,
"columnResizable": true,
"columnAlignEditable": true,
"isEnableEditField": true,
"isEnableContextMenu": true,
"isEnableInsertRow": true,
"isEnableDeleteRow": true,
"isEnableInsertColumn": true,
"isEnableDeleteColumn": true,
"isEnableMergeCell": true
}
},
{
"options": {
"left": 25.5,
"top": 379.5,
"height": 13.5,
"width": 241.5,
"title": "用法",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 8.996109008789062,
"top": 510,
"height": 13.5,
"width": 100,
"title": "医师",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "doctorName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 113,
"top": 510,
"height": 13.5,
"width": 100,
"title": "发药",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 217,
"top": 510,
"height": 13.5,
"width": 100,
"title": "划价",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 318,
"top": 510,
"height": 13.5,
"width": 100,
"title": "调配",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "nickName",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 10,
"top": 532.5,
"height": 9,
"width": 400,
"borderWidth": "1.5",
"coordinateSync": false,
"widthHeightSync": false,
"fixed": true
},
"printElementType": {
"title": "横线",
"type": "hline"
}
},
{
"options": {
"left": 26,
"top": 551.5,
"height": 13.5,
"width": 120,
"title": "制表人",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "1",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
},
{
"options": {
"left": 289,
"top": 551.5,
"height": 13.5,
"width": 120,
"title": "金额",
"coordinateSync": false,
"widthHeightSync": false,
"fontSize": 12,
"qrCodeLevel": 0,
"field": "medTotalAmount",
"fixed": true
},
"printElementType": {
"title": "文本",
"type": "text"
}
}
],
"paperNumberLeft": 236,
"paperNumberTop": 573
}
]
}

View File

@@ -0,0 +1,14 @@
处方签 Prescription.json
处置单 Disposal.json
门诊日结 DailyOutpatientSettlement.json
门诊挂号 OutpatientRegistration.json
门诊收费 OutpatientBilling.json
门诊病历 OutpatientMedicalRecord.json
手术记录 OperativeRecord.json
门诊输液贴 OutpatientInfusion.json
药房打印 Pharmacy.json
红旗门诊病历 HQOutpatientMedicalRecord.json
预交金 AdvancePayment.json
中药药房处方单 ChineseMedicinePrescription.json
中药医生处方单 DocChineseMedicinePrescription.json

View File

@@ -0,0 +1,60 @@
<template>
<div class="table-section" v-loading="loading">
<EditableTable ref="editableTableRef" v-bind="$attrs" class="editable-table">
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</EditableTable>
</div>
</template>
<script setup>
import { ref } from 'vue';
import EditableTable from './EditableTable.vue';
defineOptions({
name: 'EditTable',
inheritAttrs: false,
});
const props = defineProps({
loading: {
type: Boolean,
default: false,
},
});
const editableTableRef = ref(null);
defineExpose({
get formRef() {
return editableTableRef.value?.formRef;
},
get tableRef() {
return editableTableRef.value?.tableRef;
},
validate: (...args) => editableTableRef.value?.validate(...args),
validateField: (...args) => editableTableRef.value?.validateField(...args),
resetFields: (...args) => editableTableRef.value?.resetFields(...args),
clearValidate: (...args) => editableTableRef.value?.clearValidate(...args),
get tableData() {
return editableTableRef.value?.tableData;
},
});
</script>
<style scoped lang="scss">
.table-section {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
.editable-table {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
</style>

View File

@@ -0,0 +1,567 @@
<template>
<el-form ref="formRef" :model="{ tableData }" :rules="rules" class="editable-table-form">
<div
v-if="showAddButton || showDeleteButton || searchFields.length > 0"
class="editable-table-toolbar"
>
<div class="toolbar-left">
<el-button v-if="showAddButton" type="primary" icon="Plus" @click="handleToolbarAdd">
添加行
</el-button>
<el-button
v-if="showDeleteButton"
type="danger"
icon="Delete"
:disabled="selectedRows.length === 0"
@click="handleToolbarDelete"
>
删除行
</el-button>
</div>
<div class="toolbar-right">
<el-input
v-if="searchFields.length > 0"
v-model="searchKeyword"
:placeholder="searchPlaceholder"
clearable
style="width: 300px"
@input="handleSearch"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
</div>
<el-table
ref="tableRef"
:data="filteredTableData"
:border="border"
:stripe="stripe"
:max-height="maxHeight || undefined"
:min-height="minHeight || undefined"
:height="!maxHeight && !minHeight ? '100%' : undefined"
:row-key="getRowKey"
:virtualized="useVirtualized"
v-bind="$attrs"
@selection-change="handleSelectionChange"
class="editable-table-inner"
>
<el-table-column v-if="showSelection" type="selection" width="55" align="center" />
<el-table-column
v-if="showRowActions"
:width="rowActionsColumnWidth"
align="center"
fixed="left"
>
<template #header>
<div
v-if="showSelection && selectedRows.length > 0 && !showDeleteButton"
style="display: flex; align-items: center; justify-content: center; gap: 4px"
>
<el-button type="danger" size="small" icon="Delete" link @click="handleDeleteSelected">
删除选中({{ selectedRows.length }})
</el-button>
</div>
<span v-else></span>
</template>
<template #default="scope">
<el-button
v-if="showRowAddButton"
type="primary"
link
icon="CirclePlus"
class="action-btn"
@click="handleAdd(scope.$index)"
title="增加"
/>
<el-button
v-if="showRowDeleteButton"
type="danger"
link
icon="Delete"
class="action-btn"
@click="handleDelete(scope.$index)"
title="删除"
/>
</template>
</el-table-column>
<el-table-column
v-for="col in filteredColumns"
:key="col.prop"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:fixed="col.fixed"
:align="col.align || 'center'"
:formatter="col.formatter"
>
<template #default="scope">
<template v-if="col.type === 'input'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-input
v-model="scope.row[col.prop]"
:placeholder="col.placeholder || `请输入${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
@blur="col.onBlur && col.onBlur(scope.row, scope.$index)"
@input="col.onInput && col.onInput(scope.row, scope.$index)"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
>
<template v-if="col.suffix" #suffix>{{ col.suffix }}</template>
</el-input>
</el-form-item>
</template>
<template v-else-if="col.type === 'number'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-input-number
v-model="scope.row[col.prop]"
:placeholder="col.placeholder || `请输入${col.label}`"
:disabled="col.disabled"
:min="col.min"
:max="col.max"
:precision="col.precision"
:controls="false"
style="width: 100%"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
/>
</el-form-item>
</template>
<template v-else-if="col.type === 'select'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-select
v-model="scope.row[col.prop]"
:placeholder="col.placeholder || `请选择${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
:filterable="col.filterable"
:multiple="col.multiple"
style="width: 100%"
:class="scope.row.error ? 'error-border' : ''"
@change="
async (value) => {
const checkBeforeChange = col.extraprops?.checkBeforeChange;
if (checkBeforeChange && typeof checkBeforeChange === 'function') {
const result = await checkBeforeChange(scope.row, scope.$index, value);
if (result === false) {
return;
}
}
if (col.onChange) {
col.onChange(scope.row, scope.$index, value);
}
}
"
>
<el-option
v-for="option in typeof col.options === 'function'
? col.options(scope.row, scope.$index)
: col.options || []"
:key="option.value"
:label="option.label"
:value="option.value"
@click="option.onClick && option.onClick(scope.row, option)"
/>
</el-select>
</el-form-item>
</template>
<template v-else-if="col.type === 'date'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-date-picker
v-model="scope.row[col.prop]"
:type="col.dateType || 'date'"
:placeholder="col.placeholder || `请选择${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
:value-format="col.valueFormat || 'YYYY-MM-DD'"
style="width: 100%"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
/>
</el-form-item>
</template>
<template v-else-if="col.type === 'slot'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<slot :name="col.slot || col.prop" :row="scope.row" :index="scope.$index" />
</el-form-item>
</template>
<template v-else>
<span>{{
col.formatter
? col.formatter(scope.row, scope.column, scope.row[col.prop])
: scope.row[col.prop]
}}</span>
</template>
</template>
</el-table-column>
</el-table>
<div v-if="$slots.footer" class="editable-table-footer">
<slot name="footer" :tableData="tableData" />
</div>
</el-form>
</template>
<script setup lang="ts">
import { ref, watch, nextTick, computed } from 'vue';
import { Search } from '@element-plus/icons-vue';
import type { EditableTableProps } from '../types/EditableTable.d';
defineOptions({
name: 'EditableTable',
});
const props = withDefaults(defineProps<EditableTableProps>(), {
modelValue: () => [],
rules: () => ({}),
defaultRow: () => ({}),
border: true,
stripe: false,
showSelection: false,
showAddButton: false,
showDeleteButton: false,
showRowActions: true,
showRowAddButton: true,
showRowDeleteButton: true,
searchFields: () => [],
virtualizedThreshold: 100,
});
const emit = defineEmits<{
'update:modelValue': [value: Record<string, any>[]];
add: [row: Record<string, any>, index: number];
delete: [row: Record<string, any>, index: number, isClear: boolean];
'selection-change': [selection: Record<string, any>[]];
'toolbar-add': [];
'toolbar-delete': [rows: Record<string, any>[]];
}>();
const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
const tableRef = ref<InstanceType<typeof import('element-plus').ElTable> | null>(null);
const selectedRows = ref<Record<string, any>[]>([]);
const searchKeyword = ref('');
const tableData = ref([...props.modelValue]);
// 行唯一 key用于虚拟滚动等
const autoRowId = ref(0);
const getRowKey = (row: Record<string, any>) => {
if (row.rowKey !== undefined && row.rowKey !== null) return row.rowKey;
if (row.id !== undefined && row.id !== null) return row.id;
if (!row._etKey) {
row._etKey = `et-${autoRowId.value++}`;
}
return row._etKey;
};
// 是否开启虚拟滚动:优先使用外部传入,其次根据数据量自动开启
const useVirtualized = computed(() => {
if (typeof props.virtualized === 'boolean') {
return props.virtualized;
}
const threshold = props.virtualizedThreshold ?? 100;
return tableData.value.length > threshold;
});
// 过滤列(支持条件显示)
const filteredColumns = computed(() => {
return props.columns.filter((col) => !col.vIf || col.vIf());
});
// 行操作列宽度:同时显示“增加+删除”则宽一点;只显示一个则缩窄
const rowActionsColumnWidth = computed(() => {
const showAdd = !!props.showRowAddButton;
const showDel = !!props.showRowDeleteButton;
if (showAdd && showDel) return 100;
if (showAdd || showDel) return 60;
// 如果两者都不显示,列也不会渲染;这里给个兜底
return 0;
});
const searchPlaceholder = computed(() => {
if (props.searchFields.length === 0) {
return '请输入搜索关键词';
}
const fieldLabels = props.searchFields
.map((field) => {
const column = props.columns.find((col) => col.prop === field);
return column?.label || field;
})
.filter(Boolean);
if (fieldLabels.length === 0) {
return '请输入搜索关键词';
}
if (fieldLabels.length === 1) {
return `请输入${fieldLabels[0]}`;
}
return `请输入${fieldLabels.join('')}`;
});
// 根据搜索关键词过滤表格数据
const filteredTableData = computed(() => {
if (!searchKeyword.value || props.searchFields.length === 0) {
return tableData.value;
}
const keyword = searchKeyword.value.toLowerCase();
return tableData.value.filter((row) => {
return props.searchFields.some((field) => {
const value = row[field];
if (value === null || value === undefined) {
return false;
}
return String(value).toLowerCase().includes(keyword);
});
});
});
watch(
() => props.modelValue,
(newVal) => {
if (newVal !== tableData.value) {
tableData.value = [...newVal];
}
},
{ deep: true }
);
watch(
tableData,
(newVal) => {
emit('update:modelValue', newVal);
},
{ deep: true }
);
const handleAdd = (index) => {
const newRow = { ...props.defaultRow };
tableData.value.splice(index + 1, 0, newRow);
nextTick(() => {
emit('add', newRow, index + 1);
});
};
const handleDelete = (index) => {
if (tableData.value.length === 1) {
Object.keys(tableData.value[0]).forEach((key) => {
tableData.value[0][key] = '';
});
Object.assign(tableData.value[0], { ...props.defaultRow });
emit('delete', tableData.value[0], index, true);
} else {
const deletedRow = tableData.value.splice(index, 1)[0];
emit('delete', deletedRow, index, false);
}
};
const handleSelectionChange = (selection) => {
selectedRows.value = selection;
emit('selection-change', selection);
};
// 删除所有选中的行
const handleDeleteSelected = () => {
if (selectedRows.value.length === 0) {
return;
}
// 获取选中行的索引
const selectedIndexes = selectedRows.value.map((row) => tableData.value.indexOf(row));
// 从后往前删除,避免索引变化问题
selectedIndexes.sort((a, b) => b - a);
// 如果选中了所有行且只剩一行,清空数据而不是删除
if (tableData.value.length === selectedRows.value.length && tableData.value.length === 1) {
Object.keys(tableData.value[0]).forEach((key) => {
tableData.value[0][key] = '';
});
Object.assign(tableData.value[0], { ...props.defaultRow });
emit('delete', tableData.value[0], 0, true);
} else {
// 删除选中的行
selectedIndexes.forEach((index) => {
if (index !== -1 && tableData.value.length > 1) {
const deletedRow = tableData.value.splice(index, 1)[0];
emit('delete', deletedRow, index, false);
}
});
}
// 清空选中状态
if (tableRef.value) {
tableRef.value.clearSelection();
}
selectedRows.value = [];
};
// 工具栏新增按钮
const handleToolbarAdd = () => {
const newRow = { ...props.defaultRow };
tableData.value.push(newRow);
nextTick(() => {
emit('toolbar-add');
emit('add', newRow, tableData.value.length - 1);
});
};
// 工具栏删除按钮
const handleToolbarDelete = () => {
if (selectedRows.value.length === 0) {
return;
}
emit('toolbar-delete', selectedRows.value);
handleDeleteSelected();
};
// 搜索处理
const handleSearch = () => {
// 搜索逻辑已在 computed 中处理
};
const validate = (callback) => {
if (formRef.value) {
return formRef.value.validate(callback);
}
};
const validateField = (props, callback) => {
if (formRef.value) {
return formRef.value.validateField(props, callback);
}
};
const resetFields = () => {
if (formRef.value) {
formRef.value.resetFields();
}
};
const clearValidate = (props) => {
if (formRef.value) {
formRef.value.clearValidate(props);
}
};
defineExpose({
formRef,
tableRef,
validate,
validateField,
resetFields,
clearValidate,
tableData,
});
</script>
<style scoped lang="scss">
.editable-table-form {
display: flex;
flex-direction: column;
height: 100%;
.editable-table-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding: 0 4px;
.toolbar-left {
display: flex;
gap: 8px;
}
.toolbar-right {
display: flex;
align-items: center;
}
}
:deep(.el-table.editable-table-inner) {
flex: 1;
display: flex;
flex-direction: column;
.el-table__body-wrapper {
flex: 1;
overflow: auto;
}
.el-table__cell {
position: relative;
overflow: visible;
vertical-align: top;
.cell {
position: relative;
overflow: visible;
}
}
}
:deep(.el-table__cell) {
overflow: visible;
vertical-align: top;
.cell {
overflow: visible;
}
}
// 错误信息往下撑开行高不影响上面布局
:deep(.el-form-item) {
margin-bottom: 0;
.el-form-item__error {
position: static;
line-height: 1.5;
padding-top: 4px;
font-size: 12px;
color: var(--el-color-danger);
display: block;
white-space: nowrap;
}
}
.action-btn {
margin: 4px;
:deep(.el-icon) {
font-size: 18px;
}
}
}
.editable-table-footer {
flex-shrink: 0;
margin-top: 16px;
}
</style>

View File

@@ -0,0 +1,157 @@
<template>
<div v-if="show" class="query-form-wrapper">
<el-form
ref="queryFormRef"
:model="queryParams"
:inline="true"
class="query-form"
:label-width="labelWidth"
>
<template v-for="item in displayedFormItems" :key="item.prop">
<FormItem
:item="item"
:model-value="queryParams[item.prop]"
:on-enter="handleQuery"
@update:model-value="(value) => (queryParams[item.prop] = value)"
@change="(value) => item.onChange && item.onChange(value)"
>
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</FormItem>
</template>
<el-form-item v-if="showDefaultButtons" style="margin-left: 20px">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button v-if="needCollapse" type="text" @click="toggleExpand" style="margin-left: 16px">
{{ isExpanded ? '收起' : '展开' }}
<el-icon class="el-icon--right">
<DArrowLeft v-if="isExpanded" class="collapse-arrow collapse-arrow--up" />
<DArrowRight v-else class="collapse-arrow collapse-arrow--down" />
</el-icon>
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import FormItem from './FormItem.vue';
import type { FilterProps } from '../types/Filter.d';
defineOptions({
name: 'Filter'
});
const props = withDefaults(defineProps<FilterProps>(), {
formItems: () => [],
show: true,
showDefaultButtons: true,
labelWidth: '120px',
showLabelColon: true,
});
const emit = defineEmits<{
query: [queryParams: Record<string, any>];
reset: [];
}>();
const queryFormRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
const isExpanded = ref(true);
const itemsPerRow = 4;
const normalizedFormItems = computed(() =>
(props.formItems || []).map((item) => ({
...item,
labelSuffix: item.labelSuffix ?? (props.showLabelColon ? '' : ''),
}))
);
const needCollapse = computed(() => {
if (!normalizedFormItems.value || normalizedFormItems.value.length === 0) return false;
let totalWidth = 0;
normalizedFormItems.value.forEach((item) => {
if (item.type === 'custom' || item.type === 'daterange') {
totalWidth += 2;
} else {
totalWidth += 1;
}
});
return totalWidth > itemsPerRow * 2;
});
const displayedFormItems = computed(() => {
if (!needCollapse.value || isExpanded.value) {
return normalizedFormItems.value;
}
const maxItems = itemsPerRow * 2;
let count = 0;
const result: any[] = [];
for (const item of normalizedFormItems.value) {
const itemWidth = item.type === 'custom' || item.type === 'daterange' ? 2 : 1;
if (count + itemWidth > maxItems) {
break;
}
result.push(item);
count += itemWidth;
}
return result;
});
const toggleExpand = () => {
isExpanded.value = !isExpanded.value;
};
const handleQuery = () => {
emit('query', props.queryParams);
};
const resetQuery = () => {
if (queryFormRef.value) {
queryFormRef.value.resetFields();
}
if (props.queryParams && Object.prototype.hasOwnProperty.call(props.queryParams, 'pageNum')) {
props.queryParams.pageNum = 1;
}
emit('reset');
};
defineExpose({
queryFormRef,
handleQuery,
resetQuery,
});
</script>
<style scoped lang="scss">
.query-form-wrapper {
flex-shrink: 0;
width: 100%;
.query-form {
width: 100%;
}
}
.collapse-arrow {
transition: transform 0.2s ease;
&.collapse-arrow--up {
transform: rotate(90deg);
}
&.collapse-arrow--down {
transform: rotate(90deg);
}
}
</style>

View File

@@ -0,0 +1,115 @@
<template>
<el-form
ref="formRef"
:model="model"
:rules="rules"
:label-width="labelWidth"
:inline="inline"
:label-position="labelPosition"
class="table-layout-form"
>
<template v-for="item in normalizedFormItems" :key="item.prop">
<FormItem
:item="item"
:model-value="model[item.prop]"
@update:model-value="(value) => (model[item.prop] = value)"
@change="(value) => item.onChange && item.onChange(value)"
>
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</FormItem>
</template>
</el-form>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import FormItem from './FormItem.vue';
import type { FormProps } from '../types/Form.d';
defineOptions({
name: 'Form'
});
const props = withDefaults(defineProps<FormProps>(), {
formItems: () => [],
rules: () => ({}),
labelWidth: '120px',
inline: false,
labelPosition: 'right',
showLabelColon: true,
});
const emit = defineEmits<{
validate: [callback?: (valid: boolean) => void];
}>();
const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
const normalizedFormItems = computed(() =>
(props.formItems || []).map((item) => ({
...item,
labelSuffix: item.labelSuffix ?? (props.showLabelColon ? '' : ''),
}))
);
// 表单验证
const validate = (callback) => {
if (formRef.value) {
return formRef.value.validate(callback);
}
};
// 验证指定字段
const validateField = (props, callback) => {
if (formRef.value) {
return formRef.value.validateField(props, callback);
}
};
// 重置表单
const resetFields = () => {
if (formRef.value) {
formRef.value.resetFields();
}
};
// 清除验证
const clearValidate = (props) => {
if (formRef.value) {
formRef.value.clearValidate(props);
}
};
// 滚动到指定字段
const scrollToField = (prop) => {
if (formRef.value) {
formRef.value.scrollToField(prop);
}
};
defineExpose({
formRef,
validate,
validateField,
resetFields,
clearValidate,
scrollToField,
});
</script>
<style scoped lang="scss">
.table-layout-form {
width: 100%;
// 非内联表单样式
&:not(.el-form--inline) {
:deep(.el-form-item) {
display: flex;
margin-right: 0;
}
}
}
</style>

View File

@@ -0,0 +1,196 @@
<template>
<el-form-item
:label="labelWithSuffix"
:prop="item.prop"
:required="item.required"
:class="{ 'form-item-double': item.type === 'custom' || item.type === 'daterange' }"
>
<el-input
v-if="item.type === 'input'"
:model-value="modelValue"
:placeholder="item.placeholder || `请输入${item.label}`"
:clearable="item.clearable !== false"
:style="item.style || { width: item.width || '200px' }"
v-bind="item.extraprops || {}"
@keyup.enter="handleEnter"
@update:model-value="handleUpdate"
/>
<el-select
v-else-if="item.type === 'select'"
:model-value="modelValue"
:placeholder="item.placeholder || `请选择${item.label}`"
:clearable="item.clearable !== false"
:style="item.style || { width: item.width || '200px' }"
:disabled="item.disabled"
v-bind="item.extraprops || {}"
:multiple="item.multiple !== false"
:filterable="item.filterable !== false"
:collapse-tags="item.collapseTags !== false"
@change="handleChange"
@update:model-value="(value) => handleUpdateWithCheck(value, item.checkBeforeChange)"
>
<el-option
v-for="option in item.options || []"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
<el-radio-group
v-else-if="item.type === 'radio'"
:model-value="modelValue"
v-bind="item.extraprops || {}"
@change="handleChange"
@update:model-value="handleUpdate"
>
<el-radio v-for="option in item.options || []" :key="option.value" :label="option.value">
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 单独日期 -->
<el-date-picker
v-else-if="item.type === 'date'"
:model-value="modelValue"
type="date"
:placeholder="item.placeholder || `请选择${item.label}`"
:clearable="item.clearable !== false"
:value-format="item.valueFormat || 'YYYY-MM-DD'"
:style="item.style || { width: item.width || '200px' }"
:disabled="item.disabled"
v-bind="item.extraprops || {}"
@change="handleChange"
@update:model-value="handleUpdate"
/>
<!-- 日期区间 -->
<QuickDateRange
v-else-if="item.type === 'daterange'"
:model-value="daterangeValue"
:start-placeholder="item.startPlaceholder || '开始日期'"
:end-placeholder="item.endPlaceholder || '结束日期'"
:value-format="item.valueFormat || 'YYYY-MM-DD'"
:clearable="item.clearable !== false"
:date-picker-style="daterangeStyle"
:attrs="item.extraprops || {}"
@change="handleChange"
@update:model-value="handleUpdate"
/>
<!-- 纯文本展示 -->
<span
v-else-if="item.type === 'text'"
:style="item.style || { width: item.width || '200px' }"
class="form-item-text"
>
{{ item.formatter ? item.formatter(modelValue) : modelValue ?? '' }}
</span>
<slot
v-else-if="item.type === 'custom'"
:name="item.slot || item.prop"
:item="item"
:modelValue="modelValue"
:updateModelValue="handleUpdate"
/>
</el-form-item>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import type { FormItemProps } from '../types/FormItem.d';
import QuickDateRange from './QuickDateRange.vue';
defineOptions({
name: 'FormItem',
});
const props = defineProps<FormItemProps>();
const emit = defineEmits<{
'update:modelValue': [value: any];
change: [value: any];
}>();
const labelWithSuffix = computed(() => {
const suffix = props.item.labelSuffix || '';
return `${props.item.label || ''}${suffix}`;
});
// 日期区间组件的值处理
const daterangeValue = computed<string[]>(() => {
if (props.item.type === 'daterange') {
if (Array.isArray(props.modelValue)) {
return props.modelValue.map((v: any) => String(v));
}
return [];
}
return [];
});
// 日期区间组件的样式处理
const daterangeStyle = computed(() => {
if (props.item.type === 'daterange') {
if (
typeof props.item.style === 'object' &&
props.item.style !== null &&
!Array.isArray(props.item.style)
) {
return props.item.style;
}
return { width: props.item.width || 'calc(316px + 7em)' };
}
return {};
});
const handleUpdate = (value: any) => {
emit('update:modelValue', value);
};
const handleUpdateWithCheck = async (value: any, shouldCheck = false) => {
if (shouldCheck) {
if (props.item.onChange && typeof props.item.onChange === 'function') {
const result = await props.item.onChange(value);
if (result === false) {
return;
}
}
}
handleUpdate(value);
};
const handleChange = (value: any) => {
emit('change', value);
};
const handleEnter = () => {
if (props.onEnter && typeof props.onEnter === 'function') {
props.onEnter();
}
};
</script>
<style scoped lang="scss">
:deep(.el-form-item) {
margin-bottom: 16px;
display: inline-flex;
align-items: flex-start;
vertical-align: top;
margin-right: 16px;
.el-form-item__label {
width: 7em !important;
min-width: 7em;
white-space: normal;
word-break: break-all;
line-height: 1.5;
padding-right: 8px;
text-align: right;
padding-top: 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
.el-form-item__content {
display: flex;
align-items: center;
}
}
</style>

View File

@@ -0,0 +1,143 @@
<template>
<el-form
ref="formRef"
:model="model"
:rules="rules"
:label-width="labelWidth"
:label-position="labelPosition"
class="form-layout-form"
>
<div class="form-items-container" :class="columns > 0 ? `form-layout-${columns}col` : ''">
<template v-for="(item, index) in normalizedFormItems" :key="item.prop">
<FormItem
:item="item"
:model-value="model[item.prop]"
@update:model-value="
async (value) => {
if (item.onChange && typeof item.onChange === 'function') {
const result = await item.onChange(value);
if (result === false) {
return;
}
}
model[item.prop] = value;
}
"
>
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</FormItem>
<span
v-if="
columns > 0 &&
index > 0 &&
(index + 1) % columns === 0 &&
index < normalizedFormItems.length - 1
"
class="form-item-break"
/>
</template>
</div>
</el-form>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import FormItem from './FormItem.vue';
import type { FormLayoutProps } from '../types/FormLayout.d';
defineOptions({
name: 'FormLayout',
});
const props = withDefaults(defineProps<FormLayoutProps>(), {
formItems: () => [],
rules: () => ({}),
labelWidth: '120px',
labelPosition: 'right',
showLabelColon: true,
columns: 0,
});
const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
const normalizedFormItems = computed(() =>
(props.formItems || []).map((item) => ({
...item,
labelSuffix: item.labelSuffix ?? (props.showLabelColon ? '' : ''),
}))
);
const validate = (callback) => {
if (formRef.value) {
return formRef.value.validate(callback);
}
};
const validateField = (props, callback) => {
if (formRef.value) {
return formRef.value.validateField(props, callback);
}
};
const resetFields = () => {
if (formRef.value) {
formRef.value.resetFields();
}
};
const clearValidate = (props) => {
if (formRef.value) {
formRef.value.clearValidate(props);
}
};
const scrollToField = (prop) => {
if (formRef.value) {
formRef.value.scrollToField(prop);
}
};
defineExpose({
formRef,
validate,
validateField,
resetFields,
clearValidate,
scrollToField,
});
</script>
<style scoped lang="scss">
.form-layout-form {
width: 100%;
.form-items-container {
display: flex;
flex-wrap: wrap;
column-gap: 16px;
row-gap: 16px;
.form-item-break {
flex-basis: 100%;
width: 0;
height: 0;
margin: 0;
padding: 0;
border: none;
}
}
:deep(.el-form-item) {
margin-bottom: 0;
justify-content: flex-start;
flex: 0 0 auto;
.el-form-item__content {
justify-content: flex-start;
text-align: left;
}
}
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div class="form-section">
<slot />
</div>
</template>
<script setup>
defineOptions({
name: 'FormSection',
});
</script>
<style scoped lang="scss">
.form-section {
flex-shrink: 0;
margin-bottom: 1rem;
}
</style>

View File

@@ -0,0 +1,39 @@
<template>
<div class="form-section">
<FormLayout ref="formLayoutRef" v-bind="$attrs">
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</FormLayout>
</div>
</template>
<script setup>
import { ref } from 'vue';
import FormLayout from './FormLayout.vue';
defineOptions({
name: 'FormSectionLayout',
inheritAttrs: false,
});
const formLayoutRef = ref(null);
defineExpose({
get formRef() {
return formLayoutRef.value?.formRef;
},
validate: (...args) => formLayoutRef.value?.validate(...args),
validateField: (...args) => formLayoutRef.value?.validateField(...args),
resetFields: (...args) => formLayoutRef.value?.resetFields(...args),
clearValidate: (...args) => formLayoutRef.value?.clearValidate(...args),
scrollToField: (...args) => formLayoutRef.value?.scrollToField(...args),
});
</script>
<style scoped lang="scss">
.form-section {
flex-shrink: 0;
margin-bottom: 1rem;
}
</style>

View File

@@ -0,0 +1,136 @@
<template>
<el-input
:model-value="displayValue"
:placeholder="placeholder"
:disabled="disabled"
:clearable="clearable"
@input="handleInput"
@blur="handleBlur"
@change="handleChange"
>
<template v-if="suffix" #suffix>{{ suffix }}</template>
</el-input>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
const props = defineProps({
modelValue: [Number, String],
placeholder: String,
disabled: Boolean,
clearable: {
type: Boolean,
default: true,
},
suffix: String,
precision: Number, // 小数位数
min: Number,
max: Number,
});
const emit = defineEmits(['update:modelValue', 'blur', 'change']);
const displayValue = computed(() => {
if (props.modelValue === null || props.modelValue === undefined || props.modelValue === '') {
return '';
}
return String(props.modelValue);
});
const handleInput = (value) => {
// 只允许数字、小数点和负号
let newValue = value.replace(/[^\d.-]/g, '');
// 只允许一个小数点
const parts = newValue.split('.');
if (parts.length > 2) {
newValue = parts[0] + '.' + parts.slice(1).join('');
}
// 只允许一个负号,且必须在开头
if (newValue.indexOf('-') > 0) {
newValue = newValue.replace(/-/g, '');
}
if (newValue.startsWith('-') && newValue.split('-').length > 2) {
newValue = '-' + newValue.replace(/-/g, '');
}
// 如果为空,直接返回空字符串
if (newValue === '' || newValue === '-') {
emit('update:modelValue', '');
return;
}
// 转换为数字
const numValue = parseFloat(newValue);
if (isNaN(numValue)) {
emit('update:modelValue', '');
return;
}
// 限制最小值
if (props.min !== undefined && numValue < props.min) {
newValue = String(props.min);
}
// 限制最大值
if (props.max !== undefined && numValue > props.max) {
newValue = String(props.max);
}
// 处理精度
if (props.precision !== undefined && newValue.includes('.')) {
const parts = newValue.split('.');
if (parts[1] && parts[1].length > props.precision) {
parts[1] = parts[1].substring(0, props.precision);
newValue = parts.join('.');
}
}
emit('update:modelValue', newValue);
};
const handleBlur = (event) => {
const value = event.target.value;
if (value === '' || value === '-') {
emit('update:modelValue', '');
emit('blur', event);
return;
}
const numValue = parseFloat(value);
if (isNaN(numValue)) {
emit('update:modelValue', '');
emit('blur', event);
return;
}
// 应用精度
let finalValue = numValue;
if (props.precision !== undefined) {
finalValue = parseFloat(numValue.toFixed(props.precision));
}
// 限制范围
if (props.min !== undefined && finalValue < props.min) {
finalValue = props.min;
}
if (props.max !== undefined && finalValue > props.max) {
finalValue = props.max;
}
emit('update:modelValue', String(finalValue));
emit('blur', event);
};
const handleChange = (value) => {
emit('change', value);
};
</script>
<style scoped lang="scss">
:deep(.el-input__inner) {
text-align: left;
}
</style>

View File

@@ -0,0 +1,29 @@
<template>
<Layout>
<template #default>
<div class="page-wrapper">
<slot />
</div>
</template>
<template v-if="$slots.footer" #footer>
<slot name="footer" />
</template>
</Layout>
</template>
<script setup>
import Layout from '@/components/Layout/index.vue';
defineOptions({
name: 'PageLayout',
});
</script>
<style scoped lang="scss">
.page-wrapper {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<div class="page-wrapper">
<slot />
</div>
</template>
<script setup>
defineOptions({
name: 'PageWrapper',
});
</script>
<style scoped lang="scss">
.page-wrapper {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
</style>

View File

@@ -0,0 +1,171 @@
<template>
<div class="quick-date-range">
<el-select v-model="quickType" class="quick-select" @change="handleQuickChange">
<el-option label="自定义时间段" value="custom" />
<el-option label="今天" value="today" />
<el-option label="昨天" value="yesterday" />
<el-option label="本周" value="thisWeek" />
<el-option label="上周" value="lastWeek" />
<el-option label="最近30日" value="last30Days" />
</el-select>
<el-date-picker
v-model="innerValue"
type="daterange"
range-separator="-"
:start-placeholder="startPlaceholder || '开始日期'"
:end-placeholder="endPlaceholder || '结束日期'"
:value-format="valueFormat"
:clearable="clearable"
:style="datePickerStyle"
v-bind="attrs"
@change="handleDateChange"
/>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue';
import type { QuickDateRangeProps } from '../types/QuickDateRange.d';
defineOptions({
name: 'QuickDateRange'
});
const props = withDefaults(defineProps<QuickDateRangeProps>(), {
modelValue: () => [],
startPlaceholder: '',
endPlaceholder: '',
valueFormat: 'YYYY-MM-DD',
clearable: true,
datePickerStyle: () => ({}),
attrs: () => ({}),
});
const emit = defineEmits<{
'update:modelValue': [value: string[]];
change: [value: string[]];
}>();
const innerValue = ref<string[]>(props.modelValue && props.modelValue.length ? [...props.modelValue] : []);
const quickType = ref<string>('custom');
watch(
() => props.modelValue,
(val) => {
if (!val || !val.length) {
innerValue.value = [];
quickType.value = 'custom';
} else {
innerValue.value = [...val];
}
},
{ deep: true }
);
const datePickerStyle = computed(() => {
return Object.assign({ width: '300px' }, props.datePickerStyle || {});
});
function formatDate(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
function getToday() {
const today = new Date();
const d = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const s = formatDate(d);
return [s, s];
}
function getYesterday() {
const today = new Date();
const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 1);
const s = formatDate(d);
return [s, s];
}
function getThisWeek() {
const today = new Date();
const day = today.getDay() || 7; // 周日返回 7
const monday = new Date(today);
monday.setDate(today.getDate() - day + 1);
const sunday = new Date(monday);
sunday.setDate(monday.getDate() + 6);
return [formatDate(monday), formatDate(sunday)];
}
function getLastWeek() {
const today = new Date();
const day = today.getDay() || 7;
const lastMonday = new Date(today);
lastMonday.setDate(today.getDate() - day - 6);
const lastSunday = new Date(lastMonday);
lastSunday.setDate(lastMonday.getDate() + 6);
return [formatDate(lastMonday), formatDate(lastSunday)];
}
function getLast30Days() {
const today = new Date();
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const start = new Date(end);
start.setDate(end.getDate() - 29);
return [formatDate(start), formatDate(end)];
}
function handleQuickChange(val: string) {
if (val === 'custom') {
// 自定义时间段,清空日期值
innerValue.value = [];
emit('update:modelValue', []);
emit('change', []);
return;
}
let range: string[] = [];
switch (val) {
case 'today':
range = getToday();
break;
case 'yesterday':
range = getYesterday();
break;
case 'thisWeek':
range = getThisWeek();
break;
case 'lastWeek':
range = getLastWeek();
break;
case 'last30Days':
range = getLast30Days();
break;
default:
range = [];
}
innerValue.value = range;
emit('update:modelValue', range);
emit('change', range);
}
function handleDateChange(val: string[] | null) {
// 用户手动选择时间段时,将预设切换为自定义
quickType.value = 'custom';
innerValue.value = val || [];
emit('update:modelValue', innerValue.value);
emit('change', innerValue.value);
}
</script>
<style scoped lang="scss">
.quick-date-range {
display: inline-flex;
align-items: center;
gap: 8px;
.quick-select {
width: 130px;
}
}
</style>

View File

@@ -0,0 +1,373 @@
<template>
<div class="table-container">
<div ref="tableWrapperRef" class="table-wrapper">
<el-table
ref="tableRef"
v-loading="loading"
:data="computedTableData"
:border="border"
:stripe="stripe"
:size="size"
:height="computedTableHeight"
:row-key="rowKey"
:highlight-current-row="highlightCurrentRow"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
style="width: 100%; height: 100%"
>
<!-- 通过配置数组生成的列 -->
<template v-for="column in tableColumns" :key="column.prop || column.type">
<el-table-column
v-if="column.type && column.type !== 'expand'"
:type="column.type"
:width="column.width"
:min-width="column.minWidth"
:align="column.align || 'center'"
:fixed="
column.type === 'selection'
? column.fixed !== undefined
? column.fixed
: 'left'
: column.fixed
"
:selectable="column.selectable"
/>
<!-- 展开列支持自定义插槽内容 -->
<el-table-column
v-else-if="column.type === 'expand'"
type="expand"
:width="column.width"
:min-width="column.minWidth"
:fixed="column.fixed"
>
<template #default="scope">
<slot :name="column.slot || 'expand'" :row="scope.row" :scope="scope" />
</template>
</el-table-column>
<!-- 普通数据列 -->
<el-table-column
v-else
:prop="column.prop"
:label="column.label"
:width="column.width"
:min-width="column.minWidth"
:align="column.align || 'left'"
:fixed="column.fixed"
:show-overflow-tooltip="column.showOverflowTooltip !== false"
>
<template v-if="column.slot" #default="scope">
<slot :name="column.slot" :row="scope.row" :scope="scope" />
</template>
<template v-else-if="column.formatter" #default="scope">
{{
column.formatter(
scope.row,
scope.column,
column.prop ? scope.row[column.prop] : undefined,
scope.$index
)
}}
</template>
</el-table-column>
</template>
<!-- 通过插槽自定义的列 -->
<slot name="table" />
</el-table>
</div>
<div v-if="showPagination" ref="paginationWrapperRef" class="pagination-wrapper">
<div
class="pagination-content"
:class="{ 'has-left-content': paginationLeftText || $slots.paginationLeft }"
>
<div v-if="paginationLeftText || $slots.paginationLeft" class="pagination-left">
<slot name="paginationLeft">
{{ paginationLeftText }}
</slot>
</div>
<pagination
v-show="computedTotal > 0"
:total="computedTotal"
:page="computedPageNo"
:limit="computedPageSize"
v-bind="paginationProps"
@pagination="handlePagination"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
import Pagination from '@/components/Pagination/index.vue';
import type { TableProps } from '../types/Table.d';
defineOptions({
name: 'Table',
});
const props = withDefaults(defineProps<TableProps>(), {
tableData: () => [],
loading: false,
border: true,
stripe: false,
size: 'default',
highlightCurrentRow: false,
tableColumns: () => [],
showPagination: false,
total: 0,
pageNo: 1,
pageSize: 20,
isAllData: false,
paginationLeftText: '',
paginationProps: () => ({}),
});
const emit = defineEmits<{
'row-click': [row: Record<string, any>, column: any, event: Event];
'selection-change': [selection: Record<string, any>[]];
'sort-change': [sortInfo: { column: any; prop: string; order: string }];
pagination: [pagination: { page: number; limit: number }];
}>();
const internalPageNo = ref(props.pageNo);
const internalPageSize = ref(props.pageSize);
watch(
() => [props.pageNo, props.pageSize],
([newPageNo, newPageSize]) => {
if (!props.isAllData) {
internalPageNo.value = newPageNo;
internalPageSize.value = newPageSize;
}
}
);
watch(
() => props.isAllData,
(isAllData) => {
if (isAllData) {
internalPageNo.value = props.pageNo;
internalPageSize.value = props.pageSize;
}
}
);
const computedPageNo = computed(() => {
return props.isAllData ? internalPageNo.value : props.pageNo;
});
const computedPageSize = computed(() => {
return props.isAllData ? internalPageSize.value : props.pageSize;
});
const computedTotal = computed(() => {
return props.isAllData ? props.tableData.length : props.total;
});
const computedTableData = computed(() => {
if (!props.isAllData) {
return props.tableData;
}
const start = (computedPageNo.value - 1) * computedPageSize.value;
const end = start + computedPageSize.value;
return props.tableData.slice(start, end);
});
const handlePagination = (pagination: { page: number; limit: number }) => {
if (props.isAllData) {
internalPageNo.value = pagination.page;
internalPageSize.value = pagination.limit;
} else {
emit('pagination', pagination);
}
nextTick(() => {
calculateTableHeight();
});
};
const tableRef = ref<InstanceType<typeof import('element-plus').ElTable> | null>(null);
const tableWrapperRef = ref<HTMLDivElement | null>(null);
const paginationWrapperRef = ref<HTMLDivElement | null>(null);
const dynamicTableHeight = ref<number | null>(null);
const paginationHeight = ref<number>(0);
const computedTableHeight = computed(() => {
if (props.tableHeight) {
return props.tableHeight;
}
if (props.maxHeight) {
return props.maxHeight;
}
if (dynamicTableHeight.value) {
const height = dynamicTableHeight.value - paginationHeight.value;
return height > 0 ? height : dynamicTableHeight.value;
}
return null;
});
const calculateTableHeight = () => {
nextTick(() => {
if (tableWrapperRef.value) {
const tableContainer = tableWrapperRef.value.parentElement;
if (tableContainer) {
const containerRect = tableContainer.getBoundingClientRect();
let height = containerRect.height;
if (props.showPagination && paginationWrapperRef.value && computedTotal.value > 0) {
const paginationRect = paginationWrapperRef.value.getBoundingClientRect();
paginationHeight.value = paginationRect.height;
height -= paginationRect.height;
} else {
paginationHeight.value = 0;
}
if (height > 0) {
dynamicTableHeight.value = height;
}
}
}
});
};
let resizeObserver: ResizeObserver | null = null;
let paginationObserver: ResizeObserver | null = null;
onMounted(() => {
calculateTableHeight();
const tableContainer = tableWrapperRef.value?.parentElement;
if (tableContainer && window.ResizeObserver) {
resizeObserver = new ResizeObserver(() => {
calculateTableHeight();
});
resizeObserver.observe(tableContainer);
} else {
window.addEventListener('resize', calculateTableHeight);
}
});
watch(
() => props.showPagination && computedTotal.value > 0 && paginationWrapperRef.value,
(shouldObserve) => {
if (shouldObserve && paginationWrapperRef.value && window.ResizeObserver) {
if (!paginationObserver) {
paginationObserver = new ResizeObserver(() => {
calculateTableHeight();
});
}
paginationObserver.observe(paginationWrapperRef.value);
} else if (paginationObserver && paginationWrapperRef.value) {
paginationObserver.unobserve(paginationWrapperRef.value);
}
},
{ immediate: true }
);
onUnmounted(() => {
if (resizeObserver) {
resizeObserver.disconnect();
}
if (paginationObserver) {
paginationObserver.disconnect();
}
if (!resizeObserver) {
window.removeEventListener('resize', calculateTableHeight);
}
});
watch(
() => props.tableData,
() => {
calculateTableHeight();
if (props.isAllData && internalPageNo.value !== 1) {
internalPageNo.value = 1;
}
},
{ deep: true }
);
watch(
() => [props.showPagination, computedTotal.value],
() => {
calculateTableHeight();
}
);
const handleRowClick = (row: Record<string, any>, column: any, event: Event) => {
emit('row-click', row, column, event);
};
const handleSelectionChange = (selection: Record<string, any>[]) => {
emit('selection-change', selection);
};
const handleSortChange = ({
column,
prop,
order,
}: {
column: any;
prop: string;
order: string;
}) => {
emit('sort-change', { column, prop, order });
};
defineExpose({
tableRef,
tableWrapperRef,
});
</script>
<style scoped lang="scss">
.table-container {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
.table-wrapper {
flex: 1;
min-height: 0;
overflow: hidden;
position: relative;
}
.pagination-wrapper {
flex-shrink: 0;
margin-top: 8px;
padding-bottom: 0;
overflow: visible;
}
.pagination-content {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 16px;
&.has-left-content {
justify-content: space-between;
}
}
.pagination-left {
flex-shrink: 0;
display: flex;
justify-content: flex-start;
align-items: center;
color: var(--el-text-color-regular);
font-size: 14px;
}
.pagination-content :deep(.pagination-container) {
.el-pagination {
margin-right: 16px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
</style>

View File

@@ -0,0 +1,27 @@
<template>
<div class="table-section">
<slot />
</div>
</template>
<script setup>
defineOptions({
name: 'TableSection',
});
</script>
<style scoped lang="scss">
.table-section {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
:deep(.editable-table) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
</style>

View File

@@ -0,0 +1,411 @@
<template>
<div class="table-layout-container">
<div class="card-content-wrapper">
<div
v-if="showSideQuery"
class="side-query-wrapper"
:class="{ collapsed: sideQueryCollapsed }"
>
<div v-if="!sideQueryCollapsed" class="side-query-header">
<el-input v-model="sideSearchKeyword" placeholder="搜索树节点" clearable size="small">
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
<div v-if="!sideQueryCollapsed" class="side-query-content">
<el-tree
ref="treeRef"
:data="treeDataWithAll"
:props="defaultProps"
:node-key="treeNodeKey"
:expand-on-click-node="false"
default-expand-all
highlight-current
@node-click="handleNodeClick"
@current-change="handleCurrentChange"
></el-tree>
</div>
</div>
<div v-if="showSideQuery" class="collapse-divider">
<el-button
circle
size="small"
class="collapse-btn"
@click="sideQueryCollapsed = !sideQueryCollapsed"
>
<el-icon>
<ArrowRight v-if="sideQueryCollapsed" />
<ArrowLeft v-else />
</el-icon>
</el-button>
</div>
<!-- 主内容区域 -->
<div
class="main-content-wrapper"
:class="{ 'with-side-query': showSideQuery && !sideQueryCollapsed }"
>
<Filter
v-if="showTopQuery"
ref="queryFormComponentRef"
:query-params="queryParams"
:form-items="formItems"
:show-default-buttons="showDefaultButtons"
@query="handleQuery"
@reset="resetQuery"
>
<template
v-for="item in customFormItems"
:key="item.prop"
v-slot:[item.slotName]="slotProps"
>
<slot :name="item.slotName" :item="slotProps.item" :queryParams="props.queryParams" />
</template>
<template #default="{ queryParams, handleQuery, resetQuery }">
<slot
name="topQuery"
:queryParams="queryParams"
:handleQuery="handleQuery"
:resetQuery="resetQuery"
/>
</template>
</Filter>
<!-- 操作按钮区域 -->
<div class="table-operation-bar">
<slot name="operations" />
</div>
<!-- 表格区域 -->
<Table
:table-data="tableData"
:loading="loading"
:border="border"
:stripe="stripe"
:size="size"
:table-height="tableHeight"
:max-height="maxHeight"
:row-key="rowKey"
:highlight-current-row="highlightCurrentRow"
:table-columns="tableColumns"
:show-pagination="showPagination"
:total="total"
:page-no="props.queryParams.pageNo"
:page-size="props.queryParams.pageSize"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
@pagination="handlePagination"
>
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps" />
</template>
</Table>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import Filter from './Filter.vue';
import Table from './Table.vue';
import type { TableLayoutProps, TreeNodeData } from '../types/TableLayout.d';
defineOptions({
name: 'TableLayout',
});
const props = withDefaults(defineProps<TableLayoutProps>(), {
tableData: () => [],
loading: false,
total: 0,
queryParams: () => ({
pageNo: 1,
pageSize: 20,
}),
sideQueryParams: () => ({}),
formItems: () => [],
showTopQuery: true,
showSideQuery: false,
showPagination: true,
showDefaultButtons: true,
sideWidth: 6,
border: true,
stripe: false,
size: 'default',
highlightCurrentRow: false,
siderData: () => [],
treeNodeKey: 'id',
tableColumns: () => [],
});
const emit = defineEmits<{
query: [queryParams: Record<string, any>];
reset: [];
pagination: [pagination: { page: number; limit: number }];
'row-click': [row: Record<string, any>, column: any, event: Event];
'selection-change': [selection: Record<string, any>[]];
'sort-change': [sortInfo: { column: any; prop: string; order: string }];
'side-query': [node: TreeNodeData];
'reset-side-query': [];
}>();
const queryFormRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
import type { FilterExpose } from '../types/Filter.d';
const queryFormComponentRef = ref<FilterExpose | null>(null);
const sideSearchKeyword = ref<string>('');
const treeRef = ref<InstanceType<typeof import('element-plus').ElTree> | null>(null);
const currentTreeNode = ref<TreeNodeData | null>(null);
const sideQueryCollapsed = ref<boolean>(false);
const customFormItems = computed(() => {
return props.formItems
.filter((item) => item.type === 'custom')
.map((item) => ({
...item,
slotName: item.slot || item.prop,
}));
});
const defaultProps = {
children: 'children',
label: 'label',
};
const filteredSiderData = computed(() => {
if (!sideSearchKeyword.value || !props.siderData || props.siderData.length === 0) {
return props.siderData;
}
const keyword = sideSearchKeyword.value.toLowerCase();
const filterTree = (nodes: TreeNodeData[]): TreeNodeData[] => {
if (!nodes || nodes.length === 0) return [];
return nodes
.map((node: TreeNodeData) => {
const label = (node[defaultProps.label] || '').toLowerCase();
const match = label.includes(keyword);
const children = node[defaultProps.children];
let filteredChildren: TreeNodeData[] | null = null;
if (children && children.length > 0) {
filteredChildren = filterTree(children);
}
if (match || (filteredChildren && filteredChildren.length > 0)) {
return {
...node,
[defaultProps.children]: filteredChildren,
};
}
return null;
})
.filter(Boolean) as TreeNodeData[];
};
return filterTree(props.siderData);
});
const treeDataWithAll = computed(() => {
const children = filteredSiderData.value || [];
return [
{
[props.treeNodeKey]: '__ALL__',
[defaultProps.label]: '全部',
[defaultProps.children]: children || [],
},
];
});
const handleQuery = () => {
props.queryParams.pageNo = 1;
emit('query', props.queryParams);
if (currentTreeNode.value) {
emit('side-query', currentTreeNode.value);
}
};
const handleNodeClick = (data: TreeNodeData, node: any) => {
currentTreeNode.value = data;
if (treeRef.value && data && data[props.treeNodeKey]) {
treeRef.value.setCurrentKey(data[props.treeNodeKey]);
}
handleQuery();
};
const handleCurrentChange = (data: TreeNodeData, node: any) => {
currentTreeNode.value = data;
};
const resetQuery = () => {
if (queryFormComponentRef.value?.queryFormRef) {
queryFormComponentRef.value.queryFormRef.resetFields();
}
if (props.queryParams) {
Object.keys(props.queryParams).forEach((key) => {
if (key !== 'pageNo' && key !== 'pageSize') {
if (Array.isArray(props.queryParams[key])) {
props.queryParams[key] = [];
} else if (typeof props.queryParams[key] === 'object' && props.queryParams[key] !== null) {
props.queryParams[key] = null;
} else {
props.queryParams[key] = '';
}
}
});
if (Object.prototype.hasOwnProperty.call(props.queryParams, 'pageNo')) {
props.queryParams.pageNo = 1;
}
}
emit('reset');
handleQuery();
};
const handlePagination = (pagination) => {
if (props.queryParams) {
props.queryParams.pageNo = pagination.page;
props.queryParams.pageSize = pagination.limit;
}
emit('pagination', pagination);
emit('query', props.queryParams);
if (currentTreeNode.value) {
emit('side-query', currentTreeNode.value);
}
};
const handleRowClick = (row, column, event) => {
emit('row-click', row, column, event);
};
const handleSelectionChange = (selection) => {
emit('selection-change', selection);
};
const handleSortChange = ({ column, prop, order }) => {
emit('sort-change', { column, prop, order });
};
defineExpose({
queryFormRef: computed(() => queryFormComponentRef.value?.queryFormRef),
handleQuery,
resetQuery,
});
</script>
<style scoped lang="scss">
.table-layout-container {
height: 100%;
padding: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
box-sizing: border-box;
.main-content-card {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
min-height: 0;
overflow: visible;
:deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
padding: 16px 16px 8px 16px;
min-height: 0;
overflow: visible;
}
}
.card-content-wrapper {
flex: 1;
display: flex;
gap: 0;
min-height: 0;
position: relative;
}
.collapse-divider {
flex-shrink: 0;
width: 1px;
background-color: #ebeef5;
position: relative;
display: flex;
align-items: flex-start;
justify-content: center;
margin: 0 12px;
.collapse-btn {
position: absolute;
left: 50%;
top: 18px;
transform: translateX(-50%);
background-color: #fff;
border: 1px solid #ebeef5;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
z-index: 10;
width: 24px;
height: 24px;
&:hover {
background-color: #409eff;
color: #fff;
border-color: #409eff;
}
}
}
.side-query-wrapper {
flex-shrink: 0;
display: flex;
flex-direction: column;
transition: width 0.3s, opacity 0.3s;
overflow: hidden;
&.collapsed {
width: 0;
opacity: 0;
padding: 0;
border: none;
}
.side-query-header {
flex-shrink: 0;
margin-bottom: 12px;
display: flex;
align-items: center;
}
.side-query-content {
flex: 1;
min-height: 0;
overflow-y: auto;
:deep(.el-tree--highlight-current) {
background-color: #fff !important;
}
}
}
.main-content-wrapper {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
min-width: 0;
overflow: hidden;
}
.table-operation-bar {
flex-shrink: 0;
margin-bottom: 8px;
}
}
</style>

View File

@@ -1,188 +1,125 @@
<!--
* @Author: sjjh
* @Date: 2025-04-07 20:42:45
* @Description:住院患者信息给医生用带折叠
-->
<template>
<div class="inPatientBarDoctorFold-container">
<div class="basic_info">
<div class="patient-header white-bg">
<div class="select_wrapper_div">
<b class="bedNumber" style="margin-left: 12px">{{ patientInfo?.bedName }}</b>
<label class="content-text-color" style="margin-left: 12px; color: #a15209">
{{ patientInfo?.patientName }}
<span class="sex-age"> {{ patientInfo?.sexName }}/{{ patientInfo?.age }} </span>
<b class="bedNumber">{{ patientInfo?.bedName || '未分床' }}</b>
<label class="patient-name">
{{ patientInfo?.patientName || '-' }}
<span class="sex-age">
{{ formatSexAge(patientInfo?.sexName, patientInfo?.age) }}
</span>
</label>
<div style="display: flex; margin-left: 8px">
<!-- 状态展示// TODO 后端给状态,前段 -->
<div class="tag-list" v-if="patientInfo?.list && patientInfo.list.length > 0">
<ball-tag
style="margin-right: 4px"
v-for="item in patientInfo?.list"
v-for="item in patientInfo.list"
:key="item"
:tagId="item"
class="tag-item"
></ball-tag>
</div>
<div
class="gray-border"
v-show="patientInfo?.feeTypeName && patientInfo?.feeTypeName !== ''"
>
{{ patientInfo?.feeTypeName }}
<div class="gray-border" v-if="patientInfo?.feeTypeName">
{{ patientInfo.feeTypeName }}
</div>
<label style="margin-left: 24px">
<label class="info-label">
<span class="label-text-color">住院</span>
<span class="content-text-color">{{ patientInfo?.inHospitalDays + '天' }}</span>
<span class="content-text-color">{{ formatDays(patientInfo?.inHospitalDays) }}</span>
</label>
<label style="margin-left: 24px">
<label class="info-label" v-if="patientInfo?.inOrgTime">
<span class="label-text-color">入科</span>
<span class="content-text-color">{{ patientInfo?.inDeptDate }}</span>
<span class="content-text-color">{{ patientInfo.inOrgTime }}</span>
</label>
<label style="margin-left: 24px">
<label class="info-label" v-if="patientInfo?.inHospitalTime">
<span class="label-text-color">入院时间</span>
<span class="content-text-color">{{ patientInfo?.inHospitalTime }}</span>
<span class="content-text-color">{{ patientInfo.inHospitalTime }}</span>
</label>
<label style="margin-left: 24px">
<span class="label-text-color">住院号:{{ patientInfo?.busNo }}</span>
<label class="info-label" v-if="patientInfo?.busNo">
<span class="label-text-color">住院号</span>
<span class="content-text-color">{{ patientInfo.busNo }}</span>
</label>
<svg-icon icon-class="hipCopy" height="20px" width="20px" class="copy-svg" />
<label style="margin-left: 30px">
<label class="info-label diagnosis-label" v-if="patientInfo?.regDiagnosisName">
<span class="label-text-color">诊断</span>
<span class="content-text-color">{{ patientInfo?.regDiagnosisName }}</span>
<span class="content-text-color">{{ patientInfo.regDiagnosisName }}</span>
</label>
<label class="info-label">
<span class="label-text-color">费用</span>
<span class="content-text-color">{{ formatMoney(patientInfo?.totalAmount) }}</span>
</label>
<label class="info-label">
<span class="label-text-color">余额</span>
<span class="content-text-color">{{ formatMoney(patientInfo?.balanceAmount) }}</span>
</label>
<!-- <div style="margin-left: auto">
<el-icon v-if="expand" @click="toggleExpand"><ArrowUpBold /></el-icon>
<el-icon v-else @click="toggleExpand"><ArrowDownBold /></el-icon>
</div> -->
</div>
</div>
</div>
<div v-if="expand" class="expand_more">
<div style="background-color: #ffffff">
<div style="margin-top: -10px">
<label style="font-size: 14px">
<div class="expand-content">
<div class="expand-section">
<label class="expand-label">
<span class="primary-text">过敏</span>
<span class="primary-text">{{ patientInfo?.allergies || '无过敏史' }}</span>
</label>
<label style="font-size: 14px; margin-left: 32px" v-show="patientInfo?.insuplcAdmdvsName">
<span class="primary-text">医保统筹区:</span>
<span class="primary-text">{{ patientInfo?.insuplcAdmdvsName }}</span>
<label class="expand-label" v-if="patientInfo?.insuplcAdmdvsName">
<span class="primary-text">医保统筹区</span>
<span class="primary-text">{{ patientInfo.insuplcAdmdvsName }}</span>
</label>
<label style="font-size: 14px; margin-left: 32px" v-show="patientInfo?.ciType">
<label class="expand-label" v-if="patientInfo?.ciType">
<span class="primary-text">商保信息</span>
<span class="primary-text">{{ patientInfo?.ciType }}</span>
<span class="primary-text">{{ patientInfo.ciType }}</span>
</label>
<div style="display: flex; flex-wrap: nowrap; margin-top: 8px; white-space: nowrap">
<div
class="blue-bg"
style="background-color: #f1faff; flex-shrink: 0; min-width: fit-content"
>
<div class="info-tags">
<div class="blue-bg">
<span class="content-text-color">
{{
patientInfo?.height && patientInfo?.weight
? `${patientInfo?.height}cm/${patientInfo?.weight}kg`
: '身高/体重'
}}
{{ formatHeightWeight(patientInfo?.height, patientInfo?.weight) }}
</span>
</div>
<div
class="blue-bg"
style="
margin-left: 24px;
background-color: #f1faff;
flex-shrink: 0;
min-width: fit-content;
"
v-show="patientInfo?.postoperativeDays"
>
<span class="content-text-color">术后{{ patientInfo?.postoperativeDays }}</span>
<div class="blue-bg" v-if="patientInfo?.postoperativeDays">
<span class="content-text-color">术后{{ patientInfo.postoperativeDays }}</span>
</div>
<div
class="blue-bg"
style="
margin-left: 16px;
background-color: #f1faff;
flex-shrink: 0;
min-width: fit-content;
"
v-show="patientInfo?.poorTypeName"
>
<span class="label-text-color">贫困类型:</span>
<span class="content-text-color" style="margin-left: 4px">{{
patientInfo?.poorTypeName
}}</span>
<div class="blue-bg" v-if="patientInfo?.poorTypeName">
<span class="label-text-color">贫困类型</span>
<span class="content-text-color">{{ patientInfo.poorTypeName }}</span>
</div>
<div
class="blue-bg"
style="
margin-left: 16px;
background-color: #f1faff;
flex-shrink: 0;
min-width: fit-content;
"
v-show="patientInfo?.pathwayName"
>
<span class="label-text-color">路径情况:</span>
<span class="content-text-color" style="margin-left: 4px">{{
patientInfo?.pathwayName
}}</span>
<div class="blue-bg" v-if="patientInfo?.pathwayName">
<span class="label-text-color">路径情况</span>
<span class="content-text-color">{{ patientInfo.pathwayName }}</span>
</div>
</div>
</div>
</div>
<div style="background-color: #ffffff">
<div style="margin-top: -10px">
<div class="expand-content">
<div class="expand-section">
<div class="patient-board">
<div class="item-center">
<div class="line-block">
<div class="line-block-top">
<span class="label-text-color">科室</span>
<span class="content-text-color">{{ patientInfo?.admissionDeptName }}</span>
<span class="content-text-color">{{
patientInfo?.admissionDeptName || '-'
}}</span>
</div>
<div class="line-block-bottom">
<span class="label-text-color">病区</span>
<span class="content-text-color">{{ patientInfo?.deptNurseName }}</span>
<span class="content-text-color">{{ patientInfo?.deptNurseName || '-' }}</span>
</div>
</div>
<div class="line-block">
<div class="line-block-top">
<span class="label-text-color">主治医生</span>
<span class="content-text-color">{{ patientInfo?.masterDoctorName }}</span>
<span class="content-text-color">{{ patientInfo?.masterDoctorName || '-' }}</span>
</div>
<div class="line-block-bottom">
<span class="label-text-color">责任护士</span>
<span class="content-text-color">{{ patientInfo?.masterNurseName }}</span>
</div>
</div>
<div class="line-blockMoney">
<div class="line-blockMoney-top">
<span class="label-text-color">费用</span>
</div>
<div class="line-blockMoney-bottom">
<b class="money-content size-15">{{
patientInfo?.totalAmount ? patientInfo?.totalAmount : 0
}}</b>
<span class="content-text-color">{{ patientInfo?.masterNurseName || '-' }}</span>
</div>
</div>
<div class="line-blockMoney">
<div class="line-blockMoney-top">
<span class="label-text-color">预交金</span>
</div>
<div class="line-blockMoney-bottom">
<b class="money-content size-15">{{
patientInfo?.prepayAmount ? patientInfo?.prepayAmount : 0
}}</b>
</div>
</div>
<div class="line-blockMoney">
<div class="line-blockMoney-top">
<span class="label-text-color">余额</span>
</div>
<div class="line-blockMoney-bottom">
<b class="money-content size-15">{{
patientInfo?.balance ? patientInfo?.balance : 0
}}</b>
<b class="money-content size-15">{{ formatMoney(patientInfo?.prepayAmount) }}</b>
</div>
</div>
</div>
@@ -192,45 +129,57 @@
</div>
</div>
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue';
<script setup lang="ts">
import { ref, watch } from 'vue';
import BallTag from './components/BallTag.vue';
import { patientInfo } from '@/views/inpatientDoctor/home/store/patient.js';
// import { ElMessage } from 'element-plus'
const expand = ref(false);
const showDividers = ref(true);
// 示例方法:切换显示状态
const toggleDividers = () => {
showDividers.value = !showDividers.value;
};
const iconClass = ref('hipBarDown');
// 切换展开状态的方法
function toggleExpand() {
expand.value = !expand.value;
iconClass.value = expand.value ? 'hipBarUp' : 'hipBarDown';
toggleDividers();
interface Props {
visitCode?: string;
}
const fetchPatientInfoById = async (patientId) => {
// 查询患者信息
console.log(patientId);
};
const props = defineProps({
const props = withDefaults(defineProps<Props>(), {
visitCode: '',
});
watch(
() => props.visitCode,
(val) => {
if (val !== null && val !== '') {
fetchPatientInfoById(val);
}
const expand = ref<boolean>(false);
// 格式化性别和年龄
const formatSexAge = (sexName?: string, age?: number | string): string => {
const sex = sexName || '';
const ageStr = age !== undefined && age !== null ? String(age) : '';
if (sex && ageStr) {
return `${sex}/${ageStr}`;
} else if (sex) {
return sex;
} else if (ageStr) {
return ageStr;
}
);
return '-';
};
// 格式化天数
const formatDays = (days?: number | string): string => {
if (days === undefined || days === null || days === '') {
return '-';
}
return `${days}`;
};
// 格式化身高体重
const formatHeightWeight = (height?: number | string, weight?: number | string): string => {
if (height && weight) {
return `${height}cm/${weight}kg`;
}
return '身高/体重';
};
// 格式化金额
const formatMoney = (amount?: number | string): number => {
if (amount === undefined || amount === null || amount === '') {
return 0;
}
return Number(amount) || 0;
};
defineOptions({
name: 'NurserDoctorPatientBarminimal',
@@ -240,27 +189,77 @@ defineOptions({
<style lang="scss" scoped>
.inPatientBarDoctorFold-container {
border-bottom: 1px solid #ebeef5;
background-color: #ffffff;
align-items: center;
.basic_info {
height: 43px;
min-height: 44px;
padding: 0 8px;
display: flex;
align-items: center;
}
/* expand_more */
.expand_more {
width: 100%;
height: 56px;
display: flex;
justify-content: space-between;
flex-direction: column;
padding: 0 8px;
}
.expand-content {
background-color: #ffffff;
}
.expand-section {
margin-top: -10px;
padding: 8px 0;
}
.patient-header {
width: 100%;
padding: 6px 0;
font-size: 13px;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
.select_wrapper_div {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
width: 100%;
}
.bedNumber {
font-weight: bold;
font-size: 18px;
margin-left: 12px;
color: #1f2933;
}
.patient-name {
margin-left: 12px;
color: #a15209;
font-weight: 500;
}
.sex-age {
margin-left: 20px;
margin-left: 8px;
color: var(--hip-color-text-description);
font-size: 14px;
font-weight: normal;
}
.tag-list {
display: flex;
align-items: center;
margin-left: 8px;
gap: 4px;
}
.tag-item {
margin-right: 4px;
}
.gray-border {
@@ -270,43 +269,66 @@ defineOptions({
align-items: center;
border: 1px solid var(--hip-color-text-description);
border-radius: 20px;
padding: 0px 8px;
padding: 0 8px;
font-size: 12px;
}
.info-label {
margin-left: 24px;
white-space: nowrap;
&:first-of-type {
margin-left: 0;
}
}
.diagnosis-label {
margin-left: 30px;
}
.copy-svg {
fill: var(--hip-color-primary);
cursor: pointer;
margin-left: 4px;
transition: opacity 0.2s;
&:hover {
opacity: 0.8;
}
}
}
.expand-label {
font-size: 14px;
margin-right: 32px;
white-space: nowrap;
&:first-child {
margin-right: 32px;
}
}
.info-tags {
display: flex;
flex-wrap: nowrap;
margin-top: 8px;
white-space: nowrap;
gap: 16px;
}
.size-15 {
font-size: 15px;
}
.bedNumber {
font-weight: bold;
font-size: 18px;
}
.primary-text {
color: var(--hip-color-primary);
}
.flex-between {
display: flex;
justify-content: space-between;
}
.item-center {
display: flex;
align-items: center;
}
.flex-row {
display: flex;
}
.patient-board {
margin-left: 20px;
@@ -330,10 +352,8 @@ defineOptions({
margin-bottom: 8px;
}
.money-content {
color: #ff8616;
font-size: 20px;
font-weight: 500;
&-bottom {
margin-top: 4px;
}
}
@@ -354,7 +374,7 @@ defineOptions({
}
&-top {
margin-bottom: 0px;
margin-bottom: 0;
}
.money-content {
@@ -378,13 +398,24 @@ defineOptions({
justify-content: center;
align-items: center;
background-color: #f1faff;
padding-left: 8px;
padding-right: 8px;
border-radius: 4px; /*圆角*/
padding: 4px 8px;
border-radius: 4px;
flex-shrink: 0;
min-width: fit-content;
white-space: nowrap;
.content-text-color {
margin-left: 0;
}
.label-text-color {
margin-right: 4px;
}
}
.label-text-color {
font-size: 14px;
color: #666666;
}
.content-text-color {

View File

@@ -0,0 +1,42 @@
/**
* Dialog 尺寸类型
*/
export type DialogSize = 'small' | 'medium' | 'large';
/**
* Dialog 组件的 Props 类型
*/
export interface DialogProps {
/** 对话框标题 */
title?: string;
/** 对话框尺寸 */
size?: DialogSize;
/** 自定义宽度 */
width?: string | number;
/** 自定义高度 */
height?: string | number;
/** 是否显示对话框 */
modelValue?: boolean;
/** 是否在关闭时销毁子元素 */
destroyOnClose?: boolean;
/** 是否将对话框追加到 body 上 */
appendToBody?: boolean;
/** 是否可以通过点击遮罩层关闭对话框 */
closeOnClickModal?: boolean;
/** 是否可以通过按下 ESC 关闭对话框 */
closeOnPressEscape?: boolean;
/** 是否显示关闭按钮 */
showClose?: boolean;
/** 是否在对话框出现时将 body 滚动锁定 */
lockScroll?: boolean;
/** 自定义类名 */
customClass?: string;
/** 是否可拖拽 */
draggable?: boolean;
/** 是否全屏 */
fullscreen?: boolean;
/** 是否显示加载状态 */
loading?: boolean;
/** 对话框打开前的回调 */
beforeClose?: (done: () => void) => void;
}

View File

@@ -0,0 +1,99 @@
import type { FormItemOption } from './FormItem.d';
/**
* 可编辑表格列配置类型
*/
export interface EditableTableColumn {
/** 列字段名 */
prop: string;
/** 列标签 */
label: string;
/** 列宽度 */
width?: string | number;
/** 最小宽度 */
minWidth?: string | number;
/** 是否固定列 */
fixed?: boolean | 'left' | 'right';
/** 对齐方式 */
align?: 'left' | 'center' | 'right';
/** 列类型 */
type?: 'input' | 'number' | 'select' | 'date' | 'slot';
/** 占位符 */
placeholder?: string;
/** 是否禁用 */
disabled?: boolean | ((row: Record<string, any>, index: number) => boolean);
/** 是否可清空 */
clearable?: boolean;
/** 是否可搜索select 类型) */
filterable?: boolean;
/** 是否多选select 类型) */
multiple?: boolean;
/** 最小值number 类型) */
min?: number;
/** 最大值number 类型) */
max?: number;
/** 精度number 类型) */
precision?: number;
/** 日期类型date 类型) */
dateType?: 'date' | 'datetime' | 'daterange';
/** 日期格式 */
valueFormat?: string;
/** 选项列表select 类型) */
options?: FormItemOption[] | ((row: Record<string, any>, index: number) => FormItemOption[]);
/** 自定义插槽名称slot 类型) */
slot?: string;
/** 格式化函数 */
formatter?: (row: Record<string, any>, column: any, cellValue: any) => string;
/** 验证规则 */
rules?: any;
/** 后缀文本input 类型) */
suffix?: string;
/** 条件显示 */
vIf?: () => boolean;
/** 失焦回调 */
onBlur?: (row: Record<string, any>, index: number) => void;
/** 输入回调 */
onInput?: (row: Record<string, any>, index: number) => void;
/** 变更回调 */
onChange?: (row: Record<string, any>, index: number, value?: any) => void;
}
/**
* EditableTable 组件的 Props 类型
*/
export interface EditableTableProps {
/** 表格数据 */
modelValue: Record<string, any>[];
/** 列配置 */
columns: EditableTableColumn[];
/** 表单验证规则 */
rules?: Record<string, any>;
/** 默认行数据 */
defaultRow?: Record<string, any>;
/** 是否显示边框 */
border?: boolean;
/** 是否显示斑马纹 */
stripe?: boolean;
/** 最大高度 */
maxHeight?: string | number;
/** 最小高度 */
minHeight?: string | number;
/** 是否开启虚拟滚动(不传则根据数据量自动开启) */
virtualized?: boolean;
/** 自动开启虚拟滚动的行数阈值,默认 100 */
virtualizedThreshold?: number;
/** 是否显示选择列 */
showSelection?: boolean;
/** 是否显示新增按钮 */
showAddButton?: boolean;
/** 是否显示删除按钮 */
showDeleteButton?: boolean;
/** 是否显示行级增删按钮 */
showRowActions?: boolean;
/** 是否显示行级“增加”按钮 */
showRowAddButton?: boolean;
/** 是否显示行级“删除”按钮 */
showRowDeleteButton?: boolean;
/** 搜索字段列表(用于筛选,不为空时自动显示搜索框) */
searchFields?: string[];
}

View File

@@ -0,0 +1,30 @@
import type { FormItemConfig } from './FormItem.d';
import type { DefineComponent } from 'vue';
/**
* Filter 组件的 Props 类型
*/
export interface FilterProps {
/** 查询参数对象 */
queryParams: Record<string, any>;
/** 表单项配置数组 */
formItems: FormItemConfig[];
/** 是否显示 */
show?: boolean;
/** 是否显示默认按钮 */
showDefaultButtons?: boolean;
/** 标签宽度 */
labelWidth?: string;
/** 标签后是否添加冒号 */
showLabelColon?: boolean;
}
/**
* Filter 组件暴露的方法
*/
export interface FilterExpose {
queryFormRef: InstanceType<typeof import('element-plus').ElForm> | null;
handleQuery: () => void;
resetQuery: () => void;
}

View File

@@ -0,0 +1,21 @@
import type { FormItemConfig } from './FormItem.d';
/**
* Form 组件的 Props 类型
*/
export interface FormProps {
/** 表单数据对象 */
model: Record<string, any>;
/** 表单项配置数组 */
formItems: FormItemConfig[];
/** 表单验证规则 */
rules?: Record<string, any>;
/** 标签宽度 */
labelWidth?: string;
/** 是否内联表单 */
inline?: boolean;
/** 标签位置 */
labelPosition?: 'left' | 'right' | 'top';
/** 标签后是否添加冒号 */
showLabelColon?: boolean;
}

View File

@@ -0,0 +1,82 @@
import type { CSSProperties } from 'vue';
/**
* 表单项选项类型
*/
export interface FormItemOption {
/** 选项标签 */
label: string;
/** 选项值 */
value: string | number | boolean | null | undefined;
/** 是否禁用该选项 */
disabled?: boolean;
}
/**
* onChange 回调函数类型
* @param value - 新的值
* @returns 返回 false 时阻止更新,返回其他值或 undefined 时允许更新
*/
export type OnChangeCallback = (
value: string | number | Array<string | number> | Date | null | undefined
) => Promise<boolean | void> | boolean | void;
/**
* 表单项配置类型
*/
export interface FormItemConfig {
/** 表单项类型 */
type: 'input' | 'select' | 'radio' | 'date' | 'daterange' | 'custom' | 'text';
/** 表单项标签 */
label: string;
/** 表单项字段名(对应 queryParams 的 key */
prop: string;
/** 占位符文本 */
placeholder?: string;
/** 开始日期占位符(仅 daterange 类型) */
startPlaceholder?: string;
/** 结束日期占位符(仅 daterange 类型) */
endPlaceholder?: string;
/** 是否可清空 */
clearable?: boolean;
/** 自定义样式对象或字符串 */
style?: CSSProperties | string | { width?: string; [key: string]: any };
/** 表单项宽度(字符串,如 '200px' */
width?: string;
/** 额外的属性(会通过 v-bind 传递给组件) */
extraprops?: Record<string, any>;
/** 是否多选(仅 select 类型) */
multiple?: boolean;
/** 是否可搜索(仅 select 类型) */
filterable?: boolean;
/** 多选时是否折叠标签(仅 select 类型) */
collapseTags?: boolean;
/** 选项列表select 和 radio 类型) */
options?: FormItemOption[];
/** 日期格式date 和 daterange 类型) */
valueFormat?: string;
/** 自定义插槽名称custom 类型) */
slot?: string;
/** 是否必填 */
required?: boolean;
/** 标签后缀 */
labelSuffix?: string;
/** 值变更时的回调函数 */
onChange?: OnChangeCallback;
/** 是否在变更前进行检查(仅 select 类型,为 true 时会执行 onChange 回调) */
checkBeforeChange?: boolean;
/** 格式化函数text 类型,用于格式化显示的文本) */
formatter?: (value: any) => string;
}
/**
* FormItem 组件的 Props 类型
*/
export interface FormItemProps {
/** 表单项配置对象 */
item: FormItemConfig;
/** 表单项的值 */
modelValue?: string | number | Array<string | number> | Date | null;
/** 回车键按下时的回调函数 */
onEnter?: () => void;
}

View File

@@ -0,0 +1,21 @@
import type { FormItemConfig } from './FormItem.d';
/**
* FormLayout 组件的 Props 类型
*/
export interface FormLayoutProps {
/** 表单数据对象 */
model: Record<string, any>;
/** 表单项配置数组 */
formItems: FormItemConfig[];
/** 表单验证规则 */
rules?: Record<string, any>;
/** 标签宽度 */
labelWidth?: string;
/** 标签位置 */
labelPosition?: 'left' | 'right' | 'top';
/** 标签后是否添加冒号 */
showLabelColon?: boolean;
/** 列数0 表示不限制) */
columns?: number;
}

View File

@@ -0,0 +1,21 @@
import type { DefineComponent } from 'vue';
/**
* Pagination 组件的 Props 类型
*/
export interface PaginationProps {
/** 总记录数 */
total: number;
/** 当前页码 */
page: number;
/** 每页条数 */
limit: number;
}
/**
* 为 Pagination.vue 组件提供类型声明
*/
declare module '@/components/Pagination/index.vue' {
const component: DefineComponent<PaginationProps>;
export default component;
}

View File

@@ -0,0 +1,21 @@
import type { DefineComponent } from 'vue';
/**
* QuickDateRange 组件的 Props 类型
*/
export interface QuickDateRangeProps {
/** 日期范围值(字符串数组,如 ['2024-01-01', '2024-01-31'] */
modelValue?: string[];
/** 开始日期占位符 */
startPlaceholder?: string;
/** 结束日期占位符 */
endPlaceholder?: string;
/** 日期格式 */
valueFormat?: string;
/** 是否可清空 */
clearable?: boolean;
/** 日期选择器的样式 */
datePickerStyle?: Record<string, any>;
/** 透传给日期选择器的其他属性 */
attrs?: Record<string, any>;
}

View File

@@ -0,0 +1,48 @@
import type { TableColumn } from './TableLayout.d';
/**
* Table 组件的 Props 类型
*/
export interface TableProps {
/** 表格数据 */
tableData: Record<string, any>[];
/** 加载状态 */
loading?: boolean;
/** 是否显示边框 */
border?: boolean;
/** 是否显示斑马纹 */
stripe?: boolean;
/** 表格尺寸 */
size?: 'large' | 'default' | 'small';
/** 表格高度 */
tableHeight?: string | number;
/** 最大高度 */
maxHeight?: string | number;
/** 行键 */
rowKey?: string | ((row: Record<string, any>) => string);
/** 是否高亮当前行 */
highlightCurrentRow?: boolean;
/** 表格列配置 */
tableColumns?: TableColumn[];
/** 是否显示分页 */
showPagination?: boolean;
/** 总记录数 */
total?: number;
/** 当前页码 */
pageNo?: number;
/** 每页条数 */
pageSize?: number;
/** 是否所有数据都在客户端,如果是则在组件内部进行分页 */
isAllData?: boolean;
/** 分页左侧自定义文案 */
paginationLeftText?: string;
/** 分页组件自定义属性 */
paginationProps?: {
pageSizes?: number[];
pagerCount?: number;
layout?: string;
background?: boolean;
autoScroll?: boolean;
hidden?: boolean;
};
}

View File

@@ -0,0 +1,89 @@
import type { FormItemConfig } from './FormItem.d';
/**
* 表格列配置类型
*/
export interface TableColumn {
/** 列类型 */
type?: 'selection' | 'index' | 'expand';
/** 列字段名 */
prop?: string;
/** 列标签 */
label?: string;
/** 列宽度 */
width?: string | number;
/** 最小宽度 */
minWidth?: string | number;
/** 是否固定列 */
fixed?: boolean | 'left' | 'right';
/** 对齐方式 */
align?: 'left' | 'center' | 'right';
/** 是否显示溢出提示 */
showOverflowTooltip?: boolean;
/** 自定义插槽名称 */
slot?: string;
/** 格式化函数 */
formatter?: (row: Record<string, any>, column: any, cellValue: any, index?: number) => string;
/** 是否可选selection 类型) */
selectable?: (row: Record<string, any>, index: number) => boolean;
}
/**
* 树节点数据类型
*/
export interface TreeNodeData {
[key: string]: any;
children?: TreeNodeData[];
}
/**
* TableLayout 组件的 Props 类型
*/
export interface TableLayoutProps {
/** 表格数据 */
tableData: Record<string, any>[];
/** 加载状态 */
loading?: boolean;
/** 总记录数 */
total?: number;
/** 查询参数对象 */
queryParams: {
pageNo: number;
pageSize: number;
[key: string]: any;
};
/** 侧边查询参数 */
sideQueryParams?: Record<string, any>;
/** 表单项配置数组 */
formItems?: FormItemConfig[];
/** 是否显示顶部查询 */
showTopQuery?: boolean;
/** 是否显示侧边查询 */
showSideQuery?: boolean;
/** 是否显示分页 */
showPagination?: boolean;
/** 是否显示默认按钮 */
showDefaultButtons?: boolean;
/** 侧边栏宽度 */
sideWidth?: number;
/** 是否显示边框 */
border?: boolean;
/** 是否显示斑马纹 */
stripe?: boolean;
/** 表格尺寸 */
size?: 'large' | 'default' | 'small';
/** 表格高度 */
tableHeight?: string | number;
/** 最大高度 */
maxHeight?: string | number;
/** 行键 */
rowKey?: string | ((row: Record<string, any>) => string);
/** 是否高亮当前行 */
highlightCurrentRow?: boolean;
/** 侧边栏数据 */
siderData?: TreeNodeData[];
/** 树节点键名 */
treeNodeKey?: string;
/** 表格列配置 */
tableColumns?: TableColumn[];
}

View File

@@ -0,0 +1,13 @@
/**
* TableLayout 组件相关的类型定义
*/
export * from './FormItem.d';
export * from './QuickDateRange.d';
export * from './EditableTable.d';
export * from './Filter.d';
export * from './FormLayout.d';
export * from './Form.d';
export * from './Table.d';
export * from './TableLayout.d';
export * from './Dialog.d';