mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-09-09 20:57:17 +08:00
refactor: 优化 GiForm、GiEditTable(同步 GiDemo 更新)
This commit is contained in:
@@ -45,15 +45,18 @@ import type { TableColumnData, TableData } from '@arco-design/web-vue'
|
|||||||
import type { ColumnItem, Disabled } from './type'
|
import type { ColumnItem, Disabled } from './type'
|
||||||
|
|
||||||
defineOptions({ name: 'GiEditTable', inheritAttrs: false })
|
defineOptions({ name: 'GiEditTable', inheritAttrs: false })
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
cellDisabled: false,
|
cellDisabled: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 事件定义 */
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'tr-dblclick', value: { record: any, rowIndex: number }): void
|
(e: 'tr-dblclick', value: { record: any, rowIndex: number }): void
|
||||||
(e: 'td-dblclick', value: { record: any, rowIndex: number, column: TableColumnData }): void
|
(e: 'td-dblclick', value: { record: any, rowIndex: number, column: TableColumnData }): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
/** 插槽定义 */
|
||||||
defineSlots<{
|
defineSlots<{
|
||||||
[propsName: string]: (props: { record: T, rowIndex: number, column: ColumnItem }) => void
|
[propsName: string]: (props: { record: T, rowIndex: number, column: ColumnItem }) => void
|
||||||
}>()
|
}>()
|
||||||
@@ -66,36 +69,61 @@ interface Props {
|
|||||||
|
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
/** 表单数据 */
|
||||||
const form = computed(() => ({ tableData: props.data }))
|
const form = computed(() => ({ tableData: props.data }))
|
||||||
|
|
||||||
|
/** 表单实例 */
|
||||||
const formRef = useTemplateRef('formRef')
|
const formRef = useTemplateRef('formRef')
|
||||||
|
|
||||||
|
/** 获取表头必填星号*样式 */
|
||||||
const headerCellClass = (col: ColumnItem) => {
|
const headerCellClass = (col: ColumnItem) => {
|
||||||
return col.required ? 'gi_column_require' : ''
|
return col.required ? 'gi_column_require' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const getComponentBindProps = (col: ColumnItem) => {
|
/** 静态配置 */
|
||||||
// 组件默认配置映射表
|
const STATIC_PROPS = new Map<ColumnItem['type'], Partial<ColumnItem['props']>>([
|
||||||
const ConfigMap = new Map<ColumnItem['type'], Partial<Omit<ColumnItem['props'], 'placeholder'> & { placeholder?: string | string[] }>>([
|
['input', { allowClear: true, maxLength: 20 }],
|
||||||
['input', { allowClear: true, placeholder: `请输入${col.title}`, maxLength: 50 }],
|
['textarea', { allowClear: false, maxLength: 200 }],
|
||||||
['input-number', { placeholder: `请输入${col.title}` }],
|
['input-tag', { allowClear: true }],
|
||||||
['textarea', { allowClear: false, placeholder: `请填写${col.title}`, maxLength: 200 }],
|
['mention', { allowClear: true }],
|
||||||
['input-tag', { allowClear: true, placeholder: `请输入${col.title}` }],
|
['select', { allowClear: true }],
|
||||||
['mention', { allowClear: true, placeholder: `请输入${col.title}` }],
|
['tree-select', { allowClear: true }],
|
||||||
['select', { allowClear: true, placeholder: `请选择${col.title}` }],
|
['cascader', { allowClear: true }],
|
||||||
['tree-select', { allowClear: true, placeholder: `请选择${col.title}` }],
|
['date-picker', { allowClear: true }],
|
||||||
['cascader', { allowClear: true, placeholder: `请选择${col.title}` }],
|
['time-picker', { allowClear: true }],
|
||||||
['radio-group', {}],
|
])
|
||||||
['checkbox-group', {}],
|
|
||||||
['date-picker', { allowClear: true, placeholder: '请选择日期' }],
|
/** 获取组件默认占位 */
|
||||||
['time-picker', { allowClear: true, placeholder: '请选择时间' }],
|
const getPlaceholder = (item: ColumnItem) => {
|
||||||
])
|
if (!item.type) return undefined
|
||||||
// 获取默认配置
|
if (['input', 'input-tag', 'mention'].includes(item.type)) {
|
||||||
const defaultProps = ConfigMap.get(col.type) || {}
|
return `请输入${item.title}`
|
||||||
// 合并默认配置和自定义配置
|
}
|
||||||
return { ...defaultProps, ...col.props }
|
if (['textarea'].includes(item.type)) {
|
||||||
|
return `请填写${item.title}`
|
||||||
|
}
|
||||||
|
if (['select', 'tree-select', 'cascader'].includes(item.type)) {
|
||||||
|
return `请选择${item.title}`
|
||||||
|
}
|
||||||
|
if (['date-picker'].includes(item.type)) {
|
||||||
|
return '请选择日期'
|
||||||
|
}
|
||||||
|
if (['time-picker'].includes(item.type)) {
|
||||||
|
return '请选择时间'
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 获取组件默认配置 */
|
||||||
|
const getComponentBindProps = (col: ColumnItem) => {
|
||||||
|
return {
|
||||||
|
...STATIC_PROPS.get(col.type) || {},
|
||||||
|
placeholder: getPlaceholder(col),
|
||||||
|
...col.props,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取组件默认规则 */
|
||||||
const getRuleMessage = (col: ColumnItem) => {
|
const getRuleMessage = (col: ColumnItem) => {
|
||||||
if (['input', 'input-number', 'input-tag', 'mention'].includes(col.type ?? '')) {
|
if (['input', 'input-number', 'input-tag', 'mention'].includes(col.type ?? '')) {
|
||||||
return `请输入${col.title}`
|
return `请输入${col.title}`
|
||||||
@@ -106,12 +134,14 @@ const getRuleMessage = (col: ColumnItem) => {
|
|||||||
return `请选择${col.title}`
|
return `请选择${col.title}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 判断是否禁用 */
|
||||||
const isDisabled: Props['cellDisabled'] = (p) => {
|
const isDisabled: Props['cellDisabled'] = (p) => {
|
||||||
if (typeof props?.cellDisabled === 'boolean') return props.cellDisabled
|
if (typeof props?.cellDisabled === 'boolean') return props.cellDisabled
|
||||||
if (typeof props?.cellDisabled === 'function') return props.cellDisabled(p)
|
if (typeof props?.cellDisabled === 'function') return props.cellDisabled(p)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 暴露表单实例 */
|
||||||
defineExpose({ formRef })
|
defineExpose({ formRef })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
<component
|
<component
|
||||||
:is="`a-${item.type}`" v-else v-bind="getComponentBindProps(item)"
|
:is="`a-${item.type}`" v-else v-bind="getComponentBindProps(item)"
|
||||||
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
:model-value="modelValue[item.field as keyof typeof modelValue]"
|
||||||
@update:model-value="valueChange($event, item.field)"
|
@update:model-value="updateValue($event, item.field)"
|
||||||
>
|
>
|
||||||
<template v-for="(slotValue, slotKey) in item?.slots" :key="slotKey" #[slotKey]="scope">
|
<template v-for="(slotValue, slotKey) in item?.slots" :key="slotKey" #[slotKey]="scope">
|
||||||
<template v-if="typeof slotValue === 'string'">{{ slotValue }}</template>
|
<template v-if="typeof slotValue === 'string'">{{ slotValue }}</template>
|
||||||
@@ -50,8 +50,9 @@
|
|||||||
</a-grid-item>
|
</a-grid-item>
|
||||||
</template>
|
</template>
|
||||||
<a-grid-item
|
<a-grid-item
|
||||||
v-if="props.search" v-bind="defaultGridItemProps" :span="defaultGridItemProps?.span"
|
v-if="props.search" :key="!props.suffix ? String(collapsed) : undefined"
|
||||||
:suffix="props.search && props.suffix"
|
v-bind="defaultGridItemProps" :span="defaultGridItemProps?.span"
|
||||||
|
:suffix="props.search && (props.suffix || (!props.suffix && collapsed))"
|
||||||
>
|
>
|
||||||
<a-space wrap>
|
<a-space wrap>
|
||||||
<slot name="suffix">
|
<slot name="suffix">
|
||||||
@@ -135,35 +136,66 @@ const defaultGridItemProps = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const formRef = useTemplateRef('formRef')
|
const formRef = useTemplateRef('formRef')
|
||||||
|
/** 是否折叠 */
|
||||||
const collapsed = ref(props.defaultCollapsed)
|
const collapsed = ref(props.defaultCollapsed)
|
||||||
|
/** 数据字典 */
|
||||||
const dicData: Record<string, any> = reactive({})
|
const dicData: Record<string, any> = reactive({})
|
||||||
|
|
||||||
// 组件的默认props配置
|
/** 静态配置 */
|
||||||
|
const STATIC_PROPS = new Map<ColumnItem['type'], Partial<ColumnItem['props']>>([
|
||||||
|
['input', { allowClear: true, maxLength: 255, showWordLimit: !props.search }],
|
||||||
|
['input-password', { allowClear: true, showWordLimit: !props.search }],
|
||||||
|
['textarea', { allowClear: false, maxLength: 200, showWordLimit: !props.search, autoSize: { minRows: 3, maxRows: 5 } }],
|
||||||
|
['input-tag', { allowClear: true }],
|
||||||
|
['mention', { allowClear: true }],
|
||||||
|
['select', { allowClear: true }],
|
||||||
|
['tree-select', { allowClear: true }],
|
||||||
|
['cascader', { allowClear: true }],
|
||||||
|
['date-picker', { allowClear: true }],
|
||||||
|
['time-picker', { allowClear: true }],
|
||||||
|
])
|
||||||
|
|
||||||
|
/** 获取组件默认占位 */
|
||||||
|
const getPlaceholder = (item: ColumnItem) => {
|
||||||
|
if (!item.type) return undefined
|
||||||
|
if (['input', 'input-number', 'input-password', 'textarea', 'input-tag', 'mention'].includes(item.type)) {
|
||||||
|
return `请输入${item.label}`
|
||||||
|
}
|
||||||
|
if (['select', 'tree-select', 'cascader'].includes(item.type)) {
|
||||||
|
return `请选择${item.label}`
|
||||||
|
}
|
||||||
|
if (['date-picker'].includes(item.type)) {
|
||||||
|
return '请选择日期'
|
||||||
|
}
|
||||||
|
if (['time-picker'].includes(item.type)) {
|
||||||
|
return '请选择时间'
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取选项数据 */
|
||||||
|
const getOptions = (item: ColumnItem): any[] | undefined => {
|
||||||
|
if (!item.type) return undefined
|
||||||
|
/** 需要选项数据的组件类型 */
|
||||||
|
const arr = ['select', 'tree-select', 'cascader', 'radio-group', 'checkbox-group']
|
||||||
|
if (arr.includes(item.type)) {
|
||||||
|
return dicData[item.field] || []
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取组件绑定属性 */
|
||||||
const getComponentBindProps = (item: ColumnItem) => {
|
const getComponentBindProps = (item: ColumnItem) => {
|
||||||
// 组件默认配置映射表
|
return {
|
||||||
const ConfigMap = new Map<ColumnItem['type'], Partial<ColumnItem['props'] & { placeholder: string }>>([
|
...STATIC_PROPS.get(item.type) || {},
|
||||||
['input', { allowClear: true, placeholder: `请输入${item.label}`, maxLength: 255, showWordLimit: !props.search }],
|
placeholder: getPlaceholder(item),
|
||||||
['input-password', { placeholder: `请输入${item.label}`, showWordLimit: !props.search }],
|
options: getOptions(item),
|
||||||
['input-number', { placeholder: `请输入${item.label}` }],
|
...item.props,
|
||||||
['textarea', { allowClear: false, placeholder: `请输入${item.label}`, maxLength: 200, showWordLimit: !props.search, autoSize: { minRows: 3, maxRows: 5 } }],
|
}
|
||||||
['input-tag', { allowClear: true, placeholder: `请输入${item.label}` }],
|
|
||||||
['mention', { allowClear: true, placeholder: `请输入${item.label}` }],
|
|
||||||
['select', { allowClear: true, placeholder: `请选择${item.label}`, options: dicData[item.field] || [] }],
|
|
||||||
['tree-select', { allowClear: true, placeholder: `请选择${item.label}` }],
|
|
||||||
['cascader', { allowClear: true, placeholder: `请选择${item.label}`, options: dicData[item.field] || [] }],
|
|
||||||
['radio-group', { options: dicData[item.field] || [] }],
|
|
||||||
['checkbox-group', { options: dicData[item.field] || [] }],
|
|
||||||
['date-picker', { allowClear: true, placeholder: '请选择日期' }],
|
|
||||||
['time-picker', { allowClear: true, placeholder: '请选择时间' }],
|
|
||||||
])
|
|
||||||
// 获取默认配置
|
|
||||||
const defaultProps = ConfigMap.get(item.type) || {}
|
|
||||||
// 合并默认配置和自定义配置
|
|
||||||
return { ...defaultProps, ...item.props }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 表单数据更新 */
|
/** 表单数据更新 */
|
||||||
const valueChange = (value: any, field: string) => {
|
const updateValue = (value: any, field: string) => {
|
||||||
emit('update:modelValue', Object.assign(props.modelValue, { [field]: value }))
|
emit('update:modelValue', Object.assign(props.modelValue, { [field]: value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<!-- 列拖拽排序区域 -->
|
<!-- 列拖拽排序区域 -->
|
||||||
<div class="gi-table__draggable">
|
<div class="gi-table__draggable">
|
||||||
<VueDraggable v-model="localColumns" @end="handleDragEnd">
|
<VueDraggable v-model="localColumns" :animation="150" @end="handleDragEnd">
|
||||||
<div
|
<div
|
||||||
v-for="item in localColumns"
|
v-for="item in localColumns"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
|
2
src/types/components.d.ts
vendored
2
src/types/components.d.ts
vendored
@@ -11,6 +11,7 @@ declare module 'vue' {
|
|||||||
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
|
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
|
||||||
CellCopy: typeof import('./../components/CellCopy/index.vue')['default']
|
CellCopy: typeof import('./../components/CellCopy/index.vue')['default']
|
||||||
Chart: typeof import('./../components/Chart/index.vue')['default']
|
Chart: typeof import('./../components/Chart/index.vue')['default']
|
||||||
|
ColumnSetting: typeof import('./../components/GiTable/src/components/ColumnSetting.vue')['default']
|
||||||
CronForm: typeof import('./../components/GenCron/CronForm/index.vue')['default']
|
CronForm: typeof import('./../components/GenCron/CronForm/index.vue')['default']
|
||||||
CronModal: typeof import('./../components/GenCron/CronModal/index.vue')['default']
|
CronModal: typeof import('./../components/GenCron/CronModal/index.vue')['default']
|
||||||
DateRangePicker: typeof import('./../components/DateRangePicker/index.vue')['default']
|
DateRangePicker: typeof import('./../components/DateRangePicker/index.vue')['default']
|
||||||
@@ -58,7 +59,6 @@ declare module 'vue' {
|
|||||||
SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default']
|
SecondForm: typeof import('./../components/GenCron/CronForm/component/second-form.vue')['default']
|
||||||
SplitPanel: typeof import('./../components/SplitPanel/index.vue')['default']
|
SplitPanel: typeof import('./../components/SplitPanel/index.vue')['default']
|
||||||
TextCopy: typeof import('./../components/TextCopy/index.vue')['default']
|
TextCopy: typeof import('./../components/TextCopy/index.vue')['default']
|
||||||
ToggleDark: typeof import('./../components/ToggleDark/index.vue')['default']
|
|
||||||
UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
|
UserSelect: typeof import('./../components/UserSelect/index.vue')['default']
|
||||||
Verify: typeof import('./../components/Verify/index.vue')['default']
|
Verify: typeof import('./../components/Verify/index.vue')['default']
|
||||||
VerifyPoints: typeof import('./../components/Verify/Verify/VerifyPoints.vue')['default']
|
VerifyPoints: typeof import('./../components/Verify/Verify/VerifyPoints.vue')['default']
|
||||||
|
@@ -72,7 +72,7 @@ const {
|
|||||||
const columns: TableInstance['columns'] = [
|
const columns: TableInstance['columns'] = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
width: 66,
|
minWidth: 66,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
},
|
},
|
||||||
|
@@ -83,7 +83,7 @@ const {
|
|||||||
const columns: TableInstance['columns'] = [
|
const columns: TableInstance['columns'] = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
width: 66,
|
minWidth: 66,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
render: ({ rowIndex }) => h('span', {}, rowIndex + 1 + (pagination.current - 1) * pagination.pageSize),
|
||||||
},
|
},
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
<GiIconSelector v-model="form.icon" />
|
<GiIconSelector v-model="form.icon" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-else label="权限标识" field="permission">
|
<a-form-item v-else label="权限标识" field="permission">
|
||||||
<a-input v-model.trim="form.permission" placeholder="system:user:add" allow-clear />
|
<a-input v-model.trim="form.permission" placeholder="system:user:add" :max-length="100" show-word-limit allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col v-bind="colProps">
|
<a-col v-bind="colProps">
|
||||||
<a-form-item v-if="form.type === 2" label="权限标识" field="permission">
|
<a-form-item v-if="form.type === 2" label="权限标识" field="permission">
|
||||||
<a-input v-model.trim="form.permission" placeholder="system:user:add" allow-clear />
|
<a-input v-model.trim="form.permission" placeholder="system:user:add" :max-length="100" show-word-limit allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
Reference in New Issue
Block a user