@ithinkdt/core
Version:
iThinkDT Core
349 lines (308 loc) • 10.1 kB
JavaScript
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 }
}