vxe-pc-ui
Version:
A vue based PC component library
353 lines (315 loc) • 11.2 kB
text/typescript
import { defineComponent, ref, h, PropType, reactive, nextTick, provide, watch } from 'vue'
import XEUtils from 'xe-utils'
import { toCssUnit } from '../../ui/src/dom'
import { getConfig, createEvent, renderer, useSize } from '../../ui'
import { createListDesignActionButton } from '../render/util'
import { getDefaultSettingFormData } from './default-setting-data'
import LayoutPreviewComponent from './layout-preview'
import LayoutSettingComponent from './layout-setting'
import type { VxeListDesignDefines, VxeListDesignPropTypes, ListDesignReactData, ListDesignPrivateRef, VxeListDesignPrivateComputed, VxeListDesignConstructor, VxeListDesignPrivateMethods, ListDesignMethods, ListDesignPrivateMethods, VxeFormDesignDefines, VxeGlobalRendererHandles } from '../../../types'
export default defineComponent({
name: 'VxeListDesign',
props: {
size: {
type: String as PropType<VxeListDesignPropTypes.Size>,
default: () => getConfig().listDesign.size || getConfig().size
},
height: {
type: [String, Number] as PropType<VxeListDesignPropTypes.Height>,
default: () => getConfig().listDesign.height
},
config: Object as PropType<VxeListDesignPropTypes.Config>,
showPc: {
type: Boolean as PropType<VxeListDesignPropTypes.ShowPc>,
default: () => getConfig().listDesign.showPc
},
showMobile: {
type: Boolean as PropType<VxeListDesignPropTypes.ShowMobile>,
default: () => getConfig().listDesign.showMobile
},
actionCodes: Array as PropType<VxeListDesignPropTypes.ActionCodes>,
formRender: Object as PropType<VxeListDesignPropTypes.FormRender>
},
emits: [],
setup (props, context) {
const { emit, slots } = context
const xID = XEUtils.uniqueId()
const refElem = ref<HTMLDivElement>()
const { computeSize } = useSize(props)
const reactData = reactive<ListDesignReactData>({
formData: {} as VxeListDesignDefines.DefaultSettingFormDataObjVO,
searchFormData: {},
searchFormItems: [],
listTableColumns: []
})
const refMaps: ListDesignPrivateRef = {
refElem
}
const computeMaps: VxeListDesignPrivateComputed = {
computeSize
}
const $xeListDesign = {
xID,
props,
context,
reactData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
} as unknown as VxeListDesignConstructor & VxeListDesignPrivateMethods
const systemConfigList: VxeGlobalRendererHandles.CreateListDesignSettingActionButtonConfigResult[] = []
const customConfigList: VxeGlobalRendererHandles.CreateListDesignSettingActionButtonConfigResult[] = []
renderer.forEach((item, name) => {
const { createListDesignSettingActionButtonConfig } = item
if (createListDesignSettingActionButtonConfig) {
const params = { name }
const btnConfig = Object.assign(createListDesignActionButton({ code: name }), createListDesignSettingActionButtonConfig(params))
if (btnConfig.type === 'custom') {
customConfigList.push(btnConfig)
} else {
systemConfigList.push(btnConfig)
}
}
})
const parseWidgetColumn = (widget: VxeFormDesignDefines.WidgetObjItem) => {
return {
title: widget.title,
field: widget.field,
visible: !widget.hidden,
width: '',
cellRender: {
name: widget.name,
props: widget.options
}
}
}
/**
* 解析表单设计 JSON
*/
const parseFormDesignColumns = (config: Partial<VxeFormDesignDefines.FormDesignConfig>) => {
const tableColumns: VxeListDesignDefines.ListColumnObjItem[] = []
if (config) {
const { widgetData } = config
if (widgetData) {
widgetData.forEach(item => {
const { name } = item
if (name) {
// 如果是行列
if (name === 'row') {
item.children.forEach(childItem => {
if (childItem.name) {
tableColumns.push(parseWidgetColumn(childItem))
}
})
} else if (name === 'subtable') {
// 如果是子表
} else {
tableColumns.push(parseWidgetColumn(item))
}
}
})
}
}
return tableColumns
}
const configToSearchItems = (searchItems: VxeListDesignDefines.SearchItemObjItem[]): {
data: Record<string, any>
items: VxeListDesignDefines.SearchItemObjItem[]
} => {
if (searchItems) {
const data: Record<string, any> = {}
const items = searchItems.map(item => {
data[item.field] = null
return {
field: item.field,
title: item.title,
folding: item.folding,
itemRender: item.itemRender
}
})
return {
items,
data
}
}
return { items: [], data: {} }
}
const configToListColumns = (listColumns: VxeListDesignDefines.ListColumnObjItem[]): VxeListDesignDefines.ListColumnObjItem[] => {
if (listColumns) {
return listColumns.map(item => {
return {
field: item.field,
title: item.title,
visible: !!item.visible,
width: item.width,
cellRender: XEUtils.clone(item.cellRender)
}
})
}
return []
}
const loadConfig = (config: Partial<VxeListDesignDefines.ListDesignConfig>) => {
const { formConfig, searchItems, listColumns } = config
if (formConfig) {
loadFormConfig(formConfig)
}
if (searchItems) {
setSearchItems(searchItems)
}
if (listColumns) {
reactData.listTableColumns = parseColumnConfigs(listColumns)
}
return nextTick()
}
const parseColumnConfigs = (listColumns: VxeListDesignDefines.ListColumnObjItem[]) => {
return configToListColumns(listColumns)
}
const loadFormConfig = (data: any) => {
reactData.formData = Object.assign({}, createSettingForm(), data)
return nextTick()
}
const getSearchItems = () => {
return reactData.searchFormItems
}
const setSearchItems = (searchItems: VxeListDesignDefines.SearchItemObjItem[]) => {
const { data, items } = configToSearchItems(searchItems)
reactData.searchFormData = data
reactData.searchFormItems = items
return nextTick()
}
const getListColumns = () => {
return reactData.listTableColumns
}
const setListColumns = (listColumns: VxeListDesignDefines.ListColumnObjItem[]) => {
reactData.listTableColumns = parseColumnConfigs(listColumns)
return nextTick()
}
const createSettingForm = () => {
const { actionCodes, formRender } = props
let conf = getDefaultSettingFormData()
// 处理默认按钮
if (actionCodes && actionCodes.length) {
if (!conf.actionButtonList || !conf.actionButtonList.length) {
const defActionBtnList: VxeListDesignDefines.DefaultSettingFormActionButton[] = []
actionCodes.forEach(item => {
if (XEUtils.isObject(item) && item.default) {
const sysItem = systemConfigList.find(obj => obj.code === item.code)
if (sysItem) {
defActionBtnList.push(createListDesignActionButton({
type: sysItem.type,
code: sysItem.code
}))
}
}
})
conf.actionButtonList = defActionBtnList
}
}
// 如果为自定义渲染
if (formRender && formRender.name) {
const compConf = renderer.get(formRender.name)
const createFormConfig = compConf ? compConf.createListDesignSettingFormConfig : null
const params = { name: formRender.name }
conf = ((createFormConfig ? createFormConfig(params) : {}) || {}) as any
}
return conf
}
const initSettingForm = () => {
reactData.formData = createSettingForm()
}
const clearConfig = () => {
loadConfig({
searchItems: [],
listColumns: []
})
initSettingForm()
return nextTick()
}
const listDesignMethods: ListDesignMethods = {
dispatchEvent (type, params, evnt) {
emit(type, createEvent(evnt, { $listDesign: $xeListDesign }, params))
},
loadFormDesignConfig (config) {
const { listTableColumns } = reactData
const oldMaps: Record<string, VxeListDesignDefines.ListColumnObjItem> = {}
XEUtils.eachTree(listTableColumns, item => {
oldMaps[item.field] = item
}, { children: 'children' })
const columns = parseFormDesignColumns(config)
XEUtils.eachTree(columns, item => {
const oldItem = oldMaps[item.field]
if (oldItem) {
if (oldItem.width) {
item.width = oldItem.width
}
item.visible = oldItem.visible
}
}, { children: 'children' })
reactData.listTableColumns = columns
return nextTick()
},
reloadFormDesignConfig (config) {
reactData.listTableColumns = parseFormDesignColumns(config)
return nextTick()
},
getSearchItems,
setSearchItems,
getListColumns,
setListColumns,
getConfig () {
return {
formConfig: reactData.formData,
searchItems: getSearchItems(),
listColumns: getListColumns()
}
},
loadConfig,
reloadConfig (config) {
clearConfig()
return loadConfig(config)
},
clearConfig
}
const listDesignPrivateMethods: ListDesignPrivateMethods = {
}
Object.assign($xeListDesign, listDesignMethods, listDesignPrivateMethods)
const renderVN = () => {
const { height } = props
const vSize = computeSize.value
const headerSlot = slots.header
return h('div', {
ref: refElem,
class: ['vxe-list-design', {
[`size--${vSize}`]: vSize
}],
style: height
? {
height: toCssUnit(height)
}
: null
}, [
h('div', {
class: 'vxe-list-design--header'
}, headerSlot ? headerSlot({}) : []),
h('div', {
class: 'vxe-list-design--body'
}, [
h(LayoutPreviewComponent),
h(LayoutSettingComponent)
])
])
}
provide('$xeListDesign', $xeListDesign)
watch(() => props.config, (value) => {
loadConfig(value || {})
})
initSettingForm()
if (props.config) {
loadConfig(props.config)
}
$xeListDesign.renderVN = renderVN
return $xeListDesign
},
render () {
return this.renderVN()
}
})