Files
yunke/yunkes/src/components/YkStaffDetailModal.vue
T

127 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, watch } from 'vue'
import type { Page } from '@/api/types'
/**
* 通用明细 modal —— 复刻云客"统计数字点击弹明细表"。
* 调用方传 fetcher(返回 Page<T>)+ 列定义;组件负责 dialog/table/pagination。
*/
interface Col {
prop: string
label: string
width?: number | string
minWidth?: number | string
align?: 'left' | 'center' | 'right'
/** el-table-column formatter (row, column, cellValue, index) → display string. */
formatter?: (row: any, column: any, cellValue: any, index: number) => string
/** 该列单元格可点:渲染为 link button,点击触发回调(用于 modal 内跳聊天等)。 */
onClick?: (row: any) => void
}
const props = defineProps<{
modelValue: boolean
title: string
cols: Col[]
/** fetcher(page, page_size) → Page<T>。宽松 Page<any>:Customer 无 index signature,
* 不可直接赋 Page<Record<string,unknown>>,故用 any 接纳 Page<Customer> 等。 */
fetcher: (page: number, page_size: number) => Promise<Page<any>>
/** 弹框顶部汇总说明(对齐云客) */
summaryText?: string
pageSizes?: number[]
}>()
const emit = defineEmits<{ 'update:modelValue': [boolean] }>()
const loading = ref(false)
const items = ref<any[]>([])
const total = ref(0)
const page = ref(1)
const pageSize = ref(props.pageSizes?.[0] ?? 10)
async function load() {
loading.value = true
try {
const res = await props.fetcher(page.value, pageSize.value)
items.value = res.items
total.value = res.total
} finally {
loading.value = false
}
}
watch(
() => props.modelValue,
(open) => {
if (open) {
page.value = 1
load()
}
},
)
</script>
<template>
<el-dialog
:model-value="modelValue"
:title="title"
width="900px"
@update:model-value="emit('update:modelValue', $event)"
>
<div v-if="summaryText" class="yk-detail-modal__summary">{{ summaryText }}</div>
<el-table v-loading="loading" :data="items" border style="width: 100%" size="small">
<el-table-column
v-for="c in cols"
:key="c.prop"
:prop="c.prop"
:label="c.label"
:width="c.width"
:min-width="c.minWidth"
:align="c.align"
:formatter="c.formatter"
show-overflow-tooltip
>
<template v-if="c.type === 'person'" #default="{ row }">
<div style="display: flex; align-items: center; gap: 8px; padding: 2px 0">
<el-avatar :size="28" :src="row[c.prop + '_avatar'] || undefined" shape="square" style="flex: none; border-radius: 6px;">
{{ (row[c.prop + '_name'] || '?').slice(0, 1) }}
</el-avatar>
<div style="min-width: 0; flex: 1">
<div v-if="c.onClick" >
<el-button link type="primary" size="small" @click="c.onClick?.(row)">
{{ row[c.prop + '_name'] || row[c.prop] || '--' }}
</el-button>
</div>
<div v-else style="font-size: 13px; color: #2b3240; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
{{ row[c.prop + '_name'] || row[c.prop] || '--' }}
</div>
<div v-if="row[c.prop + '_sub']" style="font-size: 11px; color: #8a94a4; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
{{ row[c.prop + '_sub'] }}
</div>
<div v-if="row[c.prop + '_real']" style="font-size: 11px; color: #5a6472; margin-top: 1px;">
{{ row[c.prop + '_real'] }}
</div>
</div>
</div>
</template>
<template v-else-if="c.onClick" #default="{ row }">
<el-button link type="primary" size="small" @click="c.onClick?.(row)">
{{ c.formatter ? c.formatter(row, c, row[c.prop], 0) : row[c.prop] }}
</el-button>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 10px; display: flex; justify-content: flex-end">
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="pageSizes ?? [10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next"
background
size="small"
@current-change="(p: number) => { page = p; load() }"
@size-change="(s: number) => { pageSize = s; page = 1; load() }"
/>
</div>
</el-dialog>
</template>