Revert "feat: MeetingDetail 参会人表改用 GrTable + 移除合计行"
This reverts commit 8542d545d5.
This commit is contained in:
@@ -18,15 +18,30 @@
|
||||
弃用 refer/gr-table.vue 的 Vue 2 Options API + componentOptions 私有 API.
|
||||
-->
|
||||
<template>
|
||||
<!-- 桌面: el-table 完整渲染 -->
|
||||
<el-table
|
||||
v-if="!isMobile"
|
||||
ref="tableRef"
|
||||
v-bind="$attrs"
|
||||
:data="data"
|
||||
>
|
||||
<!-- 移动端展开行: 只在 ≤breakpoint 渲染, 显示非主列 -->
|
||||
<el-table-column v-if="isMobile && collapsedCols.length" type="expand">
|
||||
<template #default="{ row }">
|
||||
<el-descriptions :column="1" size="small" class="gr-mobile-desc">
|
||||
<el-descriptions-item
|
||||
v-for="col in collapsedCols"
|
||||
:key="col.prop"
|
||||
:label="col.label"
|
||||
>
|
||||
<span v-if="col.formatter">{{ col.formatter(row, col.prop, row[col.prop]) }}</span>
|
||||
<span v-else>{{ row[col.prop] ?? '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!--
|
||||
桌面: 透传所有列 (含非主列)
|
||||
移动端: 只透传主列 + 操作列 (type="selection" 也保留, 它没 prop)
|
||||
-->
|
||||
<template v-for="(child, idx) in slotColumns" :key="idx">
|
||||
<component
|
||||
@@ -36,32 +51,6 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<!-- 移动端: el-descriptions 卡片列表 (每行 = 一张卡, 包含所有字段) -->
|
||||
<div v-else class="gr-mobile-cards">
|
||||
<div v-for="(row, rIdx) in data" :key="rIdx" class="gr-mobile-card">
|
||||
<el-descriptions :column="1" size="small" class="gr-mobile-desc">
|
||||
<el-descriptions-item
|
||||
v-for="(col, cIdx) in allCols"
|
||||
:key="cIdx"
|
||||
:label="col.label || (col.type === 'selection' ? '选择' : (col.type === 'index' ? '序号' : ''))"
|
||||
>
|
||||
<!-- 序号列特殊渲染 -->
|
||||
<span v-if="col.type === 'index'">{{ rIdx + 1 }}</span>
|
||||
<!-- 选择列特殊渲染 -->
|
||||
<el-checkbox v-else-if="col.type === 'selection'" :model-value="false" disabled />
|
||||
<!-- 有自定义 template 的列: 用 vnode 渲染 (含 maskPhone / openPreview 等自定义) -->
|
||||
<component
|
||||
v-else-if="col.templateVnode"
|
||||
:is="renderTemplate(col.templateVnode, row, $event)"
|
||||
/>
|
||||
<!-- 普通 prop 列: 直接显示 -->
|
||||
<span v-else>{{ row[col.prop] ?? '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<div v-if="!data || !data.length" class="gr-mobile-empty">暂无数据</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -118,7 +107,8 @@ const slotColumns = computed(() => {
|
||||
return flat
|
||||
})
|
||||
|
||||
// 抽取所有列的元数据 (含自定义 template vnode)
|
||||
// 抽取所有有 prop 的列 (排除 type=expand / type=selection / type=index, 它们用
|
||||
// 自身 type 标识, 不通过 prop)
|
||||
const dataCols = computed(() => {
|
||||
return slotColumns.value
|
||||
.map((n, idx) => ({
|
||||
@@ -127,41 +117,11 @@ const dataCols = computed(() => {
|
||||
type: n.props?.type,
|
||||
prop: n.props?.prop,
|
||||
label: n.props?.label || (n.props?.type === 'selection' ? '#' : (n.props?.type === 'index' ? '#' : '')),
|
||||
formatter: n.props?.formatter,
|
||||
// 抓取自定义 #default slot 的 vnode (用于 mobile 卡片渲染)
|
||||
templateVnode: extractDefaultSlot(n)
|
||||
formatter: n.props?.formatter
|
||||
}))
|
||||
.filter((c) => c.prop) // 只要有 prop 的列
|
||||
})
|
||||
|
||||
// 从 el-table-column vnode 抓取自定义 default slot 的 vnode
|
||||
// el-table-column 的 children 通常是 template #default="{ row }"
|
||||
function extractDefaultSlot(node) {
|
||||
const children = node.children
|
||||
if (!children) return null
|
||||
// children 可能是数组, 也可能是单个
|
||||
if (Array.isArray(children)) {
|
||||
for (const c of children) {
|
||||
if (c && c.type && c.type.name === 'template') {
|
||||
// Vue 3 把 template slot 编译成对象 { default: () => [vnode] }
|
||||
if (typeof c.children === 'object' && c.children && typeof c.children.default === 'function') {
|
||||
return c.children
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// mobile 卡片: 渲染自定义 template (传入 row, 返回 vnode 数组)
|
||||
function renderTemplate(slotObj, row) {
|
||||
if (!slotObj || typeof slotObj.default !== 'function') return null
|
||||
try {
|
||||
return slotObj.default({ row })
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 计算主列列表 (Vue3 不用 componentOptions, 直接读 vnode.props)
|
||||
const mainColsResolved = computed(() => {
|
||||
if (props.mainCols && props.mainCols.length) return props.mainCols
|
||||
@@ -176,9 +136,6 @@ const collapsedCols = computed(() => {
|
||||
return dataCols.value.filter((c) => !mainColsResolved.value.includes(c.prop))
|
||||
})
|
||||
|
||||
// mobile 卡片显示的列 (按用户传入顺序, 但 prop 列在前+ 非 prop 在后; 不折叠)
|
||||
const allCols = computed(() => dataCols.value)
|
||||
|
||||
function shouldRenderColumn(node, idx) {
|
||||
if (!isMobile.value) return true // 桌面全显示
|
||||
const meta = dataCols.value.find((c) => c.originalIndex === idx)
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
让内容超出时容器内出现横向滚动条, 不影响外层 grid 布局.
|
||||
-->
|
||||
<div class="attendee-table-wrap">
|
||||
<GrTable :data="attendeeRows" v-loading="attendeeLoading" border size="small" @selection-change="onAttendeeSelectionChange" class="attendee-table">
|
||||
<el-table :data="attendeeRows" v-loading="attendeeLoading" border size="small" style="width: 100%;" show-summary :summary-method="attendeeSummary" @selection-change="onAttendeeSelectionChange" class="attendee-table">
|
||||
<el-table-column v-if="!isSponsor && !isReadonly" type="selection" width="42" />
|
||||
<el-table-column type="index" label="序号" width="50" align="center" />
|
||||
<el-table-column prop="name" label="医生" min-width="90" />
|
||||
@@ -171,7 +171,7 @@
|
||||
<template #empty>
|
||||
<span class="text-muted">暂无参会人, 点击右上"新增参会人"按手机号添加</span>
|
||||
</template>
|
||||
</GrTable>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -563,7 +563,7 @@ import { ElMessage } from 'element-plus'
|
||||
import OssFileUploader from '@/components/OssFileUploader.vue'
|
||||
import CameraQrUpload from '@/components/CameraQrUpload.vue'
|
||||
import OssImageUploader from '@/components/OssImageUploader.vue'
|
||||
import GrTable from '@/components/GrTable.vue'
|
||||
import IdCardUploader from '@/components/IdCardUploader.vue'
|
||||
import ImportResultDialog from '@/components/ImportResultDialog.vue'
|
||||
import Preview from '@/components/Preview.vue'
|
||||
import DoctorTitleSelect from '@/components/DoctorTitleSelect.vue'
|
||||
@@ -874,7 +874,15 @@ const meetingFee = computed(() => {
|
||||
return { total, useMain: false }
|
||||
})
|
||||
|
||||
|
||||
/** 参会人表格底部合计行: "医生"列显示"合计", "应发金额"列显示劳务费合计 */
|
||||
function attendeeSummary({ columns }) {
|
||||
const sums = columns.map(() => '')
|
||||
const nameIdx = columns.findIndex(c => c.label === '医生')
|
||||
const feeIdx = columns.findIndex(c => c.label === '应发金额')
|
||||
if (nameIdx >= 0) sums[nameIdx] = '合计'
|
||||
if (feeIdx >= 0) sums[feeIdx] = '¥ ' + laborFeeTotal.value.toFixed(2)
|
||||
return sums
|
||||
}
|
||||
|
||||
/** 已勾选的参会人 (批量邀请/推送共用) */
|
||||
const selectedAttendees = ref([])
|
||||
@@ -2161,5 +2169,36 @@ onBeforeUnmount(stopFeePolling)
|
||||
|
||||
/* 表格外层 wrap: 确保手机端表格能横向滚 */
|
||||
.attendee-table-wrap { -webkit-overflow-scrolling: touch; }
|
||||
|
||||
/* 参会人表格 mobile: 字号缩到 11px, padding 紧凑, 行高紧凑 */
|
||||
.attendee-table {
|
||||
font-size: 11px !important;
|
||||
}
|
||||
.attendee-table :deep(.el-table th.el-table__cell),
|
||||
.attendee-table :deep(.el-table td.el-table__cell) {
|
||||
padding: 4px 3px !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
.attendee-table :deep(.el-table .row-actions) {
|
||||
flex-direction: column !important;
|
||||
align-items: flex-start !important;
|
||||
gap: 1px !important;
|
||||
}
|
||||
.attendee-table :deep(.el-table .row-actions .el-link) {
|
||||
font-size: 11px !important;
|
||||
padding: 0 2px !important;
|
||||
}
|
||||
/* 标签字号缩窄 */
|
||||
.attendee-table :deep(.el-table .el-tag) {
|
||||
font-size: 10px !important;
|
||||
padding: 0 4px !important;
|
||||
height: 18px !important;
|
||||
line-height: 18px !important;
|
||||
}
|
||||
/* 摘要行 (el-table__footer) 字号缩窄 */
|
||||
.attendee-table :deep(.el-table .el-table__footer-wrapper td) {
|
||||
font-size: 11px !important;
|
||||
padding: 6px 3px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user