Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-vue-admin
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-vue-admin
Commits
9c2f3f30
提交
9c2f3f30
authored
12月 31, 2020
作者:
vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(table): refactor table #150 #148 #146 #130 #76
上级
f3a70eed
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
35 个修改的文件
包含
740 行增加
和
454 行删除
+740
-454
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+51
-8
table-demo.ts
mock/demo/table-demo.ts
+8
-0
index.ts
src/components/Form/index.ts
+3
-0
ApiSelect.vue
src/components/Form/src/components/ApiSelect.vue
+4
-1
useOpenKeys.ts
src/components/Menu/src/useOpenKeys.ts
+5
-3
index.ts
src/components/Table/index.ts
+1
-2
BasicTable.vue
src/components/Table/src/BasicTable.vue
+34
-43
componentMap.ts
src/components/Table/src/componentMap.ts
+4
-4
EditTableHeaderIcon.vue
src/components/Table/src/components/EditTableHeaderIcon.vue
+2
-1
HeaderCell.vue
src/components/Table/src/components/HeaderCell.vue
+55
-0
TableAction.vue
src/components/Table/src/components/TableAction.vue
+3
-4
CellComponent.ts
...components/Table/src/components/editable/CellComponent.ts
+33
-0
EditableCell.vue
...components/Table/src/components/editable/EditableCell.vue
+0
-0
helper.ts
src/components/Table/src/components/editable/helper.ts
+26
-0
index.ts
src/components/Table/src/components/editable/index.ts
+52
-0
renderEditable.tsx
src/components/Table/src/components/renderEditable.tsx
+0
-241
renderExpandIcon.tsx
src/components/Table/src/components/renderExpandIcon.tsx
+0
-14
ColumnSetting.vue
...omponents/Table/src/components/settings/ColumnSetting.vue
+1
-1
const.ts
src/components/Table/src/const.ts
+4
-0
useColumns.ts
src/components/Table/src/hooks/useColumns.ts
+65
-8
useDataSource.ts
src/components/Table/src/hooks/useDataSource.ts
+59
-3
useTable.ts
src/components/Table/src/hooks/useTable.ts
+38
-10
useTableScroll.ts
src/components/Table/src/hooks/useTableScroll.ts
+5
-2
props.ts
src/components/Table/src/props.ts
+9
-1
editable-cell.less
src/components/Table/src/style/editable-cell.less
+0
-39
index.less
src/components/Table/src/style/index.less
+10
-6
componentType.ts
src/components/Table/src/types/componentType.ts
+1
-2
table.ts
src/components/Table/src/types/table.ts
+42
-14
MixSider.vue
src/layouts/default/sider/MixSider.vue
+5
-0
comp.ts
src/router/menus/modules/demo/comp.ts
+9
-0
dateUtil.ts
src/utils/dateUtil.ts
+7
-4
EditCellTable.vue
src/views/demo/table/EditCellTable.vue
+100
-26
EditRowTable.vue
src/views/demo/table/EditRowTable.vue
+96
-15
FixedColumn.vue
src/views/demo/table/FixedColumn.vue
+1
-1
tableData.tsx
src/views/demo/table/tableData.tsx
+7
-1
没有找到文件。
CHANGELOG.zh_CN.md
浏览文件 @
9c2f3f30
## Wip
### ✨ 表格破坏性更新
-
重构了可编辑单元格及可编辑行。具体看示例。写法已改变。针对可编辑表格。
-
表格编辑支持表单校验
-
在表格列配置增加了以下配置
```
bash
{
# 默认是否显示列。不显示的可以在列配置打开
defaultHidden?: boolean
;
# 列头右侧帮助文本
helpMessage?: string | string[]
;
# 自定义格式化 单元格内容。 支持时间/枚举自动转化
format?: CellFormat
;
# Editable
# 是否是可编辑单元格
edit?: boolean
;
# 是否是可编辑行
editRow?: boolean
;
# 编辑状态。
editable?: boolean
;
# 编辑组件
editComponent?: ComponentType
;
# 所对应组件的参数
editComponentProps?: Recordable
;
# 校验
editRule?: boolean |
((
text: string, record: Recordable
)
=>
Promise<string>
)
;
# 值枚举转化
editValueMap?:
(
value: any
)
=>
string
;
# 触发编辑正航
record.onEditRow?:
()
=>
void
;
}
```
### ✨ 表格重构
-
新增
`clickToRowSelect`
属性。用于控制点击行是否选中勾选框
-
监听行点击事件
-
表格列配置按钮增加 列拖拽,列固定功能。
-
表格列配置新增
`defaultHidden`
属性。用于默认隐藏。可在表格列配置勾选显示
-
更强大的列配置
-
useTable:支持动态改变参数。可以传入
`Ref`
类型与
`Computed`
类型进行动态更改
-
useTable:新增返回
`getForm`
函数。可以用于操作表格内的表单
-
修复表格已知的问题
### ✨ Features
-
新增
`v-ripple`
水波纹指令
...
...
@@ -12,14 +62,6 @@
-
form: 新增远程下拉
`ApiSelect`
及示例
-
form: 新增
`autoFocusFirstItem`
配置。用于配置是否聚焦表单第一个输入框
-
useForm: 支持动态改变参数。可以传入
`Ref`
类型与
`Computed`
类型进行动态更改
-
table: 新增
`clickToRowSelect`
属性。用于控制点击行是否选中勾选狂
-
table: 监听行点击事件
-
table: 表格列配置按钮增加 列拖拽,列固定功能。
-
table:表格列配置新增
`defaultHidden`
属性。用于默认隐藏。可在表格列配置勾选显示
### ✨ Refactor
-
重构表单,解决已知 bug
### ⚡ Performance Improvements
...
...
@@ -30,6 +72,7 @@
### 🎫 Chores
-
升级
`ant-design-vue`
到
`2.0.0-rc.7`
-
升级
`vue`
到
`3.0.5`
### 🐛 Bug Fixes
...
...
mock/demo/table-demo.ts
浏览文件 @
9c2f3f30
...
...
@@ -10,6 +10,14 @@ const demoList = (() => {
endTime
:
'@datetime'
,
address
:
'@city()'
,
name
:
'@cname()'
,
name1
:
'@cname()'
,
name2
:
'@cname()'
,
name3
:
'@cname()'
,
name4
:
'@cname()'
,
name5
:
'@cname()'
,
name6
:
'@cname()'
,
name7
:
'@cname()'
,
name8
:
'@cname()'
,
'no|100000-10000000'
:
100000
,
'status|1'
:
[
'normal'
,
'enable'
,
'disable'
],
});
...
...
src/components/Form/index.ts
浏览文件 @
9c2f3f30
...
...
@@ -9,4 +9,7 @@ export * from './src/types/formItem';
export
{
useComponentRegister
}
from
'./src/hooks/useComponentRegister'
;
export
{
useForm
}
from
'./src/hooks/useForm'
;
export
{
default
as
ApiSelect
}
from
'./src/components/ApiSelect.vue'
;
export
{
default
as
RadioButtonGroup
}
from
'./src/components/RadioButtonGroup.vue'
;
export
{
BasicForm
};
src/components/Form/src/components/ApiSelect.vue
浏览文件 @
9c2f3f30
...
...
@@ -50,7 +50,8 @@
labelField
:
propTypes
.
string
.
def
(
'label'
),
valueField
:
propTypes
.
string
.
def
(
'value'
),
},
setup
(
props
)
{
emits
:
[
'options-change'
,
'change'
],
setup
(
props
,
{
emit
})
{
const
options
=
ref
<
OptionsItem
[]
>
([]);
const
loading
=
ref
(
false
);
const
attrs
=
useAttrs
();
...
...
@@ -86,11 +87,13 @@
const
res
=
await
api
(
props
.
params
);
if
(
Array
.
isArray
(
res
))
{
options
.
value
=
res
;
emit
(
'options-change'
,
unref
(
options
));
return
;
}
if
(
props
.
resultField
)
{
options
.
value
=
get
(
res
,
props
.
resultField
)
||
[];
}
emit
(
'options-change'
,
unref
(
options
));
}
catch
(
error
)
{
console
.
warn
(
error
);
}
finally
{
...
...
src/components/Menu/src/useOpenKeys.ts
浏览文件 @
9c2f3f30
...
...
@@ -15,7 +15,7 @@ export function useOpenKeys(
mode
:
Ref
<
MenuModeEnum
>
,
accordion
:
Ref
<
boolean
>
)
{
const
{
getCollapsed
}
=
useMenuSetting
();
const
{
getCollapsed
,
getIsMixSidebar
}
=
useMenuSetting
();
function
setOpenKeys
(
path
:
string
)
{
if
(
mode
.
value
===
MenuModeEnum
.
HORIZONTAL
)
{
...
...
@@ -30,7 +30,9 @@ export function useOpenKeys(
}
const
getOpenKeys
=
computed
(()
=>
{
return
unref
(
getCollapsed
)
?
menuState
.
collapsedOpenKeys
:
menuState
.
openKeys
;
const
collapse
=
unref
(
getIsMixSidebar
)
?
false
:
unref
(
getCollapsed
);
return
collapse
?
menuState
.
collapsedOpenKeys
:
menuState
.
openKeys
;
});
/**
...
...
@@ -42,7 +44,7 @@ export function useOpenKeys(
}
function
handleOpenChange
(
openKeys
:
string
[])
{
if
(
unref
(
mode
)
===
MenuModeEnum
.
HORIZONTAL
||
!
unref
(
accordion
))
{
if
(
unref
(
mode
)
===
MenuModeEnum
.
HORIZONTAL
||
!
unref
(
accordion
)
||
unref
(
getIsMixSidebar
)
)
{
menuState
.
openKeys
=
openKeys
;
}
else
{
// const menuList = toRaw(menus.value);
...
...
src/components/Table/index.ts
浏览文件 @
9c2f3f30
...
...
@@ -3,7 +3,6 @@ import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export
{
default
as
BasicTable
}
from
'./src/BasicTable.vue'
;
export
{
default
as
TableAction
}
from
'./src/components/TableAction.vue'
;
// export { default as TableImg } from './src/components/TableImg.vue';
export
{
renderEditableCell
,
renderEditableRow
}
from
'./src/components/renderEditable'
;
export
{
default
as
EditTableHeaderIcon
}
from
'./src/components/EditTableHeaderIcon.vue'
;
export
const
TableImg
=
createAsyncComponent
(()
=>
import
(
'./src/components/TableImg.vue'
));
...
...
@@ -17,4 +16,4 @@ export { useTable } from './src/hooks/useTable';
export
type
{
FormSchema
,
FormProps
}
from
'/@/components/Form/src/types/form'
;
export
type
{
EditRecordRow
}
from
'./src/components/
renderE
ditable'
;
export
type
{
EditRecordRow
}
from
'./src/components/
e
ditable'
;
src/components/Table/src/BasicTable.vue
浏览文件 @
9c2f3f30
...
...
@@ -34,19 +34,19 @@
<
template
#[
item
]="
data
"
v-for=
"item in Object.keys($slots)"
>
<slot
:name=
"item"
v-bind=
"data"
/>
</
template
>
<
template
#[`
header-
${
column
.
dataIndex
}`]
v-for=
"column in columns"
:key=
"column.dataIndex"
>
<HeaderCell
:column=
"column"
/>
</
template
>
</Table>
</div>
</template>
<
script
lang=
"ts"
>
import
type
{
BasicTableProps
,
TableActionType
,
SizeType
,
SorterResult
}
from
'./types/table'
;
import
{
PaginationProps
}
from
'./types/pagination'
;
import
type
{
BasicTableProps
,
TableActionType
,
SizeType
}
from
'./types/table'
;
import
{
defineComponent
,
ref
,
computed
,
unref
}
from
'vue'
;
import
{
Table
}
from
'ant-design-vue'
;
import
{
BasicForm
,
useForm
}
from
'/@/components/Form/index'
;
import
{
isFunction
}
from
'/@/utils/is'
;
import
{
omit
}
from
'lodash-es'
;
import
{
usePagination
}
from
'./hooks/usePagination'
;
...
...
@@ -61,15 +61,20 @@
import
{
createTableContext
}
from
'./hooks/useTableContext'
;
import
{
useTableFooter
}
from
'./hooks/useTableFooter'
;
import
{
useTableForm
}
from
'./hooks/useTableForm'
;
import
{
useExpose
}
from
'/@/hooks/core/useExpose'
;
import
{
useDesign
}
from
'/@/hooks/web/useDesign'
;
import
{
basicProps
}
from
'./props'
;
import
{
useExpose
}
from
'/@/hooks/core/useExpose
'
;
import
{
createAsyncComponent
}
from
'/@/utils/factory/createAsyncComponent
'
;
import
'./style/index.less'
;
import
{
useDesign
}
from
'/@/hooks/web/useDesign'
;
export
default
defineComponent
({
props
:
basicProps
,
components
:
{
Table
,
BasicForm
},
components
:
{
Table
,
BasicForm
,
HeaderCell
:
createAsyncComponent
(()
=>
import
(
'./components/HeaderCell.vue'
)),
},
emits
:
[
'fetch-success'
,
'fetch-error'
,
...
...
@@ -80,6 +85,8 @@
'row-contextmenu'
,
'row-mouseenter'
,
'row-mouseleave'
,
'edit-end'
,
'edit-cancel'
,
],
setup
(
props
,
{
attrs
,
emit
,
slots
})
{
const
tableElRef
=
ref
<
ComponentRef
>
(
null
);
...
...
@@ -96,15 +103,19 @@
const
{
getLoading
,
setLoading
}
=
useLoading
(
getProps
);
const
{
getPaginationInfo
,
getPagination
,
setPagination
}
=
usePagination
(
getProps
);
const
{
getSortFixedColumns
,
getColumns
,
setColumns
,
getColumnsRef
,
getCacheColumns
,
}
=
useColumns
(
getProps
,
getPaginationInfo
);
getRowSelection
,
getRowSelectionRef
,
getSelectRows
,
clearSelectedRowKeys
,
getSelectRowKeys
,
deleteSelectRowByKey
,
setSelectedRowKeys
,
}
=
useRowSelection
(
getProps
,
emit
);
const
{
handleTableChange
,
getDataSourceRef
,
getDataSource
,
setTableData
,
...
...
@@ -112,6 +123,7 @@
getRowKey
,
reload
,
getAutoCreateKey
,
updateTableData
,
}
=
useDataSource
(
getProps
,
{
...
...
@@ -119,19 +131,15 @@
setLoading
,
setPagination
,
getFieldsValue
:
formActions
.
getFieldsValue
,
clearSelectedRowKeys
,
},
emit
);
const
{
getRowSelection
,
getRowSelectionRef
,
getSelectRows
,
clearSelectedRowKeys
,
getSelectRowKeys
,
deleteSelectRowByKey
,
setSelectedRowKeys
,
}
=
useRowSelection
(
getProps
,
emit
);
const
{
getViewColumns
,
getColumns
,
setColumns
,
getColumnsRef
,
getCacheColumns
}
=
useColumns
(
getProps
,
getPaginationInfo
);
const
{
getScrollRef
,
redoHeight
}
=
useTableScroll
(
getProps
,
...
...
@@ -178,7 +186,7 @@
tableLayout
:
'fixed'
,
rowSelection
:
unref
(
getRowSelectionRef
),
rowKey
:
unref
(
getRowKey
),
columns
:
unref
(
get
SortFixed
Columns
),
columns
:
unref
(
get
View
Columns
),
pagination
:
unref
(
getPaginationInfo
),
dataSource
:
unref
(
getDataSourceRef
),
footer
:
unref
(
getFooterProps
),
...
...
@@ -197,26 +205,6 @@
return
!!
unref
(
getDataSourceRef
).
length
;
});
function
handleTableChange
(
pagination
:
PaginationProps
,
// @ts-ignore
filters
:
Partial
<
Recordable
<
string
[]
>>
,
sorter
:
SorterResult
)
{
const
{
clearSelectOnPageChange
,
sortFn
}
=
unref
(
getProps
);
if
(
clearSelectOnPageChange
)
{
clearSelectedRowKeys
();
}
setPagination
(
pagination
);
if
(
sorter
&&
isFunction
(
sortFn
))
{
const
sortInfo
=
sortFn
(
sorter
);
fetch
({
sortInfo
});
return
;
}
fetch
();
}
function
setProps
(
props
:
Partial
<
BasicTableProps
>
)
{
innerPropsRef
.
value
=
{
...
unref
(
innerPropsRef
),
...
props
};
}
...
...
@@ -239,6 +227,8 @@
getPaginationRef
:
getPagination
,
getColumns
,
getCacheColumns
,
emit
,
updateTableData
,
getSize
:
()
=>
{
return
unref
(
getBindValues
).
size
as
SizeType
;
},
...
...
@@ -265,6 +255,7 @@
replaceFormSlotKey
,
getFormSlotKeys
,
prefixCls
,
columns
:
getViewColumns
,
};
},
});
...
...
src/components/Table/src/componentMap.ts
浏览文件 @
9c2f3f30
import
{
Component
}
from
'vue'
;
import
type
{
Component
}
from
'vue'
;
import
{
Input
,
Select
,
Checkbox
,
InputNumber
,
Switch
}
from
'ant-design-vue'
;
import
{
ComponentType
}
from
'./types/componentType'
;
import
type
{
ComponentType
}
from
'./types/componentType'
;
import
{
ApiSelect
}
from
'/@/components/Form'
;
const
componentMap
=
new
Map
<
ComponentType
,
Component
>
();
componentMap
.
set
(
'Input'
,
Input
);
componentMap
.
set
(
'InputPassword'
,
Input
.
Password
);
componentMap
.
set
(
'InputNumber'
,
InputNumber
);
componentMap
.
set
(
'Select'
,
Select
);
componentMap
.
set
(
'ApiSelect'
,
ApiSelect
);
componentMap
.
set
(
'Switch'
,
Switch
);
componentMap
.
set
(
'Checkbox'
,
Checkbox
);
componentMap
.
set
(
'CheckboxGroup'
,
Checkbox
.
Group
);
export
function
add
(
compName
:
ComponentType
,
component
:
Component
)
{
componentMap
.
set
(
compName
,
component
);
...
...
src/components/Table/src/components/EditTableHeaderIcon.vue
浏览文件 @
9c2f3f30
<
template
>
<span>
<slot
/>
{{
title
}}
<FormOutlined
class=
"ml-2"
/>
<FormOutlined
/>
</span>
</
template
>
<
script
lang=
"ts"
>
...
...
src/components/Table/src/components/HeaderCell.vue
0 → 100644
浏览文件 @
9c2f3f30
<
template
>
<EditTableHeaderCell
v-if=
"getIsEdit"
>
{{
getTitle
}}
</EditTableHeaderCell>
<span
v-else
>
{{
getTitle
}}
</span>
<BasicHelp
v-if=
"getHelpMessage"
:text=
"getHelpMessage"
:class=
"`$
{prefixCls}__help`" />
</
template
>
<
script
lang=
"ts"
>
import
type
{
PropType
}
from
'vue'
;
import
type
{
BasicColumn
}
from
'../types/table'
;
import
{
defineComponent
,
computed
}
from
'vue'
;
import
{
createAsyncComponent
}
from
'/@/utils/factory/createAsyncComponent'
;
import
{
useDesign
}
from
'/@/hooks/web/useDesign'
;
export
default
defineComponent
({
name
:
'TableHeaderCell'
,
components
:
{
EditTableHeaderCell
:
createAsyncComponent
(()
=>
import
(
'./EditTableHeaderIcon.vue'
)),
BasicHelp
:
createAsyncComponent
(()
=>
import
(
'/@/components/Basic/src/BasicHelp.vue'
)),
},
props
:
{
column
:
{
type
:
Object
as
PropType
<
BasicColumn
>
,
default
:
{},
},
},
setup
(
props
)
{
const
{
prefixCls
}
=
useDesign
(
'basic-table-header-cell'
);
const
getIsEdit
=
computed
(()
=>
{
return
!!
props
.
column
?.
edit
;
});
const
getTitle
=
computed
(()
=>
{
return
props
.
column
?.
customTitle
;
});
const
getHelpMessage
=
computed
(()
=>
{
return
props
.
column
?.
helpMessage
;
});
return
{
prefixCls
,
getIsEdit
,
getTitle
,
getHelpMessage
};
},
});
</
script
>
<
style
lang=
"less"
>
@prefix-cls
:
~
'@{namespace}-basic-table-header-cell'
;
.@
{
prefix-cls
}
{
&__help
{
margin-left
:
8px
;
color
:
rgba
(
0
,
0
,
0
,
0.65
)
!important
;
}
}
</
style
>
src/components/Table/src/components/TableAction.vue
浏览文件 @
9c2f3f30
<
template
>
<div
:class=
"[prefixCls, getAlign]"
>
<template
v-for=
"(action, index) in getActions"
:key=
"`$
{index}`">
<template
v-for=
"(action, index) in getActions"
:key=
"`$
{index}
-${action.label}
`">
<PopConfirmButton
v-bind=
"action"
>
<Icon
:icon=
"action.icon"
class=
"mr-1"
v-if=
"action.icon"
/>
{{
action
.
label
}}
</PopConfirmButton>
<Divider
type=
"vertical"
v-if=
"divider && index
<
getActions
.
length
"
/>
</
template
>
<Dropdown
:trigger=
"['hover']"
:dropMenuList=
"getDropList"
>
<Dropdown
:trigger=
"['hover']"
:dropMenuList=
"getDropList"
v-if=
"dropDownActions"
>
<slot
name=
"more"
/>
<a-button
type=
"link"
size=
"small"
v-if=
"!$slots.more"
>
<MoreOutlined
class=
"icon-more"
/>
...
...
@@ -61,7 +60,7 @@
});
const
getDropList
=
computed
(()
=>
{
return
props
.
dropDownActions
.
map
((
action
,
index
)
=>
{
return
(
props
.
dropDownActions
||
[])
.
map
((
action
,
index
)
=>
{
const
{
label
}
=
action
;
return
{
...
action
,
...
...
src/components/Table/src/components/editable/CellComponent.ts
0 → 100644
浏览文件 @
9c2f3f30
import
type
{
FunctionalComponent
,
defineComponent
}
from
'vue'
;
import
type
{
ComponentType
}
from
'../../types/componentType'
;
import
{
componentMap
}
from
'/@/components/Table/src/componentMap'
;
import
{
Popover
}
from
'ant-design-vue'
;
import
{
h
}
from
'vue'
;
export
interface
ComponentProps
{
component
:
ComponentType
;
rule
:
boolean
;
popoverVisible
:
boolean
;
ruleMessage
:
string
;
}
export
const
CellComponent
:
FunctionalComponent
=
(
{
component
=
'Input'
,
rule
=
true
,
ruleMessage
,
popoverVisible
}:
ComponentProps
,
{
attrs
}
)
=>
{
const
Comp
=
componentMap
.
get
(
component
)
as
typeof
defineComponent
;
const
DefaultComp
=
h
(
Comp
,
attrs
);
if
(
!
rule
)
{
return
DefaultComp
;
}
return
h
(
Popover
,
{
overlayClassName
:
'edit-cell-rule-popover'
,
visible
:
!!
popoverVisible
},
{
default
:
()
=>
DefaultComp
,
content
:
()
=>
ruleMessage
,
}
);
};
src/components/Table/src/components/editable/EditableCell.vue
0 → 100644
浏览文件 @
9c2f3f30
差异被折叠。
点击展开。
src/components/Table/src/components/editable/helper.ts
0 → 100644
浏览文件 @
9c2f3f30
import
{
ComponentType
}
from
'../../types/componentType'
;
import
{
useI18n
}
from
'/@/hooks/web/useI18n'
;
const
{
t
}
=
useI18n
();
/**
* @description: 生成placeholder
*/
export
function
createPlaceholderMessage
(
component
:
ComponentType
)
{
if
(
component
.
includes
(
'Input'
))
{
return
t
(
'component.form.input'
);
}
if
(
component
.
includes
(
'Picker'
))
{
return
t
(
'component.form.choose'
);
}
if
(
component
.
includes
(
'Select'
)
||
component
.
includes
(
'Checkbox'
)
||
component
.
includes
(
'Radio'
)
||
component
.
includes
(
'Switch'
)
)
{
return
t
(
'component.form.choose'
);
}
return
''
;
}
src/components/Table/src/components/editable/index.ts
0 → 100644
浏览文件 @
9c2f3f30
import
type
{
BasicColumn
}
from
'/@/components/Table/src/types/table'
;
import
{
h
}
from
'vue'
;
import
EditableCell
from
'./EditableCell.vue'
;
interface
Params
{
text
:
string
;
record
:
Recordable
;
index
:
number
;
}
export
function
renderEditCell
(
column
:
BasicColumn
)
{
return
({
text
:
value
,
record
,
index
}:
Params
)
=>
{
record
.
onEdit
=
async
(
edit
:
boolean
,
submit
=
false
)
=>
{
if
(
!
submit
)
{
record
.
editable
=
edit
;
}
if
(
!
edit
&&
submit
)
{
const
res
=
await
record
.
onSubmitEdit
?.();
if
(
res
)
{
record
.
editable
=
false
;
return
true
;
}
return
false
;
}
// cancel
if
(
!
edit
&&
!
submit
)
{
record
.
onCancelEdit
?.();
}
return
true
;
};
return
h
(
EditableCell
,
{
value
,
record
,
column
,
index
,
});
};
}
export
type
EditRecordRow
<
T
=
Hash
<
any
>>
=
{
onEdit
:
(
editable
:
boolean
,
submit
?:
boolean
)
=>
Promise
<
boolean
>
;
editable
:
boolean
;
onCancel
:
Fn
;
onSubmit
:
Fn
;
submitCbs
:
Fn
[];
cancelCbs
:
Fn
[];
validCbs
:
Fn
[];
}
&
T
;
src/components/Table/src/components/renderEditable.tsx
deleted
100644 → 0
浏览文件 @
f3a70eed
import
'../style/editable-cell.less'
;
import
{
defineComponent
,
PropType
,
ref
,
unref
,
nextTick
,
watchEffect
}
from
'vue'
;
import
{
ClickOutSide
}
from
'/@/components/ClickOutSide'
;
import
{
RenderEditableCellParams
}
from
'../types/table'
;
import
{
ComponentType
}
from
'../types/componentType'
;
import
{
componentMap
}
from
'../componentMap'
;
import
{
isString
,
isBoolean
,
isArray
}
from
'/@/utils/is'
;
import
{
FormOutlined
,
CloseOutlined
,
CheckOutlined
}
from
'@ant-design/icons-vue'
;
const
prefixCls
=
'editable-cell'
;
const
EditableCell
=
defineComponent
({
name
:
'EditableCell'
,
props
:
{
value
:
{
type
:
String
as
PropType
<
string
>
,
default
:
''
,
},
componentProps
:
{
type
:
Object
as
PropType
<
any
>
,
default
:
null
,
},
dataKey
:
{
type
:
String
as
PropType
<
string
>
,
default
:
''
,
},
dataIndex
:
{
type
:
String
as
PropType
<
string
>
,
default
:
''
,
},
component
:
{
type
:
String
as
PropType
<
ComponentType
>
,
default
:
'Input'
,
},
editable
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
false
,
},
editRow
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
false
,
},
record
:
{
type
:
Object
as
PropType
<
EditRecordRow
>
,
},
placeholder
:
{
type
:
String
as
PropType
<
string
>
,
default
:
''
,
},
},
emits
:
[
'submit'
,
'cancel'
],
setup
(
props
,
{
attrs
,
emit
})
{
const
elRef
=
ref
<
any
>
(
null
);
const
isEditRef
=
ref
(
false
);
const
currentValueRef
=
ref
<
string
|
boolean
>
(
props
.
value
);
const
defaultValueRef
=
ref
<
string
|
boolean
>
(
props
.
value
);
watchEffect
(()
=>
{
defaultValueRef
.
value
=
props
.
value
;
if
(
isBoolean
(
props
.
editable
))
{
isEditRef
.
value
=
props
.
editable
;
}
});
function
handleChange
(
e
:
any
)
{
if
(
e
&&
e
.
target
&&
Reflect
.
has
(
e
.
target
,
'value'
))
{
currentValueRef
.
value
=
(
e
as
ChangeEvent
).
target
.
value
;
}
if
(
isString
(
e
)
||
isBoolean
(
e
))
{
currentValueRef
.
value
=
e
;
}
}
function
handleEdit
()
{
isEditRef
.
value
=
true
;
nextTick
(()
=>
{
const
el
=
unref
(
elRef
);
el
&&
el
.
focus
();
});
}
function
handleCancel
()
{
isEditRef
.
value
=
false
;
currentValueRef
.
value
=
defaultValueRef
.
value
;
emit
(
'cancel'
);
}
if
(
props
.
record
)
{
/* eslint-disable */
isArray
(
props
.
record
.
submitCbs
)
?
props
.
record
.
submitCbs
.
push
(
handleSubmit
)
:
(
props
.
record
.
submitCbs
=
[
handleSubmit
]);
/* eslint-disable */
isArray
(
props
.
record
.
cancelCbs
)
?
props
.
record
.
cancelCbs
.
push
(
handleCancel
)
:
(
props
.
record
.
cancelCbs
=
[
handleCancel
]);
/* eslint-disable */
props
.
record
.
onCancel
=
()
=>
{
isArray
(
props
.
record
?.
cancelCbs
)
&&
props
.
record
?.
cancelCbs
.
forEach
((
fn
)
=>
fn
());
};
/* eslint-disable */
props
.
record
.
onSubmit
=
()
=>
{
isArray
(
props
.
record
?.
submitCbs
)
&&
props
.
record
?.
submitCbs
.
forEach
((
fn
)
=>
fn
());
};
}
function
handleSubmit
()
{
const
{
dataKey
,
dataIndex
}
=
props
;
if
(
!
dataKey
||
!
dataIndex
)
return
;
if
(
props
.
record
)
{
/* eslint-disable */
props
.
record
[
dataIndex
]
=
unref
(
currentValueRef
)
as
string
;
}
isEditRef
.
value
=
false
;
}
function
onClickOutside
()
{
if
(
props
.
editRow
)
return
;
const
{
component
}
=
props
;
if
(
component
&&
component
.
includes
(
'Input'
))
{
handleCancel
();
}
}
function
renderValue
()
{
const
{
value
}
=
props
;
if
(
props
.
editRow
)
{
return
!
unref
(
isEditRef
)
?
value
:
null
;
}
return
(
!
unref
(
isEditRef
)
&&
(
<
div
class=
{
`${prefixCls}__normal`
}
onClick=
{
handleEdit
}
>
{
value
}
<
FormOutlined
class=
{
`${prefixCls}__normal-icon`
}
/>
</
div
>
)
);
}
return
()
=>
{
const
{
component
,
componentProps
=
{}
}
=
props
;
const
Comp
=
componentMap
.
get
(
component
!
)
as
any
;
return
(
<
div
class=
{
prefixCls
}
>
{
unref
(
isEditRef
)
&&
(
<
ClickOutSide
onClickOutside=
{
onClickOutside
}
>
{
()
=>
(
<
div
class=
{
`${prefixCls}__wrapper`
}
>
<
Comp
placeholder=
{
props
.
placeholder
}
{
...
{
...
attrs
,
...
componentProps
,
}}
style=
{
{
width
:
'calc(100% - 48px)'
}
}
ref=
{
elRef
}
value=
{
unref
(
currentValueRef
)
}
size=
"small"
onChange=
{
handleChange
}
onPressEnter=
{
handleSubmit
}
/>
{
!
props
.
editRow
&&
(
<
div
class=
{
`${prefixCls}__action`
}
>
<
CheckOutlined
class=
{
[
`${prefixCls}__icon`
,
'mx-2'
]
}
onClick=
{
handleSubmit
}
/>
<
CloseOutlined
class=
{
[
`${prefixCls}__icon `
]
}
onClick=
{
handleCancel
}
/>
</
div
>
)
}
</
div
>
)
}
</
ClickOutSide
>
)
}
{
renderValue
()
}
</
div
>
);
};
},
});
export
function
renderEditableCell
({
dataIndex
,
component
,
componentProps
=
{},
placeholder
,
}:
RenderEditableCellParams
)
{
return
({
text
,
record
}:
{
text
:
string
;
record
:
EditRecordRow
})
=>
{
return
(
<
EditableCell
{
...
componentProps
}
placeholder=
{
placeholder
}
value=
{
text
}
record=
{
record
}
dataKey=
{
record
.
key
}
dataIndex=
{
dataIndex
}
component=
{
component
}
/>
);
};
}
export
function
renderEditableRow
({
dataIndex
,
component
,
componentProps
=
{},
placeholder
,
}:
RenderEditableCellParams
)
{
return
({
text
,
record
}:
{
text
:
string
;
record
:
EditRecordRow
})
=>
{
return
(
<
EditableCell
{
...
componentProps
}
value=
{
text
}
placeholder=
{
placeholder
}
editRow=
{
true
}
editable=
{
record
.
editable
}
dataKey=
{
record
.
key
}
record=
{
record
}
dataIndex=
{
dataIndex
}
component=
{
component
}
/>
);
};
}
export
type
EditRecordRow
<
T
=
Hash
<
any
>>
=
{
editable
:
boolean
;
onCancel
:
Fn
;
onSubmit
:
Fn
;
submitCbs
:
Fn
[];
cancelCbs
:
Fn
[];
}
&
T
;
src/components/Table/src/components/renderExpandIcon.tsx
deleted
100644 → 0
浏览文件 @
f3a70eed
import
{
BasicArrow
}
from
'/@/components/Basic'
;
export
default
()
=>
{
return
(
props
:
Recordable
)
=>
{
return
(
<
BasicArrow
onClick=
{
(
e
:
Event
)
=>
{
props
.
onExpand
(
props
.
record
,
e
);
}
}
expand=
{
props
.
expanded
}
/>
);
};
};
src/components/Table/src/components/settings/ColumnSetting.vue
浏览文件 @
9c2f3f30
...
...
@@ -184,7 +184,7 @@
const
ret
:
Options
[]
=
[];
table
.
getColumns
({
ignoreIndex
:
true
,
ignoreAction
:
true
}).
forEach
((
item
)
=>
{
ret
.
push
({
label
:
item
.
title
as
string
,
label
:
(
item
.
title
as
string
)
||
(
item
.
customTitle
as
string
)
,
value
:
(
item
.
dataIndex
||
item
.
title
)
as
string
,
...
item
,
});
...
...
src/components/Table/src/const.ts
浏览文件 @
9c2f3f30
...
...
@@ -32,6 +32,10 @@ export function DEFAULT_SORT_FN(sortInfo: SorterResult) {
};
}
export
function
DEFAULT_FILTER_FN
(
data
:
Partial
<
Recordable
<
string
[]
>>
)
{
return
data
;
}
// 表格单元格默认布局
export
const
DEFAULT_ALIGN
=
'center'
;
...
...
src/components/Table/src/hooks/useColumns.ts
浏览文件 @
9c2f3f30
import
{
BasicColumn
,
BasicTableProps
,
GetColumnsParams
}
from
'../types/table'
;
import
{
PaginationProps
}
from
'../types/pagination'
;
import
type
{
BasicColumn
,
BasicTableProps
,
CellFormat
,
GetColumnsParams
}
from
'../types/table'
;
import
type
{
PaginationProps
}
from
'../types/pagination'
;
import
{
unref
,
ComputedRef
,
Ref
,
computed
,
watchEffect
,
ref
,
toRaw
}
from
'vue'
;
import
{
isBoolean
,
isArray
,
isString
}
from
'/@/utils/is'
;
import
{
isBoolean
,
isArray
,
isString
,
isObject
}
from
'/@/utils/is'
;
import
{
DEFAULT_ALIGN
,
PAGE_SIZE
,
INDEX_COLUMN_FLAG
,
ACTION_COLUMN_FLAG
}
from
'../const'
;
import
{
useI18n
}
from
'/@/hooks/web/useI18n'
;
import
{
isEqual
,
cloneDeep
}
from
'lodash-es'
;
import
{
isFunction
}
from
'/@/utils/is'
;
import
{
formatToDate
}
from
'/@/utils/dateUtil'
;
import
{
renderEditCell
}
from
'../components/editable'
;
const
{
t
}
=
useI18n
();
...
...
@@ -127,8 +130,30 @@ export function useColumns(
return
columns
;
});
const
getSortFixedColumns
=
computed
(()
=>
{
return
useFixedColumn
(
unref
(
getColumnsRef
));
const
getViewColumns
=
computed
(()
=>
{
const
viewColumns
=
sortFixedColumn
(
unref
(
getColumnsRef
));
viewColumns
.
forEach
((
column
)
=>
{
const
{
slots
,
dataIndex
,
customRender
,
format
,
edit
,
editRow
,
flag
}
=
column
;
if
(
!
slots
||
!
slots
?.
title
)
{
column
.
slots
=
{
title
:
`header-
${
dataIndex
}
`
,
...(
slots
||
{})
};
column
.
customTitle
=
column
.
title
;
Reflect
.
deleteProperty
(
column
,
'title'
);
}
const
isDefaultAction
=
[
INDEX_COLUMN_FLAG
,
ACTION_COLUMN_FLAG
].
includes
(
flag
!
);
if
(
!
customRender
&&
format
&&
!
edit
&&
!
isDefaultAction
)
{
column
.
customRender
=
({
text
,
record
,
index
})
=>
{
return
formatCell
(
text
,
format
,
record
,
index
);
};
}
// edit table
if
((
edit
||
editRow
)
&&
!
isDefaultAction
)
{
column
.
customRender
=
renderEditCell
(
column
);
}
});
return
viewColumns
;
});
watchEffect
(()
=>
{
...
...
@@ -191,7 +216,7 @@ export function useColumns(
}
if
(
sort
)
{
columns
=
use
FixedColumn
(
columns
);
columns
=
sort
FixedColumn
(
columns
);
}
return
columns
;
...
...
@@ -200,10 +225,10 @@ export function useColumns(
return
cacheColumns
;
}
return
{
getColumnsRef
,
getCacheColumns
,
getColumns
,
setColumns
,
get
SortFixed
Columns
};
return
{
getColumnsRef
,
getCacheColumns
,
getColumns
,
setColumns
,
get
View
Columns
};
}
export
function
use
FixedColumn
(
columns
:
BasicColumn
[])
{
function
sort
FixedColumn
(
columns
:
BasicColumn
[])
{
const
fixedLeftColumns
:
BasicColumn
[]
=
[];
const
fixedRightColumns
:
BasicColumn
[]
=
[];
const
defColumns
:
BasicColumn
[]
=
[];
...
...
@@ -224,3 +249,35 @@ export function useFixedColumn(columns: BasicColumn[]) {
return
resultColumns
;
}
// format cell
export
function
formatCell
(
text
:
string
,
format
:
CellFormat
,
record
:
Recordable
,
index
:
number
)
{
if
(
!
format
)
{
return
text
;
}
// custom function
if
(
isFunction
(
format
))
{
return
format
(
text
,
record
,
index
);
}
try
{
// date type
const
DATE_FORMAT_PREFIX
=
'date|'
;
if
(
isString
(
format
)
&&
format
.
startsWith
(
DATE_FORMAT_PREFIX
))
{
const
dateFormat
=
format
.
replace
(
DATE_FORMAT_PREFIX
,
''
);
if
(
!
dateFormat
)
{
return
text
;
}
return
formatToDate
(
text
,
dateFormat
);
}
// enum
if
(
isObject
(
format
)
&&
Reflect
.
has
(
format
,
'size'
))
{
return
format
.
get
(
text
);
}
}
catch
(
error
)
{
return
text
;
}
}
src/components/Table/src/hooks/useDataSource.ts
浏览文件 @
9c2f3f30
import
type
{
BasicTableProps
,
FetchParams
}
from
'../types/table'
;
import
type
{
BasicTableProps
,
FetchParams
,
SorterResult
}
from
'../types/table'
;
import
type
{
PaginationProps
}
from
'../types/pagination'
;
import
{
ref
,
unref
,
ComputedRef
,
computed
,
onMounted
,
watchEffect
}
from
'vue'
;
import
{
ref
,
unref
,
ComputedRef
,
computed
,
onMounted
,
watchEffect
,
reactive
}
from
'vue'
;
import
{
useTimeoutFn
}
from
'/@/hooks/core/useTimeout'
;
...
...
@@ -16,12 +16,28 @@ interface ActionType {
setPagination
:
(
info
:
Partial
<
PaginationProps
>
)
=>
void
;
setLoading
:
(
loading
:
boolean
)
=>
void
;
getFieldsValue
:
()
=>
Recordable
;
clearSelectedRowKeys
:
()
=>
void
;
}
interface
SearchState
{
sortInfo
:
Recordable
;
filterInfo
:
Record
<
string
,
string
[]
>
;
}
export
function
useDataSource
(
propsRef
:
ComputedRef
<
BasicTableProps
>
,
{
getPaginationInfo
,
setPagination
,
setLoading
,
getFieldsValue
}:
ActionType
,
{
getPaginationInfo
,
setPagination
,
setLoading
,
getFieldsValue
,
clearSelectedRowKeys
,
}:
ActionType
,
emit
:
EmitType
)
{
const
searchState
=
reactive
<
SearchState
>
({
sortInfo
:
{},
filterInfo
:
{},
});
const
dataSourceRef
=
ref
<
Recordable
[]
>
([]);
watchEffect
(()
=>
{
...
...
@@ -29,6 +45,32 @@ export function useDataSource(
!
api
&&
dataSource
&&
(
dataSourceRef
.
value
=
dataSource
);
});
function
handleTableChange
(
pagination
:
PaginationProps
,
filters
:
Partial
<
Recordable
<
string
[]
>>
,
sorter
:
SorterResult
)
{
const
{
clearSelectOnPageChange
,
sortFn
,
filterFn
}
=
unref
(
propsRef
);
if
(
clearSelectOnPageChange
)
{
clearSelectedRowKeys
();
}
setPagination
(
pagination
);
const
params
:
Recordable
=
{};
if
(
sorter
&&
isFunction
(
sortFn
))
{
const
sortInfo
=
sortFn
(
sorter
);
searchState
.
sortInfo
=
sortInfo
;
params
.
sortInfo
=
sortInfo
;
}
if
(
filters
&&
isFunction
(
filterFn
))
{
const
filterInfo
=
filterFn
(
filters
);
searchState
.
filterInfo
=
filterInfo
;
params
.
filterInfo
=
filterInfo
;
}
fetch
(
params
);
}
function
setTableKey
(
items
:
any
[])
{
if
(
!
items
||
!
Array
.
isArray
(
items
))
return
;
items
.
forEach
((
item
)
=>
{
...
...
@@ -75,6 +117,14 @@ export function useDataSource(
return
unref
(
dataSourceRef
);
});
async
function
updateTableData
(
index
:
number
,
key
:
string
,
value
:
any
)
{
const
record
=
dataSourceRef
.
value
[
index
];
if
(
record
)
{
dataSourceRef
.
value
[
index
][
key
]
=
value
;
}
return
dataSourceRef
.
value
[
index
];
}
async
function
fetch
(
opt
?:
FetchParams
)
{
const
{
api
,
searchInfo
,
fetchSetting
,
beforeFetch
,
afterFetch
,
useSearchForm
}
=
unref
(
propsRef
...
...
@@ -94,6 +144,8 @@ export function useDataSource(
pageParams
[
sizeField
]
=
pageSize
;
}
const
{
sortInfo
=
{},
filterInfo
}
=
searchState
;
let
params
:
Recordable
=
{
...
pageParams
,
...(
useSearchForm
?
getFieldsValue
()
:
{}),
...
...
@@ -101,6 +153,8 @@ export function useDataSource(
...(
opt
?
opt
.
searchInfo
:
{}),
...(
opt
?
opt
.
sortInfo
:
{}),
...(
opt
?
opt
.
filterInfo
:
{}),
...
sortInfo
,
...
filterInfo
,
};
if
(
beforeFetch
&&
isFunction
(
beforeFetch
))
{
params
=
beforeFetch
(
params
)
||
params
;
...
...
@@ -175,5 +229,7 @@ export function useDataSource(
getAutoCreateKey
,
fetch
,
reload
,
updateTableData
,
handleTableChange
,
};
}
src/components/Table/src/hooks/useTable.ts
浏览文件 @
9c2f3f30
import
type
{
BasicTableProps
,
TableActionType
,
FetchParams
,
BasicColumn
}
from
'../types/table'
;
import
type
{
PaginationProps
}
from
'../types/pagination'
;
import
type
{
DynamicProps
}
from
'/@/types/utils'
;
import
{
getDynamicProps
}
from
'/@/utils'
;
import
{
ref
,
onUnmounted
,
unref
}
from
'vue'
;
import
{
isProdMode
}
from
'/@/utils/env'
;
import
{
isInSetup
}
from
'/@/utils/helper/vueHelper'
;
import
{
error
}
from
'/@/utils/log'
;
import
{
watchEffect
}
from
'vue'
;
import
type
{
FormActionType
}
from
'/@/components/Form'
;
type
Props
=
Partial
<
DynamicProps
<
BasicTableProps
>>
;
export
function
useTable
(
tableProps
?:
P
artial
<
BasicTableProps
>
):
[(
instance
:
TableActionType
)
=>
void
,
TableActionType
]
{
tableProps
?:
P
rops
):
[(
instance
:
TableActionType
,
formInstance
:
FormActionType
)
=>
void
,
TableActionType
]
{
isInSetup
();
const
tableRef
=
ref
<
Nullable
<
TableActionType
>>
(
null
);
const
loadedRef
=
ref
<
Nullable
<
boolean
>>
(
false
);
const
formRef
=
ref
<
Nullable
<
FormActionType
>>
(
null
);
function
register
(
instance
:
TableActionType
)
{
function
register
(
instance
:
TableActionType
,
formInstance
:
FormActionType
)
{
isProdMode
()
&&
onUnmounted
(()
=>
{
tableRef
.
value
=
null
;
...
...
@@ -24,20 +32,29 @@ export function useTable(
return
;
}
tableRef
.
value
=
instance
;
tableProps
&&
instance
.
setProps
(
tableProps
);
formRef
.
value
=
formInstance
;
// tableProps && instance.setProps(tableProps);
loadedRef
.
value
=
true
;
watchEffect
(()
=>
{
tableProps
&&
instance
.
setProps
(
getDynamicProps
(
tableProps
));
});
}
function
getTableInstance
():
TableActionType
{
const
table
=
unref
(
tableRef
);
if
(
!
table
)
{
throw
new
Error
(
'table is undefined!'
);
error
(
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!'
);
}
return
table
;
return
table
as
TableActionType
;
}
const
methods
:
TableActionType
=
{
reload
:
(
opt
?:
FetchParams
)
=>
{
const
methods
:
TableActionType
&
{
getForm
:
()
=>
FormActionType
;
}
=
{
reload
:
async
(
opt
?:
FetchParams
)
=>
{
getTableInstance
().
reload
(
opt
);
},
setProps
:
(
props
:
Partial
<
BasicTableProps
>
)
=>
{
...
...
@@ -54,7 +71,6 @@ export function useTable(
},
getColumns
:
({
ignoreIndex
=
false
}:
{
ignoreIndex
?:
boolean
}
=
{})
=>
{
const
columns
=
getTableInstance
().
getColumns
({
ignoreIndex
})
||
[];
return
columns
;
},
setColumns
:
(
columns
:
BasicColumn
[])
=>
{
...
...
@@ -87,7 +103,19 @@ export function useTable(
getSize
:
()
=>
{
return
getTableInstance
().
getSize
();
},
}
as
TableActionType
;
updateTableData
:
(
index
:
number
,
key
:
string
,
value
:
any
)
=>
{
return
getTableInstance
().
updateTableData
(
index
,
key
,
value
);
},
getRowSelection
:
()
=>
{
return
getTableInstance
().
getRowSelection
();
},
getCacheColumns
:
()
=>
{
return
getTableInstance
().
getCacheColumns
();
},
getForm
:
()
=>
{
return
unref
(
formRef
)
as
FormActionType
;
},
};
return
[
register
,
methods
];
}
src/components/Table/src/hooks/useTableScroll.ts
浏览文件 @
9c2f3f30
...
...
@@ -121,7 +121,7 @@ export function useTableScroll(
width
+=
60
;
}
// TODO props
// TODO props
dth ?? 0;
const
NORMAL_WIDTH
=
150
;
const
columns
=
unref
(
columnsRef
);
...
...
@@ -135,7 +135,10 @@ export function useTableScroll(
if
(
len
!==
0
)
{
width
+=
len
*
NORMAL_WIDTH
;
}
return
width
;
const
table
=
unref
(
tableElRef
);
const
tableWidth
=
table
?.
$el
?.
offsetWidth
??
0
;
return
tableWidth
>
width
?
tableWidth
-
24
:
width
;
});
const
getScrollRef
=
computed
(()
=>
{
...
...
src/components/Table/src/props.ts
浏览文件 @
9c2f3f30
...
...
@@ -9,21 +9,29 @@ import type {
TableRowSelection
,
}
from
'./types/table'
;
import
type
{
FormProps
}
from
'/@/components/Form'
;
import
{
DEFAULT_SORT_FN
,
FETCH_SETTING
}
from
'./const'
;
import
{
DEFAULT_
FILTER_FN
,
DEFAULT_
SORT_FN
,
FETCH_SETTING
}
from
'./const'
;
import
{
propTypes
}
from
'/@/utils/propTypes'
;
// 注释看 types/table
export
const
basicProps
=
{
clickToRowSelect
:
propTypes
.
bool
.
def
(
true
),
tableSetting
:
{
type
:
Object
as
PropType
<
TableSetting
>
,
},
inset
:
propTypes
.
bool
,
sortFn
:
{
type
:
Function
as
PropType
<
(
sortInfo
:
SorterResult
)
=>
any
>
,
default
:
DEFAULT_SORT_FN
,
},
filterFn
:
{
type
:
Function
as
PropType
<
(
data
:
Partial
<
Recordable
<
string
[]
>>
)
=>
any
>
,
default
:
DEFAULT_FILTER_FN
,
},
showTableSetting
:
propTypes
.
bool
,
autoCreateKey
:
propTypes
.
bool
.
def
(
true
),
striped
:
propTypes
.
bool
.
def
(
true
),
...
...
src/components/Table/src/style/editable-cell.less
deleted
100644 → 0
浏览文件 @
f3a70eed
@prefix
-cls:
~'editable-cell'
;
.
@{prefix-cls}
{
position:
relative
;
&__wrapper
{
display:
flex
;
align-items:
center
;
}
&__icon
{
&:
hover
{
transform:
scale
(
1.2
);
svg
{
color:
@primary-color
;
}
}
}
&__normal
{
padding-right:
48
px
;
&-icon
{
position:
absolute
;
top:
4
px
;
right:
0
;
display:
none
;
width:
20
px
;
cursor:
pointer
;
}
}
&:
hover
{
.
@{prefix-cls}__normal-icon
{
display:
inline-block
;
}
}
}
src/components/Table/src/style/index.less
浏览文件 @
9c2f3f30
...
...
@@ -133,14 +133,18 @@
overflow-y:
scroll
!important
;
}
.
ant-table-fixed-right
.
ant-table-header
{
border-left:
1
px
solid
@border-color
!important
;
.
ant-table-fixed-right
{
right:
-1
px
;
.
ant-table-fixed
{
border-bottom:
none
;
.
ant-table-header
{
border-left:
1
px
solid
@border-color
!important
;
.
ant-table-fixed
{
border-bottom:
none
;
.
ant-table-thead
th
{
background:
rgb
(
241
,
243
,
244
);
.
ant-table-thead
th
{
background:
rgb
(
241
,
243
,
244
);
}
}
}
}
...
...
src/components/Table/src/types/componentType.ts
浏览文件 @
9c2f3f30
export
type
ComponentType
=
|
'Input'
|
'InputPassword'
|
'InputNumber'
|
'Select'
|
'ApiSelect'
|
'Checkbox'
|
'CheckboxGroup'
|
'Switch'
;
src/components/Table/src/types/table.ts
浏览文件 @
9c2f3f30
...
...
@@ -6,9 +6,10 @@ import type {
TableRowSelection
as
ITableRowSelection
,
}
from
'ant-design-vue/lib/table/interface'
;
import
{
ComponentType
}
from
'./componentType'
;
import
{
VueNode
}
from
'/@/utils/propTypes'
;
// import { ColumnProps } from './column';
export
declare
type
SortOrder
=
'ascend'
|
'descend'
;
export
interface
TableCurrentDataSource
<
T
=
any
>
{
export
interface
TableCurrentDataSource
<
T
=
Recordable
>
{
currentDataSource
:
T
[];
}
...
...
@@ -53,7 +54,7 @@ export interface ColumnFilterItem {
children
?:
any
;
}
export
interface
TableCustomRecord
<
T
=
any
>
{
export
interface
TableCustomRecord
<
T
=
Recordable
>
{
record
?:
T
;
index
?:
number
;
}
...
...
@@ -65,18 +66,11 @@ export interface SorterResult {
columnKey
:
string
;
}
export
interface
RenderEditableCellParams
{
dataIndex
:
string
;
component
?:
ComponentType
;
componentProps
?:
any
;
placeholder
?:
string
;
}
export
interface
FetchParams
{
searchInfo
?:
any
;
searchInfo
?:
Recordable
;
page
?:
number
;
sortInfo
?:
any
;
filterInfo
?:
any
;
sortInfo
?:
Recordable
;
filterInfo
?:
Recordable
;
}
export
interface
GetColumnsParams
{
...
...
@@ -89,7 +83,7 @@ export type SizeType = 'default' | 'middle' | 'small' | 'large';
export
interface
TableActionType
{
reload
:
(
opt
?:
FetchParams
)
=>
Promise
<
void
>
;
getSelectRows
:
<
T
=
any
>
()
=>
T
[];
getSelectRows
:
<
T
=
Recordable
>
()
=>
T
[];
clearSelectedRowKeys
:
()
=>
void
;
getSelectRowKeys
:
()
=>
string
[];
deleteSelectRowByKey
:
(
key
:
string
)
=>
void
;
...
...
@@ -106,6 +100,8 @@ export interface TableActionType {
getSize
:
()
=>
SizeType
;
getRowSelection
:
()
=>
TableRowSelection
<
Recordable
>
;
getCacheColumns
:
()
=>
BasicColumn
[];
emit
?:
EmitType
;
updateTableData
:
(
index
:
number
,
key
:
string
,
value
:
any
)
=>
Recordable
;
}
export
interface
FetchSetting
{
...
...
@@ -131,6 +127,8 @@ export interface BasicTableProps<T = any> {
clickToRowSelect
?:
boolean
;
// 自定义排序方法
sortFn
?:
(
sortInfo
:
SorterResult
)
=>
any
;
// 排序方法
filterFn
?:
(
data
:
Partial
<
Recordable
<
string
[]
>>
)
=>
any
;
// 取消表格的默认padding
inset
?:
boolean
;
// 显示表格设置
...
...
@@ -141,7 +139,7 @@ export interface BasicTableProps<T = any> {
// 是否自动生成key
autoCreateKey
?:
boolean
;
// 计算合计行的方法
summaryFunc
?:
(...
arg
:
any
)
=>
any
[];
summaryFunc
?:
(...
arg
:
any
)
=>
Recordable
[];
// 是否显示合计行
showSummary
?:
boolean
;
// 是否可拖拽列
...
...
@@ -374,13 +372,43 @@ export interface BasicTableProps<T = any> {
onExpandedRowsChange
?:
(
expandedRows
:
string
[]
|
number
[])
=>
void
;
}
export
type
CellFormat
=
|
string
|
((
text
:
string
,
record
:
Recordable
,
index
:
number
)
=>
string
|
number
)
|
Map
<
string
|
number
,
any
>
;
// @ts-ignore
export
interface
BasicColumn
extends
ColumnProps
{
children
?:
BasicColumn
[];
filters
?:
{
text
:
string
;
value
:
string
;
children
?:
|
unknown
[]
|
(((
props
:
Record
<
string
,
unknown
>
)
=>
unknown
[])
&
(()
=>
unknown
[])
&
(()
=>
unknown
[]));
}[];
//
flag
?:
'INDEX'
|
'DEFAULT'
|
'CHECKBOX'
|
'RADIO'
|
'ACTION'
;
customTitle
?:
VueNode
;
slots
?:
Indexable
;
// Whether to hide the column by default, it can be displayed in the column configuration
defaultHidden
?:
boolean
;
// Help text for table column header
helpMessage
?:
string
|
string
[];
format
?:
CellFormat
;
// Editable
edit
?:
boolean
;
editRow
?:
boolean
;
editable
?:
boolean
;
editComponent
?:
ComponentType
;
editComponentProps
?:
Recordable
;
editRule
?:
boolean
|
((
text
:
string
,
record
:
Recordable
)
=>
Promise
<
string
>
);
editValueMap
?:
(
value
:
any
)
=>
string
;
onEditRow
?:
()
=>
void
;
}
src/layouts/default/sider/MixSider.vue
浏览文件 @
9c2f3f30
...
...
@@ -351,6 +351,11 @@
position
:
absolute
;
top
:
10px
;
right
:
30px
;
&--dot
{
top
:
50%
;
margin-top
:
-3px
;
}
}
&
__title
{
...
...
src/router/menus/modules/demo/comp.ts
浏览文件 @
9c2f3f30
...
...
@@ -52,6 +52,9 @@ const menu: MenuModule = {
{
path
:
'table'
,
name
:
t
(
'routes.demo.table.table'
),
tag
:
{
dot
:
true
,
},
children
:
[
{
path
:
'basic'
,
...
...
@@ -108,10 +111,16 @@ const menu: MenuModule = {
{
path
:
'editCellTable'
,
name
:
t
(
'routes.demo.table.editCellTable'
),
tag
:
{
dot
:
true
,
},
},
{
path
:
'editRowTable'
,
name
:
t
(
'routes.demo.table.editRowTable'
),
tag
:
{
dot
:
true
,
},
},
],
},
...
...
src/utils/dateUtil.ts
浏览文件 @
9c2f3f30
...
...
@@ -3,12 +3,15 @@ import moment from 'moment';
const
DATE_TIME_FORMAT
=
'YYYY-MM-DD HH:mm'
;
const
DATE_FORMAT
=
'YYYY-MM-DD '
;
export
function
formatToDateTime
(
date
:
moment
.
MomentInput
=
null
):
string
{
return
moment
(
date
).
format
(
DATE_TIME_FORMAT
);
export
function
formatToDateTime
(
date
:
moment
.
MomentInput
=
null
,
format
=
DATE_TIME_FORMAT
):
string
{
return
moment
(
date
).
format
(
format
);
}
export
function
formatToDate
(
date
:
moment
.
MomentInput
=
null
):
string
{
return
moment
(
date
).
format
(
DATE_FORMAT
);
export
function
formatToDate
(
date
:
moment
.
MomentInput
=
null
,
format
=
DATE_FORMAT
):
string
{
return
moment
(
date
).
format
(
format
);
}
export
const
formatAgo
=
(
str
:
string
|
number
)
=>
{
...
...
src/views/demo/table/EditCellTable.vue
浏览文件 @
9c2f3f30
<
template
>
<div
class=
"p-4"
>
<BasicTable
@
register=
"registerTable"
>
<template
#
customId
>
<EditTableHeaderIcon
title=
"Id"
/>
</
template
>
<
template
#
customName
>
<EditTableHeaderIcon
title=
"姓名"
/>
</
template
>
<BasicTable
@
register=
"registerTable"
@
edit-end=
"handleEditEnd"
@
edit-cancel=
"handleEditCancel"
>
</BasicTable>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'vue'
;
import
{
BasicTable
,
useTable
,
BasicColumn
,
renderEditableCell
,
EditTableHeaderIcon
,
}
from
'/@/components/Table'
;
import
{
BasicTable
,
useTable
,
BasicColumn
,
EditTableHeaderIcon
}
from
'/@/components/Table'
;
import
{
optionsListApi
}
from
'/@/api/demo/select'
;
import
{
demoListApi
}
from
'/@/api/demo/table'
;
const
columns
:
BasicColumn
[]
=
[
{
// title: 'ID',
title
:
'输入框'
,
dataIndex
:
'name'
,
edit
:
true
,
editComponentProps
:
{
prefix
:
'$'
,
},
width
:
200
,
},
{
title
:
'默认输入状态'
,
dataIndex
:
'name7'
,
edit
:
true
,
editable
:
true
,
width
:
200
,
},
{
title
:
'输入框校验'
,
dataIndex
:
'name1'
,
edit
:
true
,
// 默认必填校验
editRule
:
true
,
width
:
200
,
},
{
title
:
'输入框函数校验'
,
dataIndex
:
'name2'
,
edit
:
true
,
editRule
:
async
(
text
)
=>
{
if
(
text
===
'2'
)
{
return
'不能输入该值'
;
}
return
''
;
},
width
:
200
,
},
{
title
:
'数字输入框'
,
dataIndex
:
'id'
,
slots
:
{
title
:
'customId'
},
customRender
:
renderEditableCell
({
dataIndex
:
'id'
}),
edit
:
true
,
editRule
:
true
,
editComponent
:
'InputNumber'
,
width
:
200
,
},
{
// title: '姓名',
dataIndex
:
'name'
,
slots
:
{
title
:
'customName'
},
customRender
:
renderEditableCell
({
dataIndex
:
'name'
,
}),
title
:
'下拉框'
,
dataIndex
:
'name3'
,
edit
:
true
,
editComponent
:
'Select'
,
editComponentProps
:
{
options
:
[
{
label
:
'Option1'
,
value
:
'1'
,
},
{
label
:
'Option2'
,
value
:
'2'
,
},
],
},
width
:
200
,
},
{
title
:
'远程下拉'
,
dataIndex
:
'name4'
,
edit
:
true
,
editComponent
:
'ApiSelect'
,
editComponentProps
:
{
api
:
optionsListApi
,
},
width
:
200
,
},
{
title
:
'地址'
,
dataIndex
:
'address'
,
sorter
:
true
,
title
:
'勾选框'
,
dataIndex
:
'name5'
,
edit
:
true
,
editComponent
:
'Checkbox'
,
editValueMap
:
(
value
)
=>
{
return
value
?
'是'
:
'否'
;
},
width
:
200
,
},
{
title
:
'开关'
,
dataIndex
:
'name6'
,
edit
:
true
,
editComponent
:
'Switch'
,
editValueMap
:
(
value
)
=>
{
return
value
?
'开'
:
'关'
;
},
width
:
200
,
},
];
export
default
defineComponent
({
...
...
@@ -50,10 +113,21 @@
api
:
demoListApi
,
columns
:
columns
,
showIndexColumn
:
false
,
bordered
:
true
,
});
function
handleEditEnd
({
record
,
index
,
key
,
value
}:
Recordable
)
{
console
.
log
(
record
,
index
,
key
,
value
);
}
function
handleEditCancel
()
{
console
.
log
(
'cancel'
);
}
return
{
registerTable
,
handleEditEnd
,
handleEditCancel
,
};
},
});
...
...
src/views/demo/table/EditRowTable.vue
浏览文件 @
9c2f3f30
...
...
@@ -15,24 +15,105 @@
TableAction
,
BasicColumn
,
ActionItem
,
renderEditableRow
,
EditTableHeaderIcon
,
EditRecordRow
,
}
from
'/@/components/Table'
;
import
{
optionsListApi
}
from
'/@/api/demo/select'
;
import
{
demoListApi
}
from
'/@/api/demo/table'
;
const
columns
:
BasicColumn
[]
=
[
{
title
:
'ID'
,
title
:
'输入框'
,
dataIndex
:
'name'
,
editRow
:
true
,
editComponentProps
:
{
prefix
:
'$'
,
},
width
:
200
,
},
{
title
:
'默认输入状态'
,
dataIndex
:
'name7'
,
editRow
:
true
,
width
:
200
,
},
{
title
:
'输入框校验'
,
dataIndex
:
'name1'
,
editRow
:
true
,
// 默认必填校验
editRule
:
true
,
width
:
200
,
},
{
title
:
'输入框函数校验'
,
dataIndex
:
'name2'
,
editRow
:
true
,
editRule
:
async
(
text
)
=>
{
if
(
text
===
'2'
)
{
return
'不能输入该值'
;
}
return
''
;
},
width
:
200
,
},
{
title
:
'数字输入框'
,
dataIndex
:
'id'
,
customRender
:
renderEditableRow
({
dataIndex
:
'id'
}),
editRow
:
true
,
editRule
:
true
,
editComponent
:
'InputNumber'
,
width
:
200
,
},
{
title
:
'姓名'
,
dataIndex
:
'name'
,
customRender
:
renderEditableRow
({
dataIndex
:
'name'
,
}),
title
:
'下拉框'
,
dataIndex
:
'name3'
,
editRow
:
true
,
editComponent
:
'Select'
,
editComponentProps
:
{
options
:
[
{
label
:
'Option1'
,
value
:
'1'
,
},
{
label
:
'Option2'
,
value
:
'2'
,
},
],
},
width
:
200
,
},
{
title
:
'远程下拉'
,
dataIndex
:
'name4'
,
editRow
:
true
,
editComponent
:
'ApiSelect'
,
editComponentProps
:
{
api
:
optionsListApi
,
},
width
:
200
,
},
{
title
:
'勾选框'
,
dataIndex
:
'name5'
,
editRow
:
true
,
editComponent
:
'Checkbox'
,
editValueMap
:
(
value
)
=>
{
return
value
?
'是'
:
'否'
;
},
width
:
200
,
},
{
title
:
'开关'
,
dataIndex
:
'name6'
,
editRow
:
true
,
editComponent
:
'Switch'
,
editValueMap
:
(
value
)
=>
{
return
value
?
'开'
:
'关'
;
},
width
:
200
,
},
];
export
default
defineComponent
({
...
...
@@ -55,19 +136,19 @@
function
handleEdit
(
record
:
EditRecordRow
)
{
currentEditKeyRef
.
value
=
record
.
key
;
record
.
editable
=
true
;
record
.
onEdit
?.(
true
)
;
}
function
handleCancel
(
record
:
EditRecordRow
)
{
currentEditKeyRef
.
value
=
''
;
record
.
editable
=
false
;
record
.
onCancel
&&
record
.
onCancel
();
record
.
onEdit
?.(
false
,
true
);
}
function
handleSave
(
record
:
EditRecordRow
)
{
currentEditKeyRef
.
value
=
''
;
record
.
editable
=
false
;
record
.
onSubmit
&&
record
.
onSubmit
();
async
function
handleSave
(
record
:
EditRecordRow
)
{
const
pass
=
await
record
.
onEdit
?.(
false
,
true
);
if
(
pass
)
{
currentEditKeyRef
.
value
=
''
;
}
}
function
createActions
(
record
:
EditRecordRow
,
column
:
BasicColumn
):
ActionItem
[]
{
...
...
src/views/demo/table/FixedColumn.vue
浏览文件 @
9c2f3f30
...
...
@@ -41,7 +41,6 @@
{
title
:
'地址'
,
dataIndex
:
'address'
,
width
:
260
,
},
{
title
:
'编号'
,
...
...
@@ -67,6 +66,7 @@
api
:
demoListApi
,
columns
:
columns
,
rowSelection
:
{
type
:
'radio'
},
bordered
:
true
,
actionColumn
:
{
width
:
160
,
title
:
'Action'
,
...
...
src/views/demo/table/tableData.tsx
浏览文件 @
9c2f3f30
...
...
@@ -7,12 +7,16 @@ export function getBasicColumns(): BasicColumn[] {
title
:
'ID'
,
dataIndex
:
'id'
,
fixed
:
'left'
,
width
:
4
00
,
width
:
2
00
,
},
{
title
:
'姓名'
,
dataIndex
:
'name'
,
width
:
150
,
filters
:
[
{
text
:
'Male'
,
value
:
'male'
},
{
text
:
'Female'
,
value
:
'female'
},
],
},
{
title
:
'地址'
,
...
...
@@ -22,11 +26,13 @@ export function getBasicColumns(): BasicColumn[] {
title
:
'编号'
,
dataIndex
:
'no'
,
width
:
150
,
sorter
:
true
,
defaultHidden
:
true
,
},
{
title
:
'开始时间'
,
width
:
120
,
sorter
:
true
,
dataIndex
:
'beginTime'
,
},
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论