build / build (push) Successful in 1m58s
- types/index.ts 补 OperatorEnum(此前 import 悬空,接入 TablePage* 即构建失败)
- TablePageAlovaNew 对齐 flow-center 版:页长记忆 localStorage.customPageCount
+ 重载清空勾选 + watch(tableHeight) 跟随页面侧 ResizeObserver 重算
- ServiceItemList/ApplyManage:三段式骨架 + search-wrap(下拉+关键字 200px
即输即搜)+ TablePageAlovaNew + Utils.operatingHandle 图标操作列(编辑/发布
icon-fasong/下架 icon-stop/删除/详情 icon-browse)+ MyConfirm + 增删后智能翻页
- ServiceDictManage:tabs-wrapper + card Tabs 双容器 v-show + 定高 + 弹窗校验
统一文案「请填写红色星号内容!」
- ServiceFormManage:无分页定高 + 前端过滤 + 按状态条件图标
- ServiceItemEdit:page-wrapper 根容器 + 必填红星
- 状态 Tag 色常量迁 api 层(APPLY_STATUS_COLOR/ITEM_STATUS_COLOR)
- dataApi 返回 alova Method 不调 .send();分页 formatResponse 适配 {total,list}
- vite build 通过(27s)
122 lines
3.6 KiB
Vue
122 lines
3.6 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())
|
||
// 页面侧挂载后可能重算高度(嵌入面板初始视口先小后大),跟随 props 更新
|
||
watch(() => props.tableHeight, v => {
|
||
if (v) tableH.value = v
|
||
})
|
||
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>
|