Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
剑九 六千里
vue-vben-admin
提交
ebf7c8aa
V
vue-vben-admin
项目概览
剑九 六千里
/
vue-vben-admin
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vue-vben-admin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ebf7c8aa
编写于
12月 28, 2020
作者:
V
vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
perf(modal-drawer): replace the scrollbar assembly
上级
73cee06d
变更
41
隐藏空白更改
内联
并排
Showing
41 changed file
with
1100 addition
and
874 deletion
+1100
-874
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+5
-0
src/components/Container/src/LazyContainer.vue
src/components/Container/src/LazyContainer.vue
+9
-2
src/components/Container/src/collapse/CollapseContainer.vue
src/components/Container/src/collapse/CollapseContainer.vue
+12
-8
src/components/Container/src/collapse/CollapseHeader.vue
src/components/Container/src/collapse/CollapseHeader.vue
+5
-2
src/components/Description/src/index.tsx
src/components/Description/src/index.tsx
+1
-1
src/components/Description/src/props.ts
src/components/Description/src/props.ts
+1
-1
src/components/Description/src/types.ts
src/components/Description/src/types.ts
+5
-2
src/components/Description/src/useDescription.ts
src/components/Description/src/useDescription.ts
+1
-1
src/components/Drawer/index.ts
src/components/Drawer/index.ts
+1
-1
src/components/Drawer/src/BasicDrawer.tsx
src/components/Drawer/src/BasicDrawer.tsx
+0
-246
src/components/Drawer/src/BasicDrawer.vue
src/components/Drawer/src/BasicDrawer.vue
+259
-0
src/components/Drawer/src/components/DrawerFooter.vue
src/components/Drawer/src/components/DrawerFooter.vue
+85
-0
src/components/Drawer/src/components/DrawerHeader.vue
src/components/Drawer/src/components/DrawerHeader.vue
+73
-0
src/components/Drawer/src/index.less
src/components/Drawer/src/index.less
+0
-66
src/components/Drawer/src/props.ts
src/components/Drawer/src/props.ts
+3
-2
src/components/Drawer/src/types.ts
src/components/Drawer/src/types.ts
+4
-1
src/components/Drawer/src/useDrawer.ts
src/components/Drawer/src/useDrawer.ts
+39
-17
src/components/Form/src/components/FormAction.vue
src/components/Form/src/components/FormAction.vue
+1
-6
src/components/Modal/index.ts
src/components/Modal/index.ts
+3
-3
src/components/Modal/src/BasicModal.tsx
src/components/Modal/src/BasicModal.tsx
+0
-232
src/components/Modal/src/BasicModal.vue
src/components/Modal/src/BasicModal.vue
+184
-0
src/components/Modal/src/ModalWrapper.tsx
src/components/Modal/src/ModalWrapper.tsx
+0
-161
src/components/Modal/src/components/Modal.tsx
src/components/Modal/src/components/Modal.tsx
+8
-6
src/components/Modal/src/components/ModalClose.vue
src/components/Modal/src/components/ModalClose.vue
+98
-0
src/components/Modal/src/components/ModalFooter.vue
src/components/Modal/src/components/ModalFooter.vue
+39
-0
src/components/Modal/src/components/ModalHeader.vue
src/components/Modal/src/components/ModalHeader.vue
+22
-0
src/components/Modal/src/components/ModalWrapper.vue
src/components/Modal/src/components/ModalWrapper.vue
+152
-0
src/components/Modal/src/hooks/useModal.ts
src/components/Modal/src/hooks/useModal.ts
+26
-19
src/components/Modal/src/hooks/useModalContext.ts
src/components/Modal/src/hooks/useModalContext.ts
+0
-0
src/components/Modal/src/hooks/useModalDrag.ts
src/components/Modal/src/hooks/useModalDrag.ts
+0
-0
src/components/Modal/src/hooks/useModalFullScreen.ts
src/components/Modal/src/hooks/useModalFullScreen.ts
+0
-0
src/components/Modal/src/index.less
src/components/Modal/src/index.less
+5
-44
src/components/Modal/src/props.ts
src/components/Modal/src/props.ts
+21
-40
src/components/Modal/src/types.ts
src/components/Modal/src/types.ts
+6
-1
src/hooks/core/useAttrs.ts
src/hooks/core/useAttrs.ts
+2
-2
src/settings/projectSetting.ts
src/settings/projectSetting.ts
+1
-1
src/utils/propTypes.ts
src/utils/propTypes.ts
+1
-1
src/views/demo/comp/drawer/Drawer3.vue
src/views/demo/comp/drawer/Drawer3.vue
+22
-2
src/views/demo/comp/drawer/Drawer5.vue
src/views/demo/comp/drawer/Drawer5.vue
+1
-1
src/views/demo/comp/drawer/index.vue
src/views/demo/comp/drawer/index.vue
+4
-4
src/views/demo/feat/tabs/index.vue
src/views/demo/feat/tabs/index.vue
+1
-1
未找到文件。
CHANGELOG.zh_CN.md
浏览文件 @
ebf7c8aa
...
...
@@ -12,6 +12,10 @@
-
form: 新增远程下拉
`ApiSelect`
及示例
-
form: 新增
`autoFocusFirstItem`
配置。用于配置是否聚焦表单第一个输入框
### ⚡ Performance Improvements
-
优化
`modal`
与
`drawer`
滚动条组件
### 🐛 Bug Fixes
-
修复混合模式下滚动条丢失问题
...
...
@@ -21,6 +25,7 @@
-
修复路由类型错误
-
修复菜单分割时权限失效问题
-
关闭多标签页时 iframe 提前加载
-
修复
`modal`
与
`drawer`
已知问题
## 2.0.0-rc.14 (2020-12-15)
...
...
src/components/Container/src/LazyContainer.vue
浏览文件 @
ebf7c8aa
<
template
>
<transition-group
class=
"lazy-container
"
:class=
"prefixCls
"
v-bind=
"$attrs"
ref=
"elRef"
:name=
"transitionName"
...
...
@@ -25,6 +25,7 @@
import
{
useTimeoutFn
}
from
'
/@/hooks/core/useTimeout
'
;
import
{
useIntersectionObserver
}
from
'
/@/hooks/event/useIntersectionObserver
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
interface
State
{
isInit
:
boolean
;
...
...
@@ -70,6 +71,8 @@
intersectionObserverInstance
:
null
,
});
const
{
prefixCls
}
=
useDesign
(
'
lazy-container
'
);
onMounted
(()
=>
{
immediateInit
();
initIntersectionObserver
();
...
...
@@ -129,13 +132,17 @@
}
return
{
elRef
,
prefixCls
,
...
toRefs
(
state
),
};
},
});
</
script
>
<
style
lang=
"less"
>
.lazy-container {
@import (reference) '../../../design/index.less';
@prefix-cls: ~'@{namespace}-lazy-container';
.@{prefix-cls} {
width: 100%;
height: 100%;
}
...
...
src/components/Container/src/collapse/CollapseContainer.vue
浏览文件 @
ebf7c8aa
<
template
>
<div
class=
"collapse-container p-2
"
>
<CollapseHeader
v-bind=
"$props"
:show=
"show"
@
expand=
"handleExpand"
>
<div
:class=
"['p-2', prefixCls]
"
>
<CollapseHeader
v-bind=
"$props"
:
prefixCls=
"prefixCls"
:
show=
"show"
@
expand=
"handleExpand"
>
<template
#title
>
<slot
name=
"title"
/>
</
template
>
...
...
@@ -8,7 +8,7 @@
<CollapseTransition
:enable=
"canExpan"
>
<Skeleton
v-if=
"loading"
/>
<div
class=
"collapse-container__body
"
v-else
v-show=
"show"
>
<div
:class=
"`${prefixCls}__body`
"
v-else
v-show=
"show"
>
<LazyContainer
:timeout=
"lazyTime"
v-if=
"lazy"
>
<slot
/>
<
template
#skeleton
>
...
...
@@ -35,6 +35,7 @@
// hook
import
{
useTimeoutFn
}
from
'
/@/hooks/core/useTimeout
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
export
default
defineComponent
({
name
:
'
CollapseContainer
'
,
...
...
@@ -64,6 +65,9 @@
},
setup
(
props
)
{
const
show
=
ref
(
true
);
const
{
prefixCls
}
=
useDesign
(
'
collapse-container
'
);
/**
* @description: Handling development events
*/
...
...
@@ -77,20 +81,20 @@
return
{
show
,
handleExpand
,
prefixCls
,
};
},
});
</
script
>
<
style
lang=
"less"
>
.collapse-container {
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-collapse-container';
.@{prefix-cls} {
background: #fff;
border-radius: 2px;
transition: all 0.3s ease-in-out;
&.no-shadow {
box-shadow: none;
}
&__header {
display: flex;
height: 32px;
...
...
src/components/Container/src/collapse/CollapseHeader.vue
浏览文件 @
ebf7c8aa
<
template
>
<div
class=
"collapse-container__header
"
>
<div
:class=
"`$
{prefixCls}__header`
">
<BasicTitle
:helpMessage=
"$attrs.helpMessage"
>
<template
v-if=
"$attrs.title"
>
{{
$attrs
.
title
}}
...
...
@@ -9,7 +9,7 @@
</
template
>
</BasicTitle>
<div
class=
"collapse-container__action
"
>
<div
:class=
"`${prefixCls}__action`
"
>
<slot
name=
"action"
/>
<BasicArrow
v-if=
"$attrs.canExpan"
top
:expand=
"$attrs.show"
@
click=
"$emit('expand')"
/>
</div>
...
...
@@ -21,5 +21,8 @@
export
default
defineComponent
({
inheritAttrs
:
false
,
components
:
{
BasicArrow
,
BasicTitle
},
props
:
{
prefixCls
:
String
,
},
});
</
script
>
src/components/Description/src/index.tsx
浏览文件 @
ebf7c8aa
...
...
@@ -24,7 +24,7 @@ export default defineComponent({
const
getMergeProps
=
computed
(()
=>
{
return
{
...
props
,
...(
unref
(
propsRef
)
as
any
),
...(
unref
(
propsRef
)
as
Recordable
),
}
as
DescOptions
;
});
...
...
src/components/Description/src/props.ts
浏览文件 @
ebf7c8aa
...
...
@@ -13,7 +13,7 @@ export default {
bordered
:
propTypes
.
bool
.
def
(
true
),
column
:
{
type
:
[
Number
,
Object
]
as
PropType
<
number
|
any
>
,
type
:
[
Number
,
Object
]
as
PropType
<
number
|
Recordable
>
,
default
:
()
=>
{
return
{
xxl
:
4
,
xl
:
3
,
lg
:
3
,
md
:
3
,
sm
:
2
,
xs
:
1
};
},
...
...
src/components/Description/src/types.ts
浏览文件 @
ebf7c8aa
...
...
@@ -15,7 +15,10 @@ export interface DescItem {
span
?:
number
;
show
?:
(...
arg
:
any
)
=>
boolean
;
// render
render
?:
(
val
:
string
,
data
:
any
)
=>
VNode
|
undefined
|
JSX
.
Element
|
Element
|
string
|
number
;
render
?:
(
val
:
string
,
data
:
Recordable
)
=>
VNode
|
undefined
|
JSX
.
Element
|
Element
|
string
|
number
;
}
export
interface
DescOptions
extends
DescriptionsProps
{
...
...
@@ -30,7 +33,7 @@ export interface DescOptions extends DescriptionsProps {
* 数据
* @type object
*/
data
:
any
;
data
:
Recordable
;
/**
* Built-in CollapseContainer component configuration
* @type CollapseContainerOptions
...
...
src/components/Description/src/useDescription.ts
浏览文件 @
ebf7c8aa
...
...
@@ -19,7 +19,7 @@ export function useDescription(props?: Partial<DescOptions>): UseDescReturnType
const
methods
:
DescInstance
=
{
setDescProps
:
(
descProps
:
Partial
<
DescOptions
>
):
void
=>
{
unref
(
descRef
)
!
.
setDescProps
(
descProps
);
unref
(
descRef
)
?
.
setDescProps
(
descProps
);
},
};
...
...
src/components/Drawer/index.ts
浏览文件 @
ebf7c8aa
import
{
withInstall
}
from
'
../util
'
;
import
BasicDrawer
from
'
./src/BasicDrawer
'
;
import
BasicDrawer
from
'
./src/BasicDrawer
.vue
'
;
export
{
BasicDrawer
};
export
*
from
'
./src/types
'
;
...
...
src/components/Drawer/src/BasicDrawer.tsx
已删除
100644 → 0
浏览文件 @
73cee06d
import
'
./index.less
'
;
import
type
{
DrawerInstance
,
DrawerProps
}
from
'
./types
'
;
import
type
{
CSSProperties
}
from
'
vue
'
;
import
{
defineComponent
,
ref
,
computed
,
watchEffect
,
watch
,
unref
,
nextTick
,
toRaw
}
from
'
vue
'
;
import
{
Drawer
,
Row
,
Col
,
Button
}
from
'
ant-design-vue
'
;
import
{
BasicTitle
}
from
'
/@/components/Basic
'
;
import
{
Loading
}
from
'
/@/components/Loading
'
;
import
{
LeftOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
getSlot
}
from
'
/@/utils/helper/tsxHelper
'
;
import
{
isFunction
,
isNumber
}
from
'
/@/utils/is
'
;
import
{
deepMerge
}
from
'
/@/utils
'
;
import
{
tryTsxEmit
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
basicProps
}
from
'
./props
'
;
const
prefixCls
=
'
basic-drawer
'
;
export
default
defineComponent
({
inheritAttrs
:
false
,
props
:
basicProps
,
emits
:
[
'
visible-change
'
,
'
ok
'
,
'
close
'
,
'
register
'
],
setup
(
props
,
{
slots
,
emit
,
attrs
})
{
const
scrollRef
=
ref
<
ElRef
>
(
null
);
const
visibleRef
=
ref
(
false
);
const
propsRef
=
ref
<
Partial
<
Nullable
<
DrawerProps
>>>
(
null
);
const
{
t
}
=
useI18n
();
const
getMergeProps
=
computed
(
():
DrawerProps
=>
{
return
deepMerge
(
toRaw
(
props
),
unref
(
propsRef
));
}
);
const
getProps
=
computed
(
():
DrawerProps
=>
{
const
opt
=
{
placement
:
'
right
'
,
...
attrs
,
...
unref
(
getMergeProps
),
visible
:
unref
(
visibleRef
),
};
opt
.
title
=
undefined
;
const
{
isDetail
,
width
,
wrapClassName
,
getContainer
}
=
opt
;
if
(
isDetail
)
{
if
(
!
width
)
{
opt
.
width
=
'
100%
'
;
}
const
detailCls
=
`
${
prefixCls
}
__detail`
;
opt
.
wrapClassName
=
wrapClassName
?
`
${
wrapClassName
}
${
detailCls
}
`
:
detailCls
;
if
(
!
getContainer
)
{
// TODO type error?
opt
.
getContainer
=
'
.layout-content
'
as
any
;
}
}
return
opt
as
DrawerProps
;
}
);
const
getBindValues
=
computed
(
():
DrawerProps
=>
{
return
{
...
attrs
,
...
unref
(
getProps
),
};
}
);
// Custom implementation of the bottom button,
const
getFooterHeight
=
computed
(()
=>
{
const
{
footerHeight
,
showFooter
}
=
unref
(
getProps
);
if
(
showFooter
&&
footerHeight
)
{
return
isNumber
(
footerHeight
)
?
`
${
footerHeight
}
px`
:
`
${
footerHeight
.
replace
(
'
px
'
,
''
)}
px`
;
}
return
`0px`
;
});
const
getScrollContentStyle
=
computed
(
():
CSSProperties
=>
{
const
footerHeight
=
unref
(
getFooterHeight
);
return
{
position
:
'
relative
'
,
height
:
`calc(100% -
${
footerHeight
}
)`
,
overflow
:
'
auto
'
,
padding
:
'
16px
'
,
paddingBottom
:
'
30px
'
,
};
}
);
const
getLoading
=
computed
(()
=>
{
return
!!
unref
(
getProps
)?.
loading
;
});
watchEffect
(()
=>
{
visibleRef
.
value
=
props
.
visible
;
});
watch
(
()
=>
visibleRef
.
value
,
(
visible
)
=>
{
nextTick
(()
=>
{
emit
(
'
visible-change
'
,
visible
);
});
},
{
immediate
:
false
,
}
);
// Cancel event
async
function
onClose
(
e
:
ChangeEvent
)
{
const
{
closeFunc
}
=
unref
(
getProps
);
emit
(
'
close
'
,
e
);
if
(
closeFunc
&&
isFunction
(
closeFunc
))
{
const
res
=
await
closeFunc
();
visibleRef
.
value
=
!
res
;
return
;
}
visibleRef
.
value
=
false
;
}
function
setDrawerProps
(
props
:
Partial
<
DrawerProps
>
):
void
{
// Keep the last setDrawerProps
propsRef
.
value
=
deepMerge
(
unref
(
propsRef
)
||
{},
props
);
if
(
Reflect
.
has
(
props
,
'
visible
'
))
{
visibleRef
.
value
=
!!
props
.
visible
;
}
}
function
renderFooter
()
{
if
(
slots
?.
footer
)
{
return
getSlot
(
slots
,
'
footer
'
);
}
const
{
showCancelBtn
,
cancelButtonProps
,
cancelText
,
showOkBtn
,
okType
,
okText
,
okButtonProps
,
confirmLoading
,
showFooter
,
}
=
unref
(
getProps
);
if
(
!
showFooter
)
{
return
null
;
}
return
(
<
div
class
=
{
`
${
prefixCls
}
__footer`
}
>
{
getSlot
(
slots
,
'
insertFooter
'
)
}
{
showCancelBtn
&&
(
<
Button
{
...
cancelButtonProps
}
onClick
=
{
onClose
}
class
=
"mr-2"
>
{
()
=>
cancelText
}
</
Button
>
)
}
{
getSlot
(
slots
,
'
centerFooter
'
)
}
{
showOkBtn
&&
(
<
Button
type
=
{
okType
}
onClick
=
{
()
=>
{
emit
(
'
ok
'
);
}
}
{
...
okButtonProps
}
loading
=
{
confirmLoading
}
>
{
()
=>
okText
}
</
Button
>
)
}
{
getSlot
(
slots
,
'
appendFooter
'
)
}
</
div
>
);
}
function
renderHeader
()
{
if
(
slots
?.
title
)
{
return
getSlot
(
slots
,
'
title
'
);
}
const
{
title
}
=
unref
(
getMergeProps
);
if
(
!
props
.
isDetail
)
{
return
<
BasicTitle
>
{
()
=>
title
||
getSlot
(
slots
,
'
title
'
)
}
</
BasicTitle
>;
}
return
(
<
Row
type
=
"flex"
align
=
"middle"
class
=
{
`
${
prefixCls
}
__detail-header`
}
>
{
()
=>
(
<>
{
props
.
showDetailBack
&&
(
<
Button
size
=
"small"
type
=
"link"
onClick
=
{
onClose
}
>
{
()
=>
<
LeftOutlined
/>
}
</
Button
>
)
}
{
title
&&
(
<
Col
style
=
"flex:1"
class
=
{
[
`
${
prefixCls
}
__detail-title`
,
'
ellipsis
'
,
'
px-2
'
]
}
>
{
()
=>
title
}
</
Col
>
)
}
{
getSlot
(
slots
,
'
titleToolbar
'
)
}
</>
)
}
</
Row
>
);
}
const
drawerInstance
:
DrawerInstance
=
{
setDrawerProps
:
setDrawerProps
,
};
tryTsxEmit
((
instance
)
=>
{
emit
(
'
register
'
,
drawerInstance
,
instance
.
uid
);
});
return
()
=>
{
return
(
<
Drawer
class
=
{
prefixCls
}
onClose
=
{
onClose
}
{
...
unref
(
getBindValues
)
}
>
{
{
title
:
()
=>
renderHeader
(),
default
:
()
=>
(
<>
<
div
ref
=
{
scrollRef
}
style
=
{
unref
(
getScrollContentStyle
)
}
>
<
Loading
absolute
tip
=
{
t
(
'
component.drawer.loadingText
'
)
}
loading
=
{
unref
(
getLoading
)
}
/>
{
getSlot
(
slots
)
}
</
div
>
{
renderFooter
()
}
</>
),
}
}
</
Drawer
>
);
};
},
});
src/components/Drawer/src/BasicDrawer.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<Drawer
:class=
"prefixCls"
@
close=
"onClose"
v-bind=
"getBindValues"
>
<template
#title
v-if=
"!$slots.title"
>
<DrawerHeader
:title=
"getMergeProps.title"
:isDetail=
"isDetail"
:showDetailBack=
"showDetailBack"
@
close=
"onClose"
>
<template
#titleToolbar
>
<slot
name=
"titleToolbar"
/>
</
template
>
</DrawerHeader>
</template>
<ScrollContainer
:style=
"getScrollContentStyle"
v-loading=
"getLoading"
:loading-tip=
"loadingText || t('component.drawer.loadingText')"
>
<slot
/>
</ScrollContainer>
<DrawerFooter
v-bind=
"getProps"
@
close=
"onClose"
@
ok=
"handleOk"
:height=
"getFooterHeight"
>
<
template
#[item]=
"data"
v-for=
"item in Object.keys($slots)"
>
<slot
:name=
"item"
v-bind=
"data"
/>
</
template
>
</DrawerFooter>
</Drawer>
</template>
<
script
lang=
"ts"
>
import
type
{
DrawerInstance
,
DrawerProps
}
from
'
./types
'
;
import
type
{
CSSProperties
}
from
'
vue
'
;
import
{
defineComponent
,
ref
,
computed
,
watchEffect
,
watch
,
unref
,
nextTick
,
toRaw
,
getCurrentInstance
,
}
from
'
vue
'
;
import
{
Drawer
}
from
'
ant-design-vue
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
isFunction
,
isNumber
}
from
'
/@/utils/is
'
;
import
{
deepMerge
}
from
'
/@/utils
'
;
import
DrawerFooter
from
'
./components/DrawerFooter.vue
'
;
import
DrawerHeader
from
'
./components/DrawerHeader.vue
'
;
import
{
ScrollContainer
}
from
'
/@/components/Container
'
;
import
{
basicProps
}
from
'
./props
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
useAttrs
}
from
'
/@/hooks/core/useAttrs
'
;
export
default
defineComponent
({
inheritAttrs
:
false
,
components
:
{
Drawer
,
ScrollContainer
,
DrawerFooter
,
DrawerHeader
},
props
:
basicProps
,
emits
:
[
'
visible-change
'
,
'
ok
'
,
'
close
'
,
'
register
'
],
setup
(
props
,
{
emit
})
{
const
visibleRef
=
ref
(
false
);
const
attrs
=
useAttrs
();
const
propsRef
=
ref
<
Partial
<
Nullable
<
DrawerProps
>>>
(
null
);
const
{
t
}
=
useI18n
();
const
{
prefixVar
,
prefixCls
}
=
useDesign
(
'
basic-drawer
'
);
const
drawerInstance
:
DrawerInstance
=
{
setDrawerProps
:
setDrawerProps
,
emitVisible
:
undefined
,
};
const
instance
=
getCurrentInstance
();
instance
&&
emit
(
'
register
'
,
drawerInstance
,
instance
.
uid
);
const
getMergeProps
=
computed
(
():
DrawerProps
=>
{
return
deepMerge
(
toRaw
(
props
),
unref
(
propsRef
));
}
);
const
getProps
=
computed
(
():
DrawerProps
=>
{
const
opt
=
{
placement
:
'
right
'
,
...
unref
(
attrs
),
...
unref
(
getMergeProps
),
visible
:
unref
(
visibleRef
),
};
opt
.
title
=
undefined
;
const
{
isDetail
,
width
,
wrapClassName
,
getContainer
}
=
opt
;
if
(
isDetail
)
{
if
(
!
width
)
{
opt
.
width
=
'
100%
'
;
}
const
detailCls
=
`
${
prefixCls
}
__detail`
;
opt
.
wrapClassName
=
wrapClassName
?
`
${
wrapClassName
}
${
detailCls
}
`
:
detailCls
;
if
(
!
getContainer
)
{
// TODO type error?
opt
.
getContainer
=
`.
${
prefixVar
}
-layout-content`
as
any
;
}
}
return
opt
as
DrawerProps
;
}
);
const
getBindValues
=
computed
(
():
DrawerProps
=>
{
return
{
...
attrs
,
...
unref
(
getProps
),
};
}
);
// Custom implementation of the bottom button,
const
getFooterHeight
=
computed
(()
=>
{
const
{
footerHeight
,
showFooter
}
=
unref
(
getProps
);
if
(
showFooter
&&
footerHeight
)
{
return
isNumber
(
footerHeight
)
?
`
${
footerHeight
}
px`
:
`
${
footerHeight
.
replace
(
'
px
'
,
''
)}
px`
;
}
return
`0px`
;
});
const
getScrollContentStyle
=
computed
(
():
CSSProperties
=>
{
const
footerHeight
=
unref
(
getFooterHeight
);
return
{
position
:
'
relative
'
,
height
:
`calc(100% -
${
footerHeight
}
)`
,
};
}
);
const
getLoading
=
computed
(()
=>
{
return
!!
unref
(
getProps
)?.
loading
;
});
watchEffect
(()
=>
{
visibleRef
.
value
=
props
.
visible
;
});
watch
(
()
=>
visibleRef
.
value
,
(
visible
)
=>
{
nextTick
(()
=>
{
emit
(
'
visible-change
'
,
visible
);
instance
&&
drawerInstance
.
emitVisible
?.(
visible
,
instance
.
uid
);
});
}
);
// Cancel event
async
function
onClose
(
e
:
Recordable
)
{
const
{
closeFunc
}
=
unref
(
getProps
);
emit
(
'
close
'
,
e
);
if
(
closeFunc
&&
isFunction
(
closeFunc
))
{
const
res
=
await
closeFunc
();
visibleRef
.
value
=
!
res
;
return
;
}
visibleRef
.
value
=
false
;
}
function
setDrawerProps
(
props
:
Partial
<
DrawerProps
>
):
void
{
// Keep the last setDrawerProps
propsRef
.
value
=
deepMerge
(
unref
(
propsRef
)
||
{},
props
);
if
(
Reflect
.
has
(
props
,
'
visible
'
))
{
visibleRef
.
value
=
!!
props
.
visible
;
}
}
function
handleOk
()
{
emit
(
'
ok
'
);
}
return
{
onClose
,
t
,
prefixCls
,
getMergeProps
,
getScrollContentStyle
,
getProps
,
getLoading
,
getBindValues
,
getFooterHeight
,
handleOk
,
};
},
});
</
script
>
<
style
lang=
"less"
>
@import (reference) '../../../design/index.less';
@header-height: 60px;
@detail-header-height: 40px;
@prefix-cls: ~'@{namespace}-basic-drawer';
@prefix-cls-detail: ~'@{namespace}-basic-drawer__detail';
.@{prefix-cls} {
.ant-drawer-wrapper-body {
overflow: hidden;
}
.ant-drawer-close {
&:hover {
color: @error-color;
}
}
.ant-drawer-body {
height: calc(100% - @header-height);
padding: 0;
background-color: @background-color-dark;
.scrollbar__wrap {
padding: 16px !important;
margin-bottom: 0 !important;
}
}
}
.@{prefix-cls-detail} {
position: absolute;
.ant-drawer-header {
width: 100%;
height: @detail-header-height;
padding: 0;
border-top: 1px solid @border-color-base;
box-sizing: border-box;
}
.ant-drawer-title {
height: 100%;
}
.ant-drawer-close {
height: @detail-header-height;
line-height: @detail-header-height;
}
.scrollbar__wrap {
padding: 0 !important;
}
.ant-drawer-body {
height: calc(100% - @detail-header-height);
}
}
</
style
>
src/components/Drawer/src/components/DrawerFooter.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<div
:class=
"prefixCls"
:style=
"getStyle"
v-if=
"showFooter || $slots.footer"
>
<template
v-if=
"!$slots.footer"
>
<slot
name=
"insertFooter"
/>
<a-button
v-bind=
"cancelButtonProps"
@
click=
"handleClose"
class=
"mr-2"
v-if=
"showCancelBtn"
>
{{
cancelText
}}
</a-button>
<slot
name=
"centerFooter"
/>
<a-button
:type=
"okType"
@
click=
"handleOk"
v-bind=
"okButtonProps"
class=
"mr-2"
:loading=
"confirmLoading"
v-if=
"showOkBtn"
>
{{
okText
}}
</a-button>
<slot
name=
"appendFooter"
/>
</
template
>
<
template
v-else
>
<slot
name=
"footer"
/>
</
template
>
</div>
</template>
<
script
lang=
"ts"
>
import
type
{
CSSProperties
}
from
'
vue
'
;
import
{
defineComponent
,
computed
}
from
'
vue
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
footerProps
}
from
'
../props
'
;
export
default
defineComponent
({
name
:
'
BasicDrawerFooter
'
,
props
:
{
...
footerProps
,
height
:
{
type
:
String
,
default
:
'
60px
'
,
},
},
emits
:
[
'
ok
'
,
'
close
'
],
setup
(
props
,
{
emit
})
{
const
{
prefixCls
}
=
useDesign
(
'
basic-drawer-footer
'
);
const
getStyle
=
computed
(
():
CSSProperties
=>
{
const
heightStr
=
`
${
props
.
height
}
`
;
return
{
height
:
heightStr
,
lineHeight
:
heightStr
,
};
}
);
function
handleOk
()
{
emit
(
'
ok
'
);
}
function
handleClose
()
{
emit
(
'
close
'
);
}
return
{
handleOk
,
prefixCls
,
handleClose
,
getStyle
};
},
});
</
script
>
<
style
lang=
"less"
>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-basic-drawer-footer';
@footer-height: 60px;
.@{prefix-cls} {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 12px 0 20px;
text-align: right;
background: #fff;
border-top: 1px solid @border-color-base;
> * {
margin-right: 8px;
}
}
</
style
>
src/components/Drawer/src/components/DrawerHeader.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<BasicTitle
v-if=
"!isDetail"
:class=
"prefixCls"
>
<slot
name=
"title"
/>
{{
!
$slots
.
title
?
title
:
''
}}
</BasicTitle>
<div
:class=
"[prefixCls, `$
{prefixCls}--detail`]" v-else>
<span
:class=
"`$
{prefixCls}__twrap`">
<span
@
click=
"handleClose"
v-if=
"showDetailBack"
>
<ArrowLeftOutlined
:class=
"`$
{prefixCls}__back`" />
</span>
<span
v-if=
"title"
>
{{
title
}}
</span>
</span>
<span
:class=
"`$
{prefixCls}__toolbar`">
<slot
name=
"titleToolbar"
/>
</span>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
BasicTitle
}
from
'
/@/components/Basic
'
;
import
{
ArrowLeftOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
name
:
'
BasicDrawerHeader
'
,
components
:
{
BasicTitle
,
ArrowLeftOutlined
},
props
:
{
isDetail
:
propTypes
.
bool
,
showDetailBack
:
propTypes
.
bool
,
title
:
propTypes
.
string
,
},
setup
(
_
,
{
emit
})
{
const
{
prefixCls
}
=
useDesign
(
'
basic-drawer-header
'
);
function
handleClose
()
{
emit
(
'
close
'
);
}
return
{
prefixCls
,
handleClose
};
},
});
</
script
>
<
style
lang=
"less"
>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-basic-drawer-header';
@footer-height: 60px;
.@{prefix-cls} {
display: flex;
height: 100%;
align-items: center;
&__back {
padding: 0 12px;
cursor: pointer;
&:hover {
color: @primary-color;
}
}
&__twrap {
flex: 1;
}
&__toolbar {
padding-right: 50px;
}
}
</
style
>
src/components/Drawer/src/index.less
已删除
100644 → 0
浏览文件 @
73cee06d
@import (reference) '../../../design/index.less';
@header-height: 40px;
@footer-height: 60px;
.basic-drawer {
.ant-drawer-wrapper-body {
overflow: hidden;
}
.ant-drawer-close {
&:hover {
color: @error-color;
}
}
.ant-drawer-body {
height: calc(100% - @header-height);
padding: 0;
background-color: @background-color-dark;
.scrollbar__wrap {
padding: 16px;
}
}
&__detail {
position: absolute;
&-header {
height: 100%;
}
.ant-drawer-header {
width: 100%;
height: @header-height;
padding: 0;
border-top: 1px solid @border-color-base;
box-sizing: border-box;
}
.ant-drawer-title {
height: 100%;
}
.ant-drawer-close {
height: @header-height;
line-height: @header-height;
}
.scrollbar__wrap {
padding: 0;
}
}
&__footer {
position: absolute;
bottom: 0;
width: 100%;
height: @footer-height;
padding: 0 26px;
line-height: @footer-height;
text-align: right;
background: #fff;
border-top: 1px solid @border-color-base;
}
}
src/components/Drawer/src/props.ts
浏览文件 @
ebf7c8aa
...
...
@@ -10,13 +10,13 @@ export const footerProps = {
* @description: Show close button
*/
showCancelBtn
:
propTypes
.
bool
.
def
(
true
),
cancelButtonProps
:
Object
as
PropType
<
any
>
,
cancelButtonProps
:
Object
as
PropType
<
Recordable
>
,
cancelText
:
propTypes
.
string
.
def
(
t
(
'
component.drawer.cancelText
'
)),
/**
* @description: Show confirmation button
*/
showOkBtn
:
propTypes
.
bool
.
def
(
true
),
okButtonProps
:
propTypes
.
any
,
okButtonProps
:
Object
as
PropType
<
Recordable
>
,
okText
:
propTypes
.
string
.
def
(
t
(
'
component.drawer.okText
'
)),
okType
:
propTypes
.
string
.
def
(
'
primary
'
),
showFooter
:
propTypes
.
bool
,
...
...
@@ -28,6 +28,7 @@ export const footerProps = {
export
const
basicProps
=
{
isDetail
:
propTypes
.
bool
,
title
:
propTypes
.
string
.
def
(
''
),
loadingText
:
propTypes
.
string
,
showDetailBack
:
propTypes
.
bool
.
def
(
true
),
visible
:
propTypes
.
bool
,
loading
:
propTypes
.
bool
,
...
...
src/components/Drawer/src/types.ts
浏览文件 @
ebf7c8aa
import
type
{
ButtonProps
}
from
'
ant-design-vue/lib/button/buttonTypes
'
;
import
type
{
CSSProperties
,
VNodeChild
}
from
'
vue
'
;
import
type
{
CSSProperties
,
VNodeChild
,
ComputedRef
}
from
'
vue
'
;
import
type
{
ScrollContainerOptions
}
from
'
/@/components/Container/index
'
;
export
interface
DrawerInstance
{
setDrawerProps
:
(
props
:
Partial
<
DrawerProps
>
|
boolean
)
=>
void
;
emitVisible
?:
(
visible
:
boolean
,
uid
:
number
)
=>
void
;
}
export
interface
ReturnMethods
extends
DrawerInstance
{
openDrawer
:
<
T
=
any
>
(
visible
?:
boolean
,
data
?:
T
,
openOnSet
?:
boolean
)
=>
void
;
getVisible
?:
ComputedRef
<
boolean
>
;
}
export
type
RegisterFn
=
(
drawerInstance
:
DrawerInstance
,
uuid
?:
string
)
=>
void
;
...
...
@@ -16,6 +18,7 @@ export interface ReturnInnerMethods extends DrawerInstance {
closeDrawer
:
()
=>
void
;
changeLoading
:
(
loading
:
boolean
)
=>
void
;
changeOkLoading
:
(
loading
:
boolean
)
=>
void
;
getVisible
?:
ComputedRef
<
boolean
>
;
}
export
type
UseDrawerReturnType
=
[
RegisterFn
,
ReturnMethods
];
...
...
src/components/Drawer/src/useDrawer.ts
浏览文件 @
ebf7c8aa
...
...
@@ -6,22 +6,32 @@ import type {
UseDrawerInnerReturnType
,
}
from
'
./types
'
;
import
{
ref
,
getCurrentInstance
,
unref
,
reactive
,
watchEffect
,
nextTick
,
toRaw
}
from
'
vue
'
;
import
{
ref
,
getCurrentInstance
,
unref
,
reactive
,
watchEffect
,
nextTick
,
toRaw
,
computed
,
}
from
'
vue
'
;
import
{
isProdMode
}
from
'
/@/utils/env
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
tryOnUnmounted
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
tryOnUnmounted
,
isInSetup
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
isEqual
}
from
'
lodash-es
'
;
import
{
error
}
from
'
/@/utils/log
'
;
const
dataTransferRef
=
reactive
<
any
>
({});
const
visibleData
=
reactive
<
{
[
key
:
number
]:
boolean
}
>
({});
/**
* @description: Applicable to separate drawer and call outside
*/
export
function
useDrawer
():
UseDrawerReturnType
{
if
(
!
getCurrentInstance
())
{
throw
new
Error
(
'
Please put useDrawer function in the setup function!
'
);
}
isInSetup
();
const
drawerRef
=
ref
<
DrawerInstance
|
null
>
(
null
);
const
loadedRef
=
ref
<
Nullable
<
boolean
>>
(
false
);
...
...
@@ -41,23 +51,31 @@ export function useDrawer(): UseDrawerReturnType {
uidRef
.
value
=
uuid
;
drawerRef
.
value
=
drawerInstance
;
loadedRef
.
value
=
true
;
drawerInstance
.
emitVisible
=
(
visible
:
boolean
,
uid
:
number
)
=>
{
visibleData
[
uid
]
=
visible
;
};
}
const
getInstance
=
()
=>
{
const
instance
=
unref
(
drawerRef
);
if
(
!
instance
)
{
throw
new
Error
(
'
instance is undefined!
'
);
error
(
'
useDrawer
instance is undefined!
'
);
}
return
instance
;
};
const
methods
:
ReturnMethods
=
{
setDrawerProps
:
(
props
:
Partial
<
DrawerProps
>
):
void
=>
{
getInstance
().
setDrawerProps
(
props
);
getInstance
()
?
.
setDrawerProps
(
props
);
},
getVisible
:
computed
(():
boolean
=>
{
return
visibleData
[
~~
unref
(
uidRef
)];
}),
openDrawer
:
<
T
=
any
>
(
visible
=
true
,
data
?:
T
,
openOnSet
=
true
):
void
=>
{
getInstance
().
setDrawerProps
({
getInstance
()
?
.
setDrawerProps
({
visible
:
visible
,
});
if
(
!
data
)
return
;
...
...
@@ -79,17 +97,18 @@ export function useDrawer(): UseDrawerReturnType {
export
const
useDrawerInner
=
(
callbackFn
?:
Fn
):
UseDrawerInnerReturnType
=>
{
const
drawerInstanceRef
=
ref
<
Nullable
<
DrawerInstance
>>
(
null
);
const
currentInsta
ll
=
getCurrentInstance
();
const
currentInsta
nce
=
getCurrentInstance
();
const
uidRef
=
ref
<
string
>
(
''
);
if
(
!
currentInsta
ll
)
{
throw
new
E
rror
(
'
useDrawerInner instance is undefined!
'
);
if
(
!
currentInsta
nce
)
{
e
rror
(
'
useDrawerInner instance is undefined!
'
);
}
const
getInstance
=
()
=>
{
const
instance
=
unref
(
drawerInstanceRef
);
if
(
!
instance
)
{
throw
new
Error
(
'
useDrawerInner instance is undefined!
'
);
error
(
'
useDrawerInner instance is undefined!
'
);
return
;
}
return
instance
;
};
...
...
@@ -102,7 +121,7 @@ export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
uidRef
.
value
=
uuid
;
drawerInstanceRef
.
value
=
modalInstance
;
currentInsta
ll
.
emit
(
'
register
'
,
modalInstance
,
uuid
);
currentInsta
nce
?
.
emit
(
'
register
'
,
modalInstance
,
uuid
);
};
watchEffect
(()
=>
{
...
...
@@ -118,19 +137,22 @@ export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
register
,
{
changeLoading
:
(
loading
=
true
)
=>
{
getInstance
().
setDrawerProps
({
loading
});
getInstance
()
?
.
setDrawerProps
({
loading
});
},
changeOkLoading
:
(
loading
=
true
)
=>
{
getInstance
().
setDrawerProps
({
confirmLoading
:
loading
});
getInstance
()
?
.
setDrawerProps
({
confirmLoading
:
loading
});
},
getVisible
:
computed
(():
boolean
=>
{
return
visibleData
[
~~
unref
(
uidRef
)];
}),
closeDrawer
:
()
=>
{
getInstance
().
setDrawerProps
({
visible
:
false
});
getInstance
()
?
.
setDrawerProps
({
visible
:
false
});
},
setDrawerProps
:
(
props
:
Partial
<
DrawerProps
>
)
=>
{
getInstance
().
setDrawerProps
(
props
);
getInstance
()
?
.
setDrawerProps
(
props
);
},
},
];
...
...
src/components/Form/src/components/FormAction.vue
浏览文件 @
ebf7c8aa
<
template
>
<a-col
v-bind=
"actionColOpt"
class=
"mb-2"
:style=
"
{ textAlign: 'right' }"
v-if="showActionButtonGroup"
>
<a-col
v-bind=
"actionColOpt"
:style=
"
{ textAlign: 'right' }" v-if="showActionButtonGroup">
<FormItem>
<slot
name=
"resetBefore"
/>
<Button
...
...
src/components/Modal/index.ts
浏览文件 @
ebf7c8aa
import
'
./src/index.less
'
;
import
{
withInstall
}
from
'
../util
'
;
import
BasicModal
from
'
./src/BasicModal
'
;
import
BasicModal
from
'
./src/BasicModal
.vue
'
;
withInstall
(
BasicModal
);
export
{
BasicModal
};
export
{
useModalContext
}
from
'
./src/useModalContext
'
;
export
{
useModal
,
useModalInner
}
from
'
./src/useModal
'
;
export
{
useModalContext
}
from
'
./src/
hooks/
useModalContext
'
;
export
{
useModal
,
useModalInner
}
from
'
./src/
hooks/
useModal
'
;
export
*
from
'
./src/types
'
;
src/components/Modal/src/BasicModal.tsx
已删除
100644 → 0
浏览文件 @
73cee06d
import
type
{
ModalProps
,
ModalMethods
}
from
'
./types
'
;
import
{
defineComponent
,
computed
,
ref
,
watch
,
unref
,
watchEffect
,
toRef
}
from
'
vue
'
;
import
Modal
from
'
./Modal
'
;
import
{
Button
}
from
'
/@/components/Button
'
;
import
ModalWrapper
from
'
./ModalWrapper
'
;
import
{
BasicTitle
}
from
'
/@/components/Basic
'
;
import
{
FullscreenExitOutlined
,
FullscreenOutlined
,
CloseOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
getSlot
,
extendSlots
}
from
'
/@/utils/helper/tsxHelper
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
deepMerge
}
from
'
/@/utils
'
;
import
{
tryTsxEmit
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
basicProps
}
from
'
./props
'
;
import
{
useFullScreen
}
from
'
./useFullScreen
'
;
export
default
defineComponent
({
name
:
'
BasicModal
'
,
props
:
basicProps
,
emits
:
[
'
visible-change
'
,
'
height-change
'
,
'
cancel
'
,
'
ok
'
,
'
register
'
],
setup
(
props
,
{
slots
,
emit
,
attrs
})
{
const
visibleRef
=
ref
(
false
);
const
propsRef
=
ref
<
Partial
<
ModalProps
>
|
null
>
(
null
);
const
modalWrapperRef
=
ref
<
ComponentRef
>
(
null
);
// modal Bottom and top height
const
extHeightRef
=
ref
(
0
);
// Unexpanded height of the popup
// Custom title component: get title
const
getMergeProps
=
computed
(
():
ModalProps
=>
{
return
{
...
props
,
...(
unref
(
propsRef
)
as
any
),
};
}
);
const
{
handleFullScreen
,
getWrapClassName
,
fullScreenRef
}
=
useFullScreen
({
modalWrapperRef
,
extHeightRef
,
wrapClassName
:
toRef
(
getMergeProps
.
value
,
'
wrapClassName
'
),
});
// modal component does not need title
const
getProps
=
computed
(
():
ModalProps
=>
{
const
opt
=
{
...
unref
(
getMergeProps
),
visible
:
unref
(
visibleRef
),
title
:
undefined
,
};
return
{
...
opt
,
wrapClassName
:
unref
(
getWrapClassName
),
};
}
);
const
getModalBindValue
=
computed
(():
any
=>
{
return
{
...
attrs
,
...
unref
(
getProps
)
};
});
watchEffect
(()
=>
{
visibleRef
.
value
=
!!
props
.
visible
;
});
watch
(
()
=>
unref
(
visibleRef
),
(
v
)
=>
{
emit
(
'
visible-change
'
,
v
);
},
{
immediate
:
false
,
}
);
/**
* @description: 渲染标题
*/
function
renderTitle
()
{
const
{
helpMessage
}
=
unref
(
getProps
);
const
{
title
}
=
unref
(
getMergeProps
);
return
(
<
BasicTitle
helpMessage
=
{
helpMessage
}
>
{
()
=>
(
slots
.
title
?
getSlot
(
slots
,
'
title
'
)
:
title
)
}
</
BasicTitle
>
);
}
// 取消事件
async
function
handleCancel
(
e
:
Event
)
{
e
?.
stopPropagation
();
if
(
props
.
closeFunc
&&
isFunction
(
props
.
closeFunc
))
{
const
isClose
:
boolean
=
await
props
.
closeFunc
();
visibleRef
.
value
=
!
isClose
;
return
;
}
visibleRef
.
value
=
false
;
emit
(
'
cancel
'
);
}
/**
* @description: 设置modal参数
*/
function
setModalProps
(
props
:
Partial
<
ModalProps
>
):
void
{
// Keep the last setModalProps
propsRef
.
value
=
deepMerge
(
unref
(
propsRef
)
||
{},
props
);
if
(
!
Reflect
.
has
(
props
,
'
visible
'
))
return
;
visibleRef
.
value
=
!!
props
.
visible
;
}
function
renderContent
()
{
type
OmitWrapperType
=
Omit
<
ModalProps
,
'
fullScreen
'
|
'
modalFooterHeight
'
|
'
visible
'
|
'
loading
'
>
;
const
{
useWrapper
,
loading
,
wrapperProps
}
=
unref
(
getProps
);
if
(
!
useWrapper
)
return
getSlot
(
slots
);
const
showFooter
=
props
.
footer
!==
undefined
&&
!
props
.
footer
?
0
:
undefined
;
return
(
<
ModalWrapper
footerOffset
=
{
props
.
wrapperFooterOffset
}
fullScreen
=
{
unref
(
fullScreenRef
)
}
ref
=
{
modalWrapperRef
}
loading
=
{
loading
}
visible
=
{
unref
(
visibleRef
)
}
modalFooterHeight
=
{
showFooter
}
{
...((
wrapperProps
as
unknown
)
as
OmitWrapperType
)
}
onGetExtHeight
=
{
(
height
:
number
)
=>
{
extHeightRef
.
value
=
height
;
}
}
onHeightChange
=
{
(
height
:
string
)
=>
{
emit
(
'
height-change
'
,
height
);
}
}
>
{
()
=>
getSlot
(
slots
)
}
</
ModalWrapper
>
);
}
// 底部按钮自定义实现,
function
renderFooter
()
{
const
{
showCancelBtn
,
cancelButtonProps
,
cancelText
,
showOkBtn
,
okType
,
okText
,
okButtonProps
,
confirmLoading
,
}
=
unref
(
getProps
);
return
(
<>
{
getSlot
(
slots
,
'
insertFooter
'
)
}
{
showCancelBtn
&&
(
<
Button
{
...
cancelButtonProps
}
onClick
=
{
handleCancel
}
>
{
()
=>
cancelText
}
</
Button
>
)
}
{
getSlot
(
slots
,
'
centerdFooter
'
)
}
{
showOkBtn
&&
(
<
Button
type
=
{
okType
as
any
}
loading
=
{
confirmLoading
}
onClick
=
{
()
=>
{
emit
(
'
ok
'
);
}
}
{
...
okButtonProps
}
>
{
()
=>
okText
}
</
Button
>
)
}
{
getSlot
(
slots
,
'
appendFooter
'
)
}
</>
);
}
/**
* @description: 关闭按钮
*/
function
renderClose
()
{
const
{
canFullscreen
}
=
unref
(
getProps
);
const
fullScreen
=
unref
(
fullScreenRef
)
?
(
<
FullscreenExitOutlined
role
=
"full"
onClick
=
{
handleFullScreen
}
/>
)
:
(
<
FullscreenOutlined
role
=
"close"
onClick
=
{
handleFullScreen
}
/>
);
const
cls
=
[
'
custom-close-icon
'
,
{
'
can-full
'
:
canFullscreen
,
},
];
return
(
<
div
class
=
{
cls
}
>
{
canFullscreen
&&
fullScreen
}
<
CloseOutlined
onClick
=
{
handleCancel
}
/>
</
div
>
);
}
const
modalMethods
:
ModalMethods
=
{
setModalProps
,
};
tryTsxEmit
((
instance
)
=>
{
emit
(
'
register
'
,
modalMethods
,
instance
.
uid
);
});
return
()
=>
(
<
Modal
onCancel
=
{
handleCancel
}
{
...
unref
(
getModalBindValue
)
}
>
{
{
footer
:
()
=>
renderFooter
(),
closeIcon
:
()
=>
renderClose
(),
title
:
()
=>
renderTitle
(),
...
extendSlots
(
slots
,
[
'
default
'
]),
default
:
()
=>
renderContent
(),
}
}
</
Modal
>
);
},
});
src/components/Modal/src/BasicModal.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<Modal
@
cancel=
"handleCancel"
v-bind=
"getBindValue"
>
<template
#closeIcon
v-if=
"!$slots.closeIcon"
>
<ModalClose
:canFullscreen=
"getProps.canFullscreen"
:fullScreen=
"fullScreenRef"
@
cancel=
"handleCancel"
@
fullscreen=
"handleFullScreen"
/>
</
template
>
<
template
#title
v-if=
"!$slots.title"
>
<ModalHeader
:helpMessage=
"getProps.helpMessage"
:title=
"getMergeProps.title"
/>
</
template
>
<
template
#footer
v-if=
"!$slots.footer"
>
<ModalFooter
v-bind=
"getProps"
@
ok=
"handleOk"
@
cancel=
"handleCancel"
/>
</
template
>
<ModalWrapper
:useWrapper=
"getProps.useWrapper"
:footerOffset=
"wrapperFooterOffset"
:fullScreen=
"fullScreenRef"
ref=
"modalWrapperRef"
:loading=
"getProps.loading"
:visible=
"visibleRef"
:modalFooterHeight=
"footer !== undefined && !footer ? 0 : undefined"
v-bind=
"omit(getProps.wrapperProps, 'visible')"
@
ext-height=
"handleExtHeight"
@
height-change=
"handleHeightChange"
>
<slot
/>
</ModalWrapper>
</Modal>
</template>
<
script
lang=
"ts"
>
import
type
{
ModalProps
,
ModalMethods
}
from
'
./types
'
;
import
{
defineComponent
,
computed
,
ref
,
watch
,
unref
,
watchEffect
,
toRef
,
getCurrentInstance
,
}
from
'
vue
'
;
import
Modal
from
'
./components/Modal
'
;
import
ModalWrapper
from
'
./components/ModalWrapper.vue
'
;
import
ModalClose
from
'
./components/ModalClose.vue
'
;
import
ModalFooter
from
'
./components/ModalFooter.vue
'
;
import
ModalHeader
from
'
./components/ModalHeader.vue
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
deepMerge
}
from
'
/@/utils
'
;
import
{
basicProps
}
from
'
./props
'
;
import
{
useFullScreen
}
from
'
./hooks/useModalFullScreen
'
;
import
{
omit
}
from
'
lodash-es
'
;
export
default
defineComponent
({
name
:
'
BasicModal
'
,
components
:
{
Modal
,
ModalWrapper
,
ModalClose
,
ModalFooter
,
ModalHeader
},
props
:
basicProps
,
emits
:
[
'
visible-change
'
,
'
height-change
'
,
'
cancel
'
,
'
ok
'
,
'
register
'
],
setup
(
props
,
{
emit
,
attrs
})
{
const
visibleRef
=
ref
(
false
);
const
propsRef
=
ref
<
Partial
<
ModalProps
>
|
null
>
(
null
);
const
modalWrapperRef
=
ref
<
ComponentRef
>
(
null
);
// modal Bottom and top height
const
extHeightRef
=
ref
(
0
);
const
modalMethods
:
ModalMethods
=
{
setModalProps
,
emitVisible
:
undefined
,
};
const
instance
=
getCurrentInstance
();
if
(
instance
)
{
emit
(
'
register
'
,
modalMethods
,
instance
.
uid
);
}
// Custom title component: get title
const
getMergeProps
=
computed
(
():
ModalProps
=>
{
return
{
...
props
,
...(
unref
(
propsRef
)
as
any
),
};
}
);
const
{
handleFullScreen
,
getWrapClassName
,
fullScreenRef
}
=
useFullScreen
({
modalWrapperRef
,
extHeightRef
,
wrapClassName
:
toRef
(
getMergeProps
.
value
,
'
wrapClassName
'
),
});
// modal component does not need title
const
getProps
=
computed
(
():
ModalProps
=>
{
const
opt
=
{
...
unref
(
getMergeProps
),
visible
:
unref
(
visibleRef
),
title
:
undefined
,
};
return
{
...
opt
,
wrapClassName
:
unref
(
getWrapClassName
),
};
}
);
const
getBindValue
=
computed
(():
any
=>
{
return
{
...
attrs
,
...
unref
(
getProps
)
};
});
watchEffect
(()
=>
{
visibleRef
.
value
=
!!
props
.
visible
;
});
watch
(
()
=>
unref
(
visibleRef
),
(
v
)
=>
{
emit
(
'
visible-change
'
,
v
);
instance
&&
modalMethods
.
emitVisible
?.(
v
,
instance
.
uid
);
},
{
immediate
:
false
,
}
);
// 取消事件
async
function
handleCancel
(
e
:
Event
)
{
e
?.
stopPropagation
();
if
(
props
.
closeFunc
&&
isFunction
(
props
.
closeFunc
))
{
const
isClose
:
boolean
=
await
props
.
closeFunc
();
visibleRef
.
value
=
!
isClose
;
return
;
}
visibleRef
.
value
=
false
;
emit
(
'
cancel
'
);
}
/**
* @description: 设置modal参数
*/
function
setModalProps
(
props
:
Partial
<
ModalProps
>
):
void
{
// Keep the last setModalProps
propsRef
.
value
=
deepMerge
(
unref
(
propsRef
)
||
{},
props
);
if
(
!
Reflect
.
has
(
props
,
'
visible
'
))
return
;
visibleRef
.
value
=
!!
props
.
visible
;
}
function
handleOk
()
{
emit
(
'
ok
'
);
}
function
handleHeightChange
(
height
:
string
)
{
emit
(
'
height-change
'
,
height
);
}
function
handleExtHeight
(
height
:
number
)
{
extHeightRef
.
value
=
height
;
}
return
{
handleCancel
,
getBindValue
,
getProps
,
handleFullScreen
,
fullScreenRef
,
getMergeProps
,
handleOk
,
visibleRef
,
omit
,
modalWrapperRef
,
handleExtHeight
,
handleHeightChange
,
};
},
});
</
script
>
src/components/Modal/src/ModalWrapper.tsx
已删除
100644 → 0
浏览文件 @
73cee06d
import
type
{
ModalWrapperProps
}
from
'
./types
'
;
import
type
{
CSSProperties
}
from
'
vue
'
;
import
{
defineComponent
,
computed
,
ref
,
watchEffect
,
unref
,
watch
,
onMounted
,
nextTick
,
onUnmounted
,
}
from
'
vue
'
;
import
{
Spin
}
from
'
ant-design-vue
'
;
import
{
useWindowSizeFn
}
from
'
/@/hooks/event/useWindowSizeFn
'
;
import
{
getSlot
}
from
'
/@/utils/helper/tsxHelper
'
;
import
{
useElResize
}
from
'
/@/hooks/event/useElResize
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
createModalContext
}
from
'
./useModalContext
'
;
export
default
defineComponent
({
name
:
'
ModalWrapper
'
,
props
:
{
loading
:
propTypes
.
bool
,
modalHeaderHeight
:
propTypes
.
number
.
def
(
50
),
modalFooterHeight
:
propTypes
.
number
.
def
(
54
),
minHeight
:
propTypes
.
number
.
def
(
200
),
footerOffset
:
propTypes
.
number
.
def
(
0
),
visible
:
propTypes
.
bool
,
fullScreen
:
propTypes
.
bool
,
},
emits
:
[
'
heightChange
'
,
'
getExtHeight
'
],
setup
(
props
:
ModalWrapperProps
,
{
slots
,
emit
})
{
const
wrapperRef
=
ref
<
ElRef
>
(
null
);
const
spinRef
=
ref
<
ComponentRef
>
(
null
);
const
realHeightRef
=
ref
(
0
);
let
stopElResizeFn
:
Fn
=
()
=>
{};
useWindowSizeFn
(
setModalHeight
);
createModalContext
({
redoModalHeight
:
setModalHeight
,
});
const
wrapStyle
=
computed
(
():
CSSProperties
=>
{
return
{
minHeight
:
`
${
props
.
minHeight
}
px`
,
height
:
`
${
unref
(
realHeightRef
)}
px`
,
overflow
:
'
auto
'
,
};
}
);
watchEffect
(()
=>
{
setModalHeight
();
});
watch
(
()
=>
props
.
fullScreen
,
(
v
)
=>
{
!
v
&&
setModalHeight
();
}
);
onMounted
(()
=>
{
const
{
modalHeaderHeight
,
modalFooterHeight
}
=
props
;
emit
(
'
getExtHeight
'
,
modalHeaderHeight
+
modalFooterHeight
);
listenElResize
();
});
onUnmounted
(()
=>
{
stopElResizeFn
&&
stopElResizeFn
();
});
async
function
setModalHeight
()
{
// 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
// 加上这个,就必须在使用的时候传递父级的visible
if
(
!
props
.
visible
)
return
;
const
wrapperRefDom
=
unref
(
wrapperRef
);
if
(
!
wrapperRefDom
)
return
;
const
bodyDom
=
wrapperRefDom
.
parentElement
;
if
(
!
bodyDom
)
return
;
bodyDom
.
style
.
padding
=
'
0
'
;
await
nextTick
();
try
{
const
modalDom
=
bodyDom
.
parentElement
&&
bodyDom
.
parentElement
.
parentElement
;
if
(
!
modalDom
)
return
;
const
modalRect
=
getComputedStyle
(
modalDom
).
top
;
const
modalTop
=
Number
.
parseInt
(
modalRect
);
let
maxHeight
=
window
.
innerHeight
-
modalTop
*
2
+
(
props
.
footerOffset
!
||
0
)
-
props
.
modalFooterHeight
-
props
.
modalHeaderHeight
;
// 距离顶部过进会出现滚动条
if
(
modalTop
<
40
)
{
maxHeight
-=
26
;
}
await
nextTick
();
const
spinEl
=
unref
(
spinRef
);
if
(
!
spinEl
)
return
;
const
spinContainerEl
=
spinEl
.
$el
.
querySelector
(
'
.ant-spin-container
'
)
as
HTMLElement
;
if
(
!
spinContainerEl
)
return
;
const
realHeight
=
spinContainerEl
.
scrollHeight
;
if
(
props
.
fullScreen
)
{
realHeightRef
.
value
=
window
.
innerHeight
-
props
.
modalFooterHeight
-
props
.
modalHeaderHeight
;
}
else
{
realHeightRef
.
value
=
realHeight
>
maxHeight
?
maxHeight
:
realHeight
+
16
+
30
;
}
emit
(
'
heightChange
'
,
unref
(
realHeightRef
));
nextTick
(()
=>
{
const
el
=
spinEl
.
$el
;
if
(
el
)
{
el
.
style
.
height
=
`
${
unref
(
realHeightRef
)}
px`
;
}
});
}
catch
(
error
)
{
console
.
log
(
error
);
}
}
function
listenElResize
()
{
const
wrapper
=
unref
(
wrapperRef
);
if
(
!
wrapper
)
return
;
const
container
=
wrapper
.
querySelector
(
'
.ant-spin-container
'
);
if
(
!
container
)
return
;
const
[
start
,
stop
]
=
useElResize
(
container
,
()
=>
{
setModalHeight
();
});
stopElResizeFn
=
stop
;
start
();
}
return
()
=>
{
return
(
<
div
ref
=
{
wrapperRef
}
style
=
{
unref
(
wrapStyle
)
}
>
<
Spin
ref
=
{
spinRef
}
spinning
=
{
props
.
loading
}
>
{
()
=>
getSlot
(
slots
)
}
</
Spin
>
</
div
>
);
};
},
});
src/components/Modal/src/Modal.tsx
→
src/components/Modal/src/
components/
Modal.tsx
浏览文件 @
ebf7c8aa
import
{
Modal
}
from
'
ant-design-vue
'
;
import
{
defineComponent
,
toRefs
}
from
'
vue
'
;
import
{
basicProps
}
from
'
./props
'
;
import
{
useModalDragMove
}
from
'
./useModalDrag
'
;
import
{
defineComponent
,
toRefs
,
unref
}
from
'
vue
'
;
import
{
basicProps
}
from
'
../props
'
;
import
{
useModalDragMove
}
from
'
../hooks/useModalDrag
'
;
import
{
useAttrs
}
from
'
/@/hooks/core/useAttrs
'
;
import
{
extendSlots
}
from
'
/@/utils/helper/tsxHelper
'
;
export
default
defineComponent
({
name
:
'
Modal
'
,
inheritAttrs
:
false
,
props
:
basicProps
,
setup
(
props
,
{
attrs
,
slots
})
{
setup
(
props
,
{
slots
})
{
const
{
visible
,
draggable
,
destroyOnClose
}
=
toRefs
(
props
);
const
attrs
=
useAttrs
();
useModalDragMove
({
visible
,
destroyOnClose
,
...
...
@@ -18,7 +19,8 @@ export default defineComponent({
});
return
()
=>
{
const
propsData
=
{
...
attrs
,
...
props
}
as
any
;
const
propsData
=
{
...
unref
(
attrs
),
...
props
}
as
Recordable
;
return
<
Modal
{
...
propsData
}
>
{
extendSlots
(
slots
)
}
</
Modal
>;
};
},
...
...
src/components/Modal/src/components/ModalClose.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<div
:class=
"getClass"
>
<template
v-if=
"canFullscreen"
>
<FullscreenExitOutlined
role=
"full"
@
click=
"handleFullScreen"
v-if=
"fullScreen"
/>
<FullscreenOutlined
role=
"close"
@
click=
"handleFullScreen"
v-else
/>
</
template
>
<CloseOutlined
@
click=
"handleCancel"
/>
</div>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
,
computed
}
from
'
vue
'
;
import
{
FullscreenExitOutlined
,
FullscreenOutlined
,
CloseOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
name
:
'
ModalClose
'
,
components
:
{
FullscreenExitOutlined
,
FullscreenOutlined
,
CloseOutlined
},
props
:
{
canFullscreen
:
propTypes
.
bool
.
def
(
true
),
fullScreen
:
propTypes
.
bool
,
},
emits
:
[
'
cancel
'
,
'
fullscreen
'
],
setup
(
props
,
{
emit
})
{
const
{
prefixCls
}
=
useDesign
(
'
basic-modal-close
'
);
const
getClass
=
computed
(()
=>
{
return
[
prefixCls
,
`
${
prefixCls
}
--custom`
,
{
[
`
${
prefixCls
}
--can-full`
]:
props
.
canFullscreen
,
},
];
});
function
handleCancel
()
{
emit
(
'
cancel
'
);
}
function
handleFullScreen
(
e
:
Event
)
{
e
?.
stopPropagation
();
e
?.
preventDefault
();
emit
(
'
fullscreen
'
);
}
return
{
getClass
,
prefixCls
,
handleCancel
,
handleFullScreen
,
};
},
});
</
script
>
<
style
lang=
"less"
>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-basic-modal-close';
.@{prefix-cls} {
display: flex;
height: 95%;
align-items: center;
> span {
margin-left: 48px;
font-size: 16px;
}
&--can-full {
> span {
margin-left: 12px;
}
}
&:not(&--can-full) {
> span:nth-child(1) {
&:hover {
font-weight: 700;
}
}
}
& span:nth-child(1) {
display: inline-block;
padding: 10px;
&:hover {
color: @primary-color;
}
}
& span:nth-child(2) {
&:hover {
color: @error-color;
}
}
}
</
style
>
src/components/Modal/src/components/ModalFooter.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<div>
<slot
name=
"insertFooter"
/>
<a-button
v-bind=
"cancelButtonProps"
@
click=
"handleCancel"
v-if=
"showCancelBtn"
>
{{
cancelText
}}
</a-button>
<slot
name=
"centerFooter"
/>
<a-button
:type=
"okType"
@
click=
"handleOk"
:loading=
"confirmLoading"
v-bind=
"okButtonProps"
v-if=
"showOkBtn"
>
{{
okText
}}
</a-button>
<slot
name=
"appendFooter"
/>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
basicProps
}
from
'
../props
'
;
export
default
defineComponent
({
name
:
'
BasicModalFooter
'
,
props
:
basicProps
,
emits
:
[
'
ok
'
,
'
cancel
'
],
setup
(
_
,
{
emit
})
{
function
handleOk
()
{
emit
(
'
ok
'
);
}
function
handleCancel
()
{
emit
(
'
cancel
'
);
}
return
{
handleOk
,
handleCancel
};
},
});
</
script
>
src/components/Modal/src/components/ModalHeader.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<BasicTitle
:helpMessage=
"helpMessage"
>
{{
title
}}
</BasicTitle>
</
template
>
<
script
lang=
"ts"
>
import
type
{
PropType
}
from
'
vue
'
;
import
{
defineComponent
}
from
'
vue
'
;
import
{
BasicTitle
}
from
'
/@/components/Basic
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
name
:
'
BasicModalHeader
'
,
components
:
{
BasicTitle
},
props
:
{
helpMessage
:
{
type
:
[
String
,
Array
]
as
PropType
<
string
|
string
[]
>
,
},
title
:
propTypes
.
string
,
},
});
</
script
>
src/components/Modal/src/components/ModalWrapper.vue
0 → 100644
浏览文件 @
ebf7c8aa
<
template
>
<ScrollContainer
ref=
"wrapperRef"
:style=
"wrapStyle"
>
<div
ref=
"spinRef"
:style=
"spinStyle"
v-loading=
"loading"
:loading-tip=
"loadingTip"
>
<slot
/>
</div>
</ScrollContainer>
</
template
>
<
script
lang=
"ts"
>
import
type
{
ModalWrapperProps
}
from
'
../types
'
;
import
type
{
CSSProperties
}
from
'
vue
'
;
import
{
defineComponent
,
computed
,
ref
,
watchEffect
,
unref
,
watch
,
onMounted
,
nextTick
,
onUnmounted
,
}
from
'
vue
'
;
import
{
Spin
}
from
'
ant-design-vue
'
;
import
{
useWindowSizeFn
}
from
'
/@/hooks/event/useWindowSizeFn
'
;
import
{
ScrollContainer
}
from
'
/@/components/Container
'
;
// import { useElResize } from '/@/hooks/event/useElResize';
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
createModalContext
}
from
'
../hooks/useModalContext
'
;
export
default
defineComponent
({
name
:
'
ModalWrapper
'
,
components
:
{
Spin
,
ScrollContainer
},
props
:
{
loading
:
propTypes
.
bool
,
useWrapper
:
propTypes
.
bool
.
def
(
true
),
modalHeaderHeight
:
propTypes
.
number
.
def
(
50
),
modalFooterHeight
:
propTypes
.
number
.
def
(
54
),
minHeight
:
propTypes
.
number
.
def
(
200
),
footerOffset
:
propTypes
.
number
.
def
(
0
),
visible
:
propTypes
.
bool
,
fullScreen
:
propTypes
.
bool
,
loadingTip
:
propTypes
.
string
,
},
emits
:
[
'
height-change
'
,
'
ext-height
'
],
setup
(
props
:
ModalWrapperProps
,
{
emit
})
{
const
wrapperRef
=
ref
<
ComponentRef
>
(
null
);
const
spinRef
=
ref
<
ElRef
>
(
null
);
const
realHeightRef
=
ref
(
0
);
let
stopElResizeFn
:
Fn
=
()
=>
{};
useWindowSizeFn
(
setModalHeight
);
createModalContext
({
redoModalHeight
:
setModalHeight
,
});
const
wrapStyle
=
computed
(
():
CSSProperties
=>
{
return
{
minHeight
:
`
${
props
.
minHeight
}
px`
,
height
:
`
${
unref
(
realHeightRef
)}
px`
,
// overflow: 'auto',
};
}
);
const
spinStyle
=
computed
(
():
CSSProperties
=>
{
return
{
// padding 28
height
:
`
${
unref
(
realHeightRef
)
-
28
}
px`
,
};
}
);
watchEffect
(()
=>
{
props
.
useWrapper
&&
setModalHeight
();
});
watch
(
()
=>
props
.
fullScreen
,
()
=>
{
setTimeout
(()
=>
{
setModalHeight
();
},
0
);
}
);
onMounted
(()
=>
{
const
{
modalHeaderHeight
,
modalFooterHeight
}
=
props
;
emit
(
'
ext-height
'
,
modalHeaderHeight
+
modalFooterHeight
);
// listenElResize();
});
onUnmounted
(()
=>
{
stopElResizeFn
&&
stopElResizeFn
();
});
async
function
setModalHeight
()
{
// 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
// 加上这个,就必须在使用的时候传递父级的visible
if
(
!
props
.
visible
)
return
;
const
wrapperRefDom
=
unref
(
wrapperRef
);
if
(
!
wrapperRefDom
)
return
;
const
bodyDom
=
wrapperRefDom
.
$el
.
parentElement
;
if
(
!
bodyDom
)
return
;
bodyDom
.
style
.
padding
=
'
0
'
;
await
nextTick
();
try
{
const
modalDom
=
bodyDom
.
parentElement
&&
bodyDom
.
parentElement
.
parentElement
;
if
(
!
modalDom
)
return
;
const
modalRect
=
getComputedStyle
(
modalDom
).
top
;
const
modalTop
=
Number
.
parseInt
(
modalRect
);
let
maxHeight
=
window
.
innerHeight
-
modalTop
*
2
+
(
props
.
footerOffset
!
||
0
)
-
props
.
modalFooterHeight
-
props
.
modalHeaderHeight
;
// 距离顶部过进会出现滚动条
if
(
modalTop
<
40
)
{
maxHeight
-=
26
;
}
await
nextTick
();
const
spinEl
=
unref
(
spinRef
);
if
(
!
spinEl
)
return
;
const
realHeight
=
spinEl
.
scrollHeight
;
if
(
props
.
fullScreen
)
{
realHeightRef
.
value
=
window
.
innerHeight
-
props
.
modalFooterHeight
-
props
.
modalHeaderHeight
;
}
else
{
realHeightRef
.
value
=
realHeight
>
maxHeight
?
maxHeight
:
realHeight
+
16
+
30
;
}
emit
(
'
height-change
'
,
unref
(
realHeightRef
));
}
catch
(
error
)
{
console
.
log
(
error
);
}
}
return
{
wrapStyle
,
wrapperRef
,
spinRef
,
spinStyle
};
},
});
</
script
>
src/components/Modal/src/useModal.ts
→
src/components/Modal/src/
hooks/
useModal.ts
浏览文件 @
ebf7c8aa
...
...
@@ -4,7 +4,7 @@ import type {
ModalProps
,
ReturnMethods
,
UseModalInnerReturnType
,
}
from
'
./types
'
;
}
from
'
.
.
/types
'
;
import
{
ref
,
...
...
@@ -19,16 +19,18 @@ import {
import
{
isProdMode
}
from
'
/@/utils/env
'
;
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
isEqual
}
from
'
lodash-es
'
;
import
{
tryOnUnmounted
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
tryOnUnmounted
,
isInSetup
}
from
'
/@/utils/helper/vueHelper
'
;
import
{
error
}
from
'
/@/utils/log
'
;
import
{
computed
}
from
'
vue
'
;
const
dataTransferRef
=
reactive
<
any
>
({});
const
visibleData
=
reactive
<
{
[
key
:
number
]:
boolean
}
>
({});
/**
* @description: Applicable to independent modal and call outside
*/
export
function
useModal
():
UseModalReturnType
{
if
(
!
getCurrentInstance
())
{
throw
new
Error
(
'
Please put useModal function in the setup function!
'
);
}
isInSetup
();
const
modalRef
=
ref
<
Nullable
<
ModalMethods
>>
(
null
);
const
loadedRef
=
ref
<
Nullable
<
boolean
>>
(
false
);
const
uidRef
=
ref
<
string
>
(
''
);
...
...
@@ -45,23 +47,29 @@ export function useModal(): UseModalReturnType {
if
(
unref
(
loadedRef
)
&&
isProdMode
()
&&
modalMethod
===
unref
(
modalRef
))
return
;
modalRef
.
value
=
modalMethod
;
modalMethod
.
emitVisible
=
(
visible
:
boolean
,
uid
:
number
)
=>
{
visibleData
[
uid
]
=
visible
;
};
}
const
getInstance
=
()
=>
{
const
instance
=
unref
(
modalRef
);
if
(
!
instance
)
{
throw
new
Error
(
'
instance is undefined!
'
);
error
(
'
useModal
instance is undefined!
'
);
}
return
instance
;
};
const
methods
:
ReturnMethods
=
{
setModalProps
:
(
props
:
Partial
<
ModalProps
>
):
void
=>
{
getInstance
().
setModalProps
(
props
);
getInstance
()
?
.
setModalProps
(
props
);
},
getVisible
:
computed
(():
boolean
=>
{
return
visibleData
[
~~
unref
(
uidRef
)];
}),
openModal
:
<
T
=
any
>
(
visible
=
true
,
data
?:
T
,
openOnSet
=
true
):
void
=>
{
getInstance
().
setModalProps
({
getInstance
()
?
.
setModalProps
({
visible
:
visible
,
});
...
...
@@ -83,20 +91,16 @@ export function useModal(): UseModalReturnType {
export
const
useModalInner
=
(
callbackFn
?:
Fn
):
UseModalInnerReturnType
=>
{
const
modalInstanceRef
=
ref
<
Nullable
<
ModalMethods
>>
(
null
);
const
currentInsta
ll
=
getCurrentInstance
();
const
currentInsta
nce
=
getCurrentInstance
();
const
uidRef
=
ref
<
string
>
(
''
);
if
(
!
currentInstall
)
{
throw
new
Error
(
'
instance is undefined!
'
);
}
// currentInstall.type.emits = [...currentInstall.type.emits, 'register'];
// Object.assign(currentInstall.type.emits, ['register']);
const
getInstance
=
()
=>
{
const
instance
=
unref
(
modalInstanceRef
);
if
(
!
instance
)
{
throw
new
Error
(
'
instance is undefined!
'
);
error
(
'
useModalInner
instance is undefined!
'
);
}
return
instance
;
};
...
...
@@ -108,7 +112,7 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
});
uidRef
.
value
=
uuid
;
modalInstanceRef
.
value
=
modalInstance
;
currentInsta
ll
.
emit
(
'
register
'
,
modalInstance
,
uuid
);
currentInsta
nce
?
.
emit
(
'
register
'
,
modalInstance
,
uuid
);
};
watchEffect
(()
=>
{
...
...
@@ -124,19 +128,22 @@ export const useModalInner = (callbackFn?: Fn): UseModalInnerReturnType => {
register
,
{
changeLoading
:
(
loading
=
true
)
=>
{
getInstance
().
setModalProps
({
loading
});
getInstance
()
?
.
setModalProps
({
loading
});
},
getVisible
:
computed
(():
boolean
=>
{
return
visibleData
[
~~
unref
(
uidRef
)];
}),
changeOkLoading
:
(
loading
=
true
)
=>
{
getInstance
().
setModalProps
({
confirmLoading
:
loading
});
getInstance
()
?
.
setModalProps
({
confirmLoading
:
loading
});
},
closeModal
:
()
=>
{
getInstance
().
setModalProps
({
visible
:
false
});
getInstance
()
?
.
setModalProps
({
visible
:
false
});
},
setModalProps
:
(
props
:
Partial
<
ModalProps
>
)
=>
{
getInstance
().
setModalProps
(
props
);
getInstance
()
?
.
setModalProps
(
props
);
},
},
];
...
...
src/components/Modal/src/useModalContext.ts
→
src/components/Modal/src/
hooks/
useModalContext.ts
浏览文件 @
ebf7c8aa
文件已移动
src/components/Modal/src/useModalDrag.ts
→
src/components/Modal/src/
hooks/
useModalDrag.ts
浏览文件 @
ebf7c8aa
文件已移动
src/components/Modal/src/
use
FullScreen.ts
→
src/components/Modal/src/
hooks/useModal
FullScreen.ts
浏览文件 @
ebf7c8aa
文件已移动
src/components/Modal/src/index.less
浏览文件 @
ebf7c8aa
...
...
@@ -21,9 +21,12 @@
width: 520px;
padding-bottom: 0;
.
ant-spin-nested-loading
{
padding: 1
6
px;
.
scroll-container
{
padding: 1
4
px;
}
// .ant-spin-nested-loading {
// padding: 16px;
// }
&-title {
font-size: 16px;
...
...
@@ -35,46 +38,6 @@
}
}
.custom-close-icon {
display: flex;
height: 95%;
align-items: center;
> span {
margin-left: 48px;
font-size: 16px;
}
&.can-full {
> span {
margin-left: 12px;
}
}
&:not(.can-full) {
> span:nth-child(1) {
&:hover {
font-weight: 700;
}
}
}
& span:nth-child(1) {
display: inline-block;
padding: 10px;
&:hover {
color: @primary-color;
}
}
& span:nth-child(2) {
&:hover {
color: @error-color;
}
}
}
.ant-modal-body {
padding: 0;
}
...
...
@@ -96,8 +59,6 @@
}
&-footer {
// padding: 10px 26px 26px 16px;
button + button {
margin-left: 10px;
}
...
...
src/components/Modal/src/props.ts
浏览文件 @
ebf7c8aa
import
type
{
PropType
}
from
'
vue
'
;
import
type
{
PropType
,
CSSProperties
}
from
'
vue
'
;
import
{
ButtonProps
}
from
'
ant-design-vue/es/button/buttonTypes
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
import
{
propTypes
,
VueNode
}
from
'
/@/utils/propTypes
'
;
import
type
{
ModalWrapperProps
}
from
'
./types
'
;
const
{
t
}
=
useI18n
();
export
const
modalProps
=
{
...
...
@@ -26,6 +27,7 @@ export const basicProps = Object.assign({}, modalProps, {
// Whether to setting wrapper
useWrapper
:
propTypes
.
bool
.
def
(
true
),
loading
:
propTypes
.
bool
,
loadingTip
:
propTypes
.
string
,
/**
* @description: Show close button
*/
...
...
@@ -35,65 +37,44 @@ export const basicProps = Object.assign({}, modalProps, {
*/
showOkBtn
:
propTypes
.
bool
.
def
(
true
),
wrapperProps
:
Object
as
PropType
<
any
>
,
wrapperProps
:
Object
as
PropType
<
Partial
<
ModalWrapperProps
>
>
,
afterClose
:
Function
as
PropType
<
()
=>
Promise
<
any
>>
,
afterClose
:
Function
as
PropType
<
()
=>
Promise
<
VueNode
>>
,
bodyStyle
:
Object
as
PropType
<
any
>
,
bodyStyle
:
Object
as
PropType
<
CSSProperties
>
,
closable
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
true
,
},
closable
:
propTypes
.
bool
.
def
(
true
),
closeIcon
:
Object
as
PropType
<
any
>
,
closeIcon
:
Object
as
PropType
<
VueNode
>
,
confirmLoading
:
Boolean
as
PropType
<
boolean
>
,
confirmLoading
:
propTypes
.
bool
,
destroyOnClose
:
Boolean
as
PropType
<
boolean
>
,
destroyOnClose
:
propTypes
.
bool
,
footer
:
Object
as
PropType
<
any
>
,
footer
:
Object
as
PropType
<
VueNode
>
,
getContainer
:
Function
as
PropType
<
()
=>
any
>
,
mask
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
true
,
},
mask
:
propTypes
.
bool
.
def
(
true
),
maskClosable
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
true
,
},
keyboard
:
{
type
:
Boolean
as
PropType
<
boolean
>
,
default
:
true
,
},
maskClosable
:
propTypes
.
bool
.
def
(
true
),
keyboard
:
propTypes
.
bool
.
def
(
true
),
maskStyle
:
Object
as
PropType
<
any
>
,
maskStyle
:
Object
as
PropType
<
CSSProperties
>
,
okType
:
{
type
:
String
as
PropType
<
string
>
,
default
:
'
primary
'
,
},
okType
:
propTypes
.
string
.
def
(
'
primary
'
),
okButtonProps
:
Object
as
PropType
<
ButtonProps
>
,
cancelButtonProps
:
Object
as
PropType
<
ButtonProps
>
,
title
:
{
type
:
String
as
PropType
<
string
>
,
},
title
:
propTypes
.
string
,
visible
:
Boolean
as
PropType
<
boolean
>
,
visible
:
propTypes
.
bool
,
width
:
[
String
,
Number
]
as
PropType
<
string
|
number
>
,
wrapClassName
:
{
type
:
String
as
PropType
<
string
>
,
},
wrapClassName
:
propTypes
.
string
,
zIndex
:
{
type
:
Number
as
PropType
<
number
>
,
},
zIndex
:
propTypes
.
number
,
});
src/components/Modal/src/types.ts
浏览文件 @
ebf7c8aa
import
type
{
ButtonProps
}
from
'
ant-design-vue/lib/button/buttonTypes
'
;
import
type
{
CSSProperties
,
VNodeChild
}
from
'
vue
'
;
import
type
{
CSSProperties
,
VNodeChild
,
ComputedRef
}
from
'
vue
'
;
/**
* @description: 弹窗对外暴露的方法
*/
export
interface
ModalMethods
{
setModalProps
:
(
props
:
Partial
<
ModalProps
>
)
=>
void
;
emitVisible
?:
(
visible
:
boolean
,
uid
:
number
)
=>
void
;
}
export
type
RegisterFn
=
(
modalMethods
:
ModalMethods
,
uuid
?:
string
)
=>
void
;
export
interface
ReturnMethods
extends
ModalMethods
{
openModal
:
<
T
=
any
>
(
props
?:
boolean
,
data
?:
T
,
openOnSet
?:
boolean
)
=>
void
;
getVisible
?:
ComputedRef
<
boolean
>
;
}
export
type
UseModalReturnType
=
[
RegisterFn
,
ReturnMethods
];
...
...
@@ -19,6 +21,7 @@ export interface ReturnInnerMethods extends ModalMethods {
closeModal
:
()
=>
void
;
changeLoading
:
(
loading
:
boolean
)
=>
void
;
changeOkLoading
:
(
loading
:
boolean
)
=>
void
;
getVisible
?:
ComputedRef
<
boolean
>
;
}
export
type
UseModalInnerReturnType
=
[
RegisterFn
,
ReturnInnerMethods
];
...
...
@@ -38,6 +41,7 @@ export interface ModalProps {
useWrapper
:
boolean
;
loading
:
boolean
;
loadingTip
?:
string
;
wrapperProps
:
Omit
<
ModalWrapperProps
,
'
loading
'
>
;
...
...
@@ -193,4 +197,5 @@ export interface ModalWrapperProps {
minHeight
:
number
;
visible
:
boolean
;
fullScreen
:
boolean
;
useWrapper
:
boolean
;
}
src/hooks/core/useAttrs.ts
浏览文件 @
ebf7c8aa
import
{
getCurrentInstance
,
reactive
,
shallowRef
,
watchEffect
}
from
'
vue
'
;
import
type
{
Ref
}
from
'
vue
'
;
interface
Params
{
excludeListeners
?:
boolean
;
excludeKeys
?:
string
[];
...
...
@@ -12,7 +12,7 @@ export function entries<T>(obj: Hash<T>): [string, T][] {
return
Object
.
keys
(
obj
).
map
((
key
:
string
)
=>
[
key
,
obj
[
key
]]);
}
export
function
useAttrs
(
params
:
Params
=
{})
{
export
function
useAttrs
(
params
:
Params
=
{})
:
Ref
<
Recordable
>
|
{}
{
const
instance
=
getCurrentInstance
();
if
(
!
instance
)
return
{};
...
...
src/settings/projectSetting.ts
浏览文件 @
ebf7c8aa
...
...
@@ -37,7 +37,7 @@ const setting: ProjectConfig = {
showLogo
:
true
,
// Whether to show footer
showFooter
:
tru
e
,
showFooter
:
fals
e
,
// locale setting
locale
:
{
...
...
src/utils/propTypes.ts
浏览文件 @
ebf7c8aa
import
{
CSSProperties
,
VNodeChild
}
from
'
vue
'
;
import
{
createTypes
,
VueTypeValidableDef
,
VueTypesInterface
}
from
'
vue-types
'
;
type
VueNode
=
VNodeChild
|
JSX
.
Element
;
export
type
VueNode
=
VNodeChild
|
JSX
.
Element
;
type
PropTypes
=
VueTypesInterface
&
{
readonly
style
:
VueTypeValidableDef
<
CSSProperties
>
;
...
...
src/views/demo/comp/drawer/Drawer3.vue
浏览文件 @
ebf7c8aa
<
template
>
<BasicDrawer
v-bind=
"$attrs"
title=
"Modal Title"
width=
"50%"
showFooter
>
<BasicDrawer
v-bind=
"$attrs"
title=
"Modal Title"
width=
"50%"
showFooter
@
ok=
"handleOk"
>
<p
class=
"h-20"
v-for=
"index in 40"
:key=
"index"
>
根据屏幕高度自适应
</p>
<template
#insertFooter
>
<a-button>
btn
</a-button>
</
template
>
<
template
#centerFooter
>
<a-button>
btn2
</a-button>
</
template
>
<
template
#appendFooter
>
<a-button>
btn3
</a-button>
</
template
>
<!-- <template #footer>
<a-button> customerFooter</a-button>
</template> -->
</BasicDrawer>
</template>
<
script
lang=
"ts"
>
...
...
@@ -9,7 +23,13 @@
export
default
defineComponent
({
components
:
{
BasicDrawer
},
setup
()
{
return
{};
return
{
handleOk
:
()
=>
{
console
.
log
(
'
=====================
'
);
console
.
log
(
'
ok
'
);
console
.
log
(
'
======================
'
);
},
};
},
});
</
script
>
src/views/demo/comp/drawer/Drawer5.vue
浏览文件 @
ebf7c8aa
<
template
>
<BasicDrawer
v-bind=
"$attrs"
:isDetail=
"true"
title=
"Drawer Title5"
>
<p
class=
"h-20"
>
Content Message
</p>
<template
#titleToolbar
>
toolbar
</
template
>
</BasicDrawer>
</template>
<
script
lang=
"ts"
>
...
...
@@ -8,6 +9,5 @@
import
{
BasicDrawer
}
from
'
/@/components/Drawer
'
;
export
default
defineComponent
({
components
:
{
BasicDrawer
},
setup
()
{},
});
</
script
>
src/views/demo/comp/drawer/index.vue
浏览文件 @
ebf7c8aa
...
...
@@ -3,10 +3,10 @@
<Alert
message=
"使用 useDrawer 进行抽屉操作"
show-icon
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawerLoading"
>
打开Drawer
</a-button>
<Alert
message=
"内外同时
同时
显示隐藏"
show-icon
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer2"
>
打开Drawer
</a-button>
<Alert
message=
"内外同时
控制
显示隐藏"
show-icon
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer2
(true)
"
>
打开Drawer
</a-button>
<Alert
message=
"自适应高度/显示footer"
show-icon
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer3"
>
打开Drawer
</a-button>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer3
(true)
"
>
打开Drawer
</a-button>
<Alert
message=
"内外数据交互,外部通过 transferModalData 发送,内部通过 receiveDrawerDataRef 接收。该数据具有响应式"
...
...
@@ -14,7 +14,7 @@
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"send"
>
打开Drawer并传递数据
</a-button>
<Alert
message=
"详情页模式"
show-icon
/>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer5"
>
打开详情Drawer
</a-button>
<a-button
type=
"primary"
class=
"my-4"
@
click=
"openDrawer5
(true)
"
>
打开详情Drawer
</a-button>
<Drawer1
@
register=
"register1"
/>
<Drawer2
@
register=
"register2"
/>
<Drawer3
@
register=
"register3"
/>
...
...
src/views/demo/feat/tabs/index.vue
浏览文件 @
ebf7c8aa
...
...
@@ -4,7 +4,7 @@
<a-input
placeholder=
"请输入"
/>
</CollapseContainer>
<CollapseContainer
class=
"mt-4
px-4
"
title=
"标签页操作"
>
<CollapseContainer
class=
"mt-4"
title=
"标签页操作"
>
<a-button
class=
"mr-2"
@
click=
"closeAll"
>
关闭所有
</a-button>
<a-button
class=
"mr-2"
@
click=
"closeLeft"
>
关闭左侧
</a-button>
<a-button
class=
"mr-2"
@
click=
"closeRight"
>
关闭右侧
</a-button>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录