index.jsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import './index.less'
  2. import PropTypes from 'ant-design-vue/es/_util/vue-types'
  3. import GridContent from '../GridContent'
  4. import { PageHeader, Tabs } from 'ant-design-vue'
  5. import { getComponentFromProp } from 'ant-design-vue/lib/_util/props-util'
  6. const { PageHeaderProps } = PageHeader
  7. const prefixedClassName = 'ant-pro-page-header-wrap'
  8. const PageHeaderTabConfig = {
  9. tabList: PropTypes.array,
  10. tabActiveKey: PropTypes.string,
  11. tabProps: PropTypes.object,
  12. tabChange: PropTypes.func
  13. }
  14. const PageHeaderWrapperProps = {
  15. ...PageHeaderTabConfig,
  16. ...PageHeaderProps,
  17. title: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  18. content: PropTypes.any,
  19. extraContent: PropTypes.any,
  20. pageHeaderRender: PropTypes.func,
  21. breadcrumb: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).def(true),
  22. back: PropTypes.func,
  23. // only use `pro-layout` in children
  24. i18nRender: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]).def(false)
  25. }
  26. const defaultI18nRender = (t) => t
  27. const useContext = (route) => {
  28. return route && {
  29. ...route.meta
  30. } || null
  31. }
  32. const noop = () => {
  33. }
  34. // TODO :: tabList tab 支持图标 优化
  35. const renderFooter = (h, tabConfigProps, i18nRender) => {
  36. const {
  37. tabList,
  38. tabActiveKey,
  39. tabChange: onTabChange,
  40. tabBarExtraContent,
  41. tabProps
  42. } = tabConfigProps
  43. return tabList && tabList.length > 0 && (
  44. <Tabs
  45. class={`${prefixedClassName}-tabs`}
  46. activeKey={tabActiveKey}
  47. onChange={key => {
  48. if (onTabChange) {
  49. onTabChange(key)
  50. }
  51. }}
  52. tabBarExtraContent={tabBarExtraContent}
  53. {...tabProps}
  54. >
  55. {tabList.map(item => (
  56. <Tabs.TabPane {...item} tab={i18nRender(item.tab)} key={item.key} />
  57. ))}
  58. </Tabs>
  59. )
  60. }
  61. const renderPageHeader = (h, content, extraContent) => {
  62. if (!content && !extraContent) {
  63. return null
  64. }
  65. return (
  66. <div class={`${prefixedClassName}-detail`}>
  67. <div class={`${prefixedClassName}-main`}>
  68. <div class={`${prefixedClassName}-row`}>
  69. {content && (
  70. <div class={`${prefixedClassName}-content`}>{content}</div>
  71. )}
  72. {extraContent && (
  73. <div class={`${prefixedClassName}-extraContent`}>
  74. {extraContent}
  75. </div>
  76. )}
  77. </div>
  78. </div>
  79. </div>
  80. )
  81. }
  82. const defaultPageHeaderRender = (h, props, pageMeta, i18nRender) => {
  83. const {
  84. title,
  85. content,
  86. pageHeaderRender,
  87. extra,
  88. extraContent,
  89. breadcrumb,
  90. back: handleBack,
  91. ...restProps
  92. } = props
  93. if (pageHeaderRender) {
  94. return pageHeaderRender({ ...props })
  95. }
  96. let pageHeaderTitle = title
  97. if (!title && title !== false) {
  98. pageHeaderTitle = pageMeta.title
  99. }
  100. const tabProps = {
  101. breadcrumb,
  102. extra,
  103. title: i18nRender(pageHeaderTitle),
  104. footer: renderFooter(h, restProps, i18nRender)
  105. }
  106. if (!handleBack) {
  107. tabProps.backIcon = false
  108. }
  109. return (
  110. <PageHeader {...{ props: tabProps }} onBack={handleBack || noop}>
  111. {renderPageHeader(h, content, extraContent)}
  112. </PageHeader>
  113. )
  114. // return
  115. }
  116. const PageHeaderWrapper = {
  117. name: 'PageHeaderWrapper',
  118. props: PageHeaderWrapperProps,
  119. inject: ['locale', 'contentWidth', 'breadcrumbRender'],
  120. render (h) {
  121. const { $route, $listeners } = this
  122. const children = this.$slots.default
  123. const content = getComponentFromProp(this, 'content')
  124. const extra = getComponentFromProp(this, 'extra')
  125. const extraContent = getComponentFromProp(this, 'extraContent')
  126. const pageMeta = useContext(this.$props.route || $route)
  127. const i18n = this.$props.i18nRender || this.locale || defaultI18nRender
  128. const contentWidth = this.$props.contentWidth || this.contentWidth || false
  129. // 当未设置 back props 或未监听 @back,不显示 back
  130. // props 的 back 事件优先级高于 @back,需要注意
  131. const onBack = this.$props.back || $listeners.back
  132. const back = onBack && (() => {
  133. // this.$emit('back')
  134. // call props back func
  135. onBack && onBack()
  136. }) || undefined
  137. const onTabChange = this.$props.tabChange
  138. const tabChange = (key) => {
  139. this.$emit('tabChange', key)
  140. onTabChange && onTabChange(key)
  141. }
  142. let breadcrumb = {}
  143. const propsBreadcrumb = this.$props.breadcrumb
  144. if (propsBreadcrumb === true) {
  145. const routes = $route.matched.concat().map(route => {
  146. return {
  147. path: route.path,
  148. breadcrumbName: i18n(route.meta.title)
  149. }
  150. })
  151. const defaultItemRender = ({ route, params, routes, paths, h }) => {
  152. return routes.indexOf(route) === routes.length - 1 && (
  153. <span>{route.breadcrumbName}</span>
  154. ) || (
  155. <router-link to={{ path: route.path || '/', params }}>{route.breadcrumbName}</router-link>
  156. )
  157. }
  158. // If custom breadcrumb render undefined
  159. // use default breadcrumb..
  160. const itemRender = this.breadcrumbRender || defaultItemRender
  161. breadcrumb = { props: { routes, itemRender } }
  162. } else {
  163. breadcrumb = propsBreadcrumb || null
  164. }
  165. const props = {
  166. ...this.$props,
  167. content,
  168. extra,
  169. extraContent,
  170. breadcrumb,
  171. tabChange,
  172. back
  173. }
  174. return (
  175. <div class="ant-pro-page-header-wrap">
  176. <div class={`${prefixedClassName}-page-header-warp`}>
  177. <GridContent>{defaultPageHeaderRender(h, props, pageMeta, i18n)}</GridContent>
  178. </div>
  179. {children ? (
  180. <GridContent contentWidth={contentWidth}>
  181. <div class={`${prefixedClassName}-children-content`}>
  182. {children}
  183. </div>
  184. </GridContent>
  185. ) : null}
  186. </div>
  187. )
  188. }
  189. }
  190. export default PageHeaderWrapper