@ithinkdt/core
Version:
iThinkDT Core
185 lines (159 loc) • 5.63 kB
JavaScript
import { isRef, computed } from 'vue'
// eslint-disable-next-line vue/prefer-import-from-vue
import { isObject } from '@vue/shared'
import { merge } from '@ithinkdt/common'
import { useI18n } from '../../i18n'
import { useDict } from '../../dict'
import { getRender, getDictKey } from './render'
function def(t, filed, value) {
if (filed in t) return
Object.defineProperty(t, filed, {
value,
enumerable: false,
writable: false,
configurable: false,
})
}
function fieldDec(decName, init) {
return (value, ctx) => {
if (ctx.kind === 'class' || ctx.kind === 'method') {
console.warn(`${decName} Decorator 不能用在 class 或 method!`)
}
const initializer = init(value, ctx)
ctx.addInitializer?.(initializer)
if (ctx.kind === 'field') return initializer
}
}
export function Label(label) {
return fieldDec('Label', (_value, { name }) => {
return function (value) {
def(Object.getPrototypeOf(this).constructor, `__label_${name}`, label)
return value
}
})
}
export function Field(formatOrOptions) {
return fieldDec('Field', (_value, { name }) => {
const options = typeof formatOrOptions === 'string' ? { format: formatOrOptions } : formatOrOptions
return function (value) {
def(Object.getPrototypeOf(this).constructor, `__field_${name}`, options)
return value
}
})
}
function applyEntity(i18n, clazz) {
if (!i18n) return
let inst = i18n.inst
if (!inst) {
inst = () => useI18n('local', i18n)
}
inst = typeof inst === 'function' ? inst : () => inst
let _inst
const t = (k) => {
if (!_inst) _inst = inst()
const s = i18n.prefix ? `${i18n.prefix}.${k}` : k
const _s = _inst.t(s)
return _s === s ? (k.startsWith('_') ? t(k.slice(1)) : _s) : _s
}
const $t = (s) => {
return computed(() => t(s))
}
def(clazz, `__$t`, $t)
const obj = new clazz()
for (const k of Object.keys(obj)) {
def(clazz, `__label_${k}`, $t(k))
}
}
export function Entity({ i18n } = {}) {
return (value, { kind }) => {
if (kind !== 'class') {
console.warn(`Entity Decorator 不能用在 field 或 method!`)
}
applyEntity(i18n, value)
}
}
export function analyzeEntity(EntityClass, { i18n } = {}) {
applyEntity(i18n, EntityClass)
function fi(name, type, requiredOrOptions, isSearchItem = false) {
if (isRef(requiredOrOptions) || !isObject(requiredOrOptions)) {
requiredOrOptions =
requiredOrOptions === undefined
? {}
: {
required: requiredOrOptions,
}
}
const $t = EntityClass[`__$t`]
const field = EntityClass[`__field_${name}`] ?? {}
const { dictKey, multiple } = getDictKey(field.format, field)
if (dictKey) {
const props = (requiredOrOptions.props ??= {})
if ('options' in props === false) {
props.options = useDict(dictKey)
}
if ('multiple' in props === false) {
props.multiple = multiple
}
}
return {
label: EntityClass[`__label_${name}`] ?? $t?.(name) ?? name,
name,
type,
view:
!isSearchItem &&
getRender(
field?.format ??
(dictKey
? multiple
? `dicts`
: `dict`
: field?.name && ['createUser', 'updateUser'].includes(field.name)
? 'user'
: 'string'),
field,
),
...requiredOrOptions,
}
}
return {
fi,
qi: (name, type, requiredOrOptions) => fi(name, type, requiredOrOptions, true),
r: (name) => {
const field = EntityClass[`__field_${name}`] ?? {}
const { dictKey, multiple } = getDictKey(field.format, field)
const render = getRender(field?.format ?? (dictKey ? (multiple ? `dicts` : `dict`) : 'string'), field)
return (v, model) => render(v, { model })
},
col(name, widthOrOptions) {
if (isRef(widthOrOptions) || !isObject(widthOrOptions)) {
widthOrOptions =
widthOrOptions === undefined
? {}
: {
width: widthOrOptions,
}
}
const $t = EntityClass[`__$t`]
const field = EntityClass[`__field_${name}`] ?? {}
const { dictKey, multiple } = getDictKey(field.format, field)
return {
label: EntityClass[`__label_${name}`] ?? $t?.(name) ?? name,
key: name,
...merge(
{
format: dictKey
? multiple
? `dicts`
: `dict`
: ['createUser', 'updateUser'].includes(name)
? 'user'
: 'string',
dictKey,
},
field || {},
widthOrOptions,
),
}
},
}
}