build / build (push) Successful in 3m17s
应用页规范(bsch)重构: - 6 个列表页迁规范骨架: page-wrapper/tabs-wrapper + search-wrap 搜索区(关键字 200px 即输即搜, 去查询按钮) + link-table table-bottom-box 定高表格 + page-panel 分页栏 - 分页列表统一接 TablePageAlovaNew(页长 [10,20,30,40]/customPageCount 记忆/增删智能翻页); dataApi 须返回 Method, 调 .send() 会导致表格静默空数据 - 操作列统一图标式 operatingHandle(Tooltip+fixed right 居中); 各列表补序号列; 危险操作统一 MyConfirm 二次确认 - 弹窗表单必填红星 + 统一提示「请填写红色星号内容!」 - TablePageAlovaNew 补页长记忆与重载后清空勾选; 新增 src/types OperatorEnum 工作台与流程轨迹优化: - 已办列表去重: 每办件一行, doneCount>1 显示「共办理 N 次」标签 - 新增 TraceTimeline 轨迹时间流(时间升序/kind/轮次, 按人员/科室切换写回 URL), 接入详情/办理页 - 新增流程源码只读抽屉 SourceDrawer, 接入定义列表与图示页 - 办理人映射/流程定义新增「启用」回路(/admin/map/enable, /admin/def/enable) - 图示视图口径统一 dept/user 两档, 缺省人员视图; 状态列 Tag 色映射统一导出
118 lines
3.4 KiB
Vue
118 lines
3.4 KiB
Vue
<template>
|
||
<Table :columns="columns" :data="list" :height="tableH" :loading="loading" no-data-text="暂无数据"
|
||
class="link-table table-bottom-box" @on-selection-change="selectChange">
|
||
<template #loading>
|
||
<div class="table-spin-load">加载中</div>
|
||
</template>
|
||
<template v-for="slotName in tableSlotNames" :key="slotName" v-slot:[slotName]="slotProps">
|
||
<slot :name="slotName" v-bind="slotProps" />
|
||
</template>
|
||
</Table>
|
||
|
||
<div class="page-panel">
|
||
<div class="fl ml-15 align-middle">
|
||
<slot :checkList="selectList" />
|
||
</div>
|
||
|
||
<Page class="page-box fr" :total="total" :model-value="page" :page-size="pageSize"
|
||
:page-size-opts="[10, 20, 30, 40]" show-total show-sizer placement="top" @on-change="onPageChange"
|
||
@on-page-size-change="onSizeChange" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref, useSlots, watch } from 'vue'
|
||
import Utils from '@/utils'
|
||
import { OperatorEnum } from '@/types'
|
||
|
||
interface Props {
|
||
dataApi: any
|
||
columns: any[]
|
||
tableHeight?: number
|
||
autoLoad?: boolean
|
||
dataFilter?: (resp: any) => any[]
|
||
formatResponse?: (res: any) => { total: number; list: any[] }
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
autoLoad: true,
|
||
formatResponse: (res: any) => ({ total: res.total, list: res.content })
|
||
})
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'selection-change', list: number[]): void
|
||
}>()
|
||
const slots = useSlots()
|
||
|
||
const tableH = ref(props.tableHeight ?? Utils.useTableHeight())
|
||
const tableSlotNames = computed(() => Object.keys(slots).filter(name => !['default', 'loading'].includes(name)))
|
||
|
||
const selectList = ref<number[]>([])
|
||
function selectChange(rows: any[]) {
|
||
selectList.value = rows.map((r: any) => r.id)
|
||
emit('selection-change', selectList.value)
|
||
}
|
||
|
||
const {
|
||
loading,
|
||
data: resp,
|
||
send: sendLoad,
|
||
page,
|
||
pageSize,
|
||
total,
|
||
reload
|
||
} = usePagination(
|
||
(current: number, size: number) =>
|
||
props.dataApi({ pageIndex: current, pageSize: size }),
|
||
{
|
||
total: res => props.formatResponse(res).total,
|
||
data: res => props.formatResponse(res).list,
|
||
initialPage: 1,
|
||
// 页长记忆(bsch 应用页规范 §3:customPageCount localStorage)
|
||
initialPageSize: parseInt(localStorage.getItem('customPageCount') || '10') || 10,
|
||
immediate: props.autoLoad,
|
||
}
|
||
)
|
||
|
||
// 数据重载后清空勾选,避免批量操作用到旧选中行
|
||
watch(resp, () => {
|
||
if (selectList.value.length) {
|
||
selectList.value = []
|
||
emit('selection-change', selectList.value)
|
||
}
|
||
})
|
||
|
||
const list = computed(() => {
|
||
if (!resp.value) return []
|
||
return props.dataFilter ? props.dataFilter(resp.value) : resp.value
|
||
})
|
||
|
||
const onPageChange = (p: number) => (page.value = p)
|
||
const onSizeChange = (s: number) => {
|
||
pageSize.value = s
|
||
localStorage.setItem('customPageCount', String(s))
|
||
}
|
||
|
||
function refreshData() {
|
||
page.value = 1
|
||
reload()
|
||
}
|
||
|
||
function reloadData(type: OperatorEnum = OperatorEnum.sel) {
|
||
let p = page.value
|
||
const s = pageSize.value
|
||
|
||
if (type === OperatorEnum.add && p * s === total.value) p += 1
|
||
if (type === OperatorEnum.del && (p - 1) * s + 1 === total.value) p -= 1
|
||
if (type === OperatorEnum.sel) p = 1
|
||
if (p < 1) p = 1
|
||
|
||
page.value = p
|
||
sendLoad()
|
||
}
|
||
|
||
defineExpose({ list, refreshData, reloadData })
|
||
</script>
|
||
|
||
<style scoped></style>
|