UNPKG

@ithinkdt/core

Version:

iThinkDT Core

349 lines (308 loc) 10.1 kB
import { computed, isRef, reactive, ref, shallowReactive, toRefs, isReactive, unref, watch, h } from 'vue' import { measureText } from '@ithinkdt/common' import { getRender } from './entity/render' import { useI18n } from '../i18n' import { useModalRef } from './use-modal' import { pageInit } from './plugin' export function useTable(options) { let { cached = pageInit.defaultCache, index, select, selectable, expand, expandable, columns, operation, operationMax: max, tableRef = ref(), } = options if (isRef(options) || Array.isArray(options) || typeof options === 'function') columns = options if (typeof columns === 'function') { const col = (k, it) => ({ ...it, key: k }) const group = (show, items) => { return items.map((it) => { return { ...it, hidden: computed(() => !show.value || unref(it.hidden) === true), } }) } columns = columns({ col, group }) } const { t } = useI18n() let _columns function _map(columns) { return columns .filter((it) => !!it) .map((it) => { const _def = getDefault(it, t) const col = reactive({ ..._def, ...(isReactive(it) ? toRefs(it) : it), render: _def.render || it.render, fixed: computed(() => custom.value[it.key]?.fixed ?? unref(_def.fixed) ?? unref(it.fixed)), hidden: computed(() => custom.value[it.key]?.hidden ?? unref(_def.hidden) ?? unref(it.hidden)), }) if (it.children?.length) { col.children = _map(it.children) } return col }) } function _transform(columns) { if (expand) { expand = ref(expand) columns.unshift({ key: '__expand', format: `expand`, hidden: computed(() => !expand.value), width: 40, minWidth: 40, expandable, renderExpand: computed(() => expand.value || (() => h('div'))), resizable: false, disaCustom: true, }) } if (index) { index = ref(index) columns.unshift({ key: '__index', format: 'index', hidden: computed(() => !index.value), render: typeof index === 'function' ? (_, i) => index(i) : undefined, resizable: false, disaCustom: true, }) } if (select) { select = ref(select) columns.unshift({ key: '__selection', format: `selection`, fixed: 'left', width: 40, minWidth: 40, hidden: computed(() => !select.value), multiple: computed(() => select.value !== 'single'), selectable, disaCustom: true, }) } if (operation) { columns.push({ key: '__operation', format: `operation`, ellipsis: false, fixed: 'right', btns: operation, max, resizable: false, disaCustom: true, }) } return _map(columns) } if (isRef(columns)) { watch(columns, (cols) => { if (!_columns) return _columns = _transform([...cols]) sort.value = _columns.map((it) => it.key) updateCols() }) } const custom = ref({}) const sort = ref([]) let storeKey const _cols = shallowReactive([]) function store() { if (storeKey) { localStorage.setItem( storeKey, JSON.stringify({ custom: custom.value, sort: sort.value, }), ) } } const getIndex = (key) => sort.value.indexOf(key) function updateCols() { _cols.length = 0 _cols.push(..._columns) _cols.sort((a, b) => getIndex(a.key) - getIndex(b.key)) } const key = pageInit.useTableKey() const modalRef = useModalRef() const init = () => { _columns = _transform([...unref(columns)]) sort.value = _columns.map((it) => it.key) if (cached !== false && pageInit.getUsername()) { if (typeof cached === 'string') { storeKey = cached } else { if (!modalRef?.inModal) { storeKey = `${pageInit.getUsername() || ''}: ${pageInit.getAppCode() || ''} # ${unref(key)}` } else if (cached) { console.debug('[table]: 在弹窗内 cached 请给定 key, 否则忽略缓存') } } if (storeKey) { const config = JSON.parse(localStorage.getItem(storeKey) ?? 'null') if (config) { custom.value = config.custom sort.value = config.sort } } } updateCols() } pageInit.__$ ? init() : pageInit.$init.then(init) return { tableRef, columns: _cols, customCols({ key, field, value }) { if (field === 'index') { const i = sort.value.indexOf(key) if (i !== -1) { const [it] = sort.value.splice(i, 1) sort.value.splice(value, 0, it) } updateCols() } else { custom.value[key] ??= {} custom.value[key][field] = value } store() }, resetCols() { custom.value = {} sort.value = _columns.map((it) => it.key) updateCols() store() }, } } const getDefault = (item, t) => { const _type = item.format || (['createUser', 'updateUser'].includes(item.key) ? 'user' : 'string') let custom = pageInit.dataFormatters?.[_type.split('|')[0]] if (custom && custom.cellDefault) { return typeof custom.cellDefault === 'function' ? custom.cellDefault(item) || {} : custom.cellDefault } let render = ['index', 'operation', 'selection', 'expand'].includes(_type) ? undefined : getRender(_type, item) if (_type === 'string' || _type.startsWith('text')) { return { ellipsis: true, render, } } if (_type === 'index') { return { label: computed(() => t('table.th.index')), fixed: 'left', align: 'center', width: 70, render, ellipsis: false, } } if (_type.startsWith('date')) return { width: _type.startsWith('datetime') ? 170 : 120, align: 'center', sortable: true, ellipsis: false, render, } if (_type.startsWith('number')) { return { align: 'right', sortable: true, ellipsis: false, render, } } if (_type.startsWith('percent')) { return { align: 'right', sortable: true, ellipsis: false, render, } } if (_type.startsWith('file')) { return { align: 'left', sortable: false, ellipsis: false, render, } } if (_type.startsWith('image')) { return { align: 'center', sortable: false, ellipsis: false, render, } } if (_type === 'yesno') { return { align: 'center', ellipsis: false, render, } } if (_type.startsWith('dict') || _type.startsWith('state')) { return { ellipsis: _type.startsWith('dicts'), render, } } if (_type.startsWith('tag')) { return { ellipsis: _type.startsWith('tags'), render, } } if (_type.startsWith('operation')) { const btns = computed(() => { return (unref(item.btns) ?? []) .filter((btn) => !!btn && btn.auth !== false) .map((btn) => { return { ...btn, type: btn.type ?? (btn.preset === 'delete' ? 'error' : 'primary'), title: typeof btn.title === 'function' ? btn.title : () => unref(btn.title), text: typeof btn.text === 'function' ? btn.text : () => unref(btn.text) ?? (btn.preset ? t(`page.action.${btn.preset}`) : ''), onClick: btn.onClick, } }) }) const max = computed(() => unref(item.max) || 3) const width = computed(() => { const _btns = btns.value const _max = unref(max) for (const btn of _btns) { btn._width = btn.width || measureText(btn.text()) } const arr = _btns.length > _max ? [..._btns.slice(0, _max - 1), { _width: measureText(t('table.op.more')) }] : _btns return arr.reduce((w, btn) => w + btn._width, 0) + (arr.length - 1) * 14 }) render = getRender(_type, { ...item, btns, max, width }) return { label: computed(() => t('table.th.op')), ellipsis: false, align: 'center', hidden: computed(() => btns.value.length === 0), render, width: computed(() => width.value + 24), } } return { render } }