123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import { h, ref, defineComponent, computed, reactive, provide } from 'vue'
- import { ElTable, ElTableColumn, ElRadio, ElTooltip } from 'element-plus'
- import { isNotEmpty, isEmpty, isArray, getUsingConfig, setFieldValue } from '@cip/utils/util'
- import CipTableHandler from '../cip-table-handler'
- import { useCipConfig } from '../hooks/use-cip-config'
- import { cipTableKey } from '../hooks/use-table'
- import { tableProps } from './table-props'
- import ColumnInput from './column-input'
- import { dataColumnWidthMap } from './config'
- import './index.less'
- import { analyseData, getPropertyKeyByPath } from '@cip/components/cip-table/util'
- export default defineComponent({
- name: 'CipTable',
- inheritAttrs: false,
- props: tableProps,
- emits: ['sort', 'update:data', 'update:selectColumns'],
- setup (props, context) {
- const cipConfig = useCipConfig()
- const cipTableRef = ref()
- const _size = computed(() => {
- // 考虑历史因素使用small作为默认值, 当前主要项目使用medium, 在修改表格size注意定宽项的折叠
- return getUsingConfig(props.size, cipConfig.table.size, 'small')
- })
- const coefficient = computed(() => {
- if (props.size) return 1
- const { sizeStandard = 'medium', size = 'medium' } = cipConfig.table || {}
- if (['small', 'mini'].includes(sizeStandard) && size === 'medium') {
- return 1.17
- } else if (['small', 'mini'].includes(sizeStandard) && size === 'medium') {
- return Number((1 / 1.17).toFixed(2))
- }
- return 1
- })
- const cipTable = reactive({
- size: _size
- })
- provide(cipTableKey, cipTable)
- context.expose({
- cipTableRef
- })
- // table 数据更新 v-model:data
- const updateData = (val, index) => {
- // 数据索引
- const dataIndexed = analyseData(props.data, props.treeProps)
- const path = dataIndexed[index]
- // 当存在tree是index与实际的不符合需要使用key进行唯一定位 或者遍历计数
- const propertyKey = getPropertyKeyByPath(path, props.treeProps)
- const data = props.data
- setFieldValue(data, propertyKey, val)
- // data[index] = val
- context.emit('update:data', data)
- }
- // 触发table的排序事件
- const onSortChange = ({ prop, order }) => {
- context.emit('sort', { prop, order })
- }
- // 触发列的选中改变事件
- const onSelectionChange = (val) => {
- context.emit('update:selectColumns', val)
- }
- // 原始的width 转换系数
- const transformWidth = (widthStr, coefficient = 1) => {
- if (typeof widthStr === 'number') return Math.ceil((widthStr - 20) * coefficient) + 20
- if (widthStr.indexOf('px') > -1) return `${Math.ceil(Number(widthStr.replace('px', '') - 20) * coefficient) + 20}px`
- return widthStr
- }
- // 渲染table的单个数据列 注意此处为Column
- const renderTableColumn = ({ key, config } = {}) => {
- const { children, type, ...tableColumnConfig } = config
- // date 类型 强行修改宽度
- if (!tableColumnConfig.width) {
- if (config.type === 'date' && config.viewType === 'datetime') {
- tableColumnConfig.width = dataColumnWidthMap[_size.value]
- }
- } else {
- tableColumnConfig.width = transformWidth(tableColumnConfig.width, coefficient.value)
- }
- const headerSlots = ({ column, $index }) => {
- const result = [h('span', {}, [config.label])]
- // 存在说明
- if (config.description) {
- const descriptionComp = (
- <ElTooltip effect={config.descriptionEffect || 'light'} placement={'top'}>
- {{
- content: () => config.description,
- default: () => <i class={'el-icon-question'} style={'margin-left:2px'}/>
- }}
- </ElTooltip>
- )
- result.push(descriptionComp)
- }
- // 必填标记
- if (config.required === true && config.writable === true) {
- const requiredAsterisk = (<span class={['cip-danger-color']} style={{ marginRight: '4px' }}>*</span>)
- result.unshift(requiredAsterisk)
- }
- return result
- }
- let dataIndexed
- if (props.rowKey) {
- dataIndexed = analyseData(props.data, props.treeProps)
- }
- return h(ElTableColumn, {
- prop: key,
- align: config.type === 'number' ? 'right' : '', // 针对数字类型进行居右优化
- style: 'display: flex;',
- ...tableColumnConfig
- }, {
- header: headerSlots,
- default: ({ row, $index, column }) => {
- // if ($index === -1) return // 如果写上这个代码 children 将失效
- if (isArray(config.children) && config.children.length > 0) {
- return renderTableColumns(config.children)
- } else {
- if ($index < 0) return null
- // 同时开放key值插槽及key+'Slot' 的插槽
- // default/append/expand/_handler为table其他用途的插槽不可用于渲染column
- // 如果存在字段名为上述字段的,需要加Slot后缀,例: defaultSlot\appendSlot
- if (!['default', 'append', 'prepend', 'expand', '_handler', '$handler'].includes(key) && context.slots[key]) {
- return context.slots[key]({ row, $index, column })
- }
- // 特殊字段插槽 ['default', 'append', 'expand', '_handler', '$handler']
- if (context.slots[`${key}Slot`]) {
- return context.slots[`${key}Slot`]({ row, $index, column })
- }
- let propertyKey = $index
- if (dataIndexed) {
- const path = dataIndexed[$index]
- propertyKey = path?.length > 1 ? getPropertyKeyByPath(path, props.treeProps) : $index
- }
- return h(ColumnInput, {
- config,
- fieldKey: props.fieldKey,
- index: $index,
- model: row,
- key,
- tableRuleKey: props.ruleKey,
- propertyKey: propertyKey,
- columnKey: key,
- tableDependOnValues: props.dependOnValues,
- tableData: props.data,
- updateData
- })
- }
- }
- })
- }
- // 渲染table的所有数据列 注意此处为Columns
- const renderTableColumns = (columns = []) => {
- if (!isArray(columns)) {
- throw new Error('function renderTableColumns param columns must be array')
- }
- return columns.filter(column => !column.config.hideItem).map(column => renderTableColumn(column))
- }
- // 渲染table所有列 操作、选中、序号等
- const TableColumns = () => {
- // table字段渲染
- const slots = renderTableColumns(props.columns)
- // 序号渲染
- if (isNotEmpty(props.offset) && props.offset > -1 && !props.hideIndex) {
- const indexColumn = h(ElTableColumn, { label: '序号', fixed: props.indexFixed ? 'left' : '', width: isEmpty(props.rowKey) ? '55px' : '75px' }, {
- default: ({ $index }) => `${$index + 1 + props.offset}`
- })
- slots.unshift(indexColumn)
- }
- // 复选框
- if (props.selectType === 'checkbox') {
- const option = { type: 'selection', width: '45px', fixed: 'left' }
- if (isNotEmpty(props.selectable)) { // 选择
- option.selectable = (row, index) => props.selectable(row || {}, index)
- }
- const selectionColumn = h(ElTableColumn, option)
- slots.unshift(selectionColumn)
- }
- // 单选框
- if (props.selectType === 'radio') {
- const selectionColumn = h(ElTableColumn, { width: '45px', fixed: 'left' }, {
- default: ({ row }) => h(ElRadio, {
- label: row[props.selectLabel] ?? row.id,
- modelValue: props.selectRadio
- }, { default: () => '' })
- })
- slots.unshift(selectionColumn)
- }
- // 展开
- if (context.slots.expand) {
- const expendColumn = h(ElTableColumn, { type: 'expand', width: '32px', fixed: 'left' }, {
- default: ({ row, index }) => context.slots.expand({ row, index })
- })
- slots.unshift(expendColumn)
- }
- // jsx编译时有时候会去除_handler插槽
- // 注意_handler即将废弃请使用$handler代替
- if (props.withTableHandle && (context.slots._handler || context.slots.$handler)) {
- const handlerSlot = context.slots._handler || context.slots.$handler
- const handlerColumn = h(ElTableColumn, {
- label: '操作',
- fixed: 'right',
- width: transformWidth(props.handlerWidth, coefficient.value)
- }, {
- default: ({ row, $index }) => h(CipTableHandler, { limit: props.handlerLimit, row }, {
- default: () => handlerSlot({ row, $index })
- })
- })
- slots.unshift(handlerColumn)
- // 内部组件必须使用cip-table-button
- }
- // el-table组件提供的默认插槽
- if (context.slots.default) {
- slots.push(context.slots.default())
- }
- // el-table组件提供的prepend插槽
- if (context.slots.prepend) {
- const prependSlots = context.slots.prepend()
- if (isArray(prependSlots)) {
- slots.unshift(...prependSlots)
- } else {
- slots.unshift(prependSlots)
- }
- }
- // el-table组件提供的append插槽
- if (context.slots.append) {
- const appendSlots = context.slots.append()
- if (isArray(appendSlots)) {
- slots.push(...appendSlots)
- } else {
- slots.push(appendSlots)
- }
- }
- // 给所有column加一个父亲
- if (props.tableHeaderLabel) return h(ElTableColumn, { label: props.tableHeaderLabel, align: 'center' }, { default: () => slots })
- return slots
- }
- // 渲染table
- return () => <ElTable
- ref={cipTableRef}
- size={_size.value}
- {...context.attrs}
- class={'cip-table'}
- data={props.data}
- rowKey={props.rowKey}
- treeProps={props.treeProps}
- defaultExpendAll={props.defaultExpendAll}
- onSortChange={onSortChange}
- onSelectionChange={onSelectionChange}
- >
- <TableColumns/>
- </ElTable>
- }
- })
|