index.tsx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. import { Carousel, Drawer, Spin } from "antd";
  2. import React, { useEffect, useMemo, useState } from "react"
  3. import { ReactComponent as Topimg } from '@/assets/topimg.svg'
  4. import { ReactComponent as Img } from '@/assets/img.svg'
  5. import style from './index.less'
  6. import '../addLandingPage/index1.less'
  7. import { UserAddOutlined } from "@ant-design/icons";
  8. import { useModel } from "umi";
  9. import { getTypeKey } from "@/utils/utils";
  10. import VideoNews from "../newsModal/videoNews";
  11. type Props = {
  12. visible?: boolean,
  13. onClose?: () => void,
  14. id: number
  15. }
  16. /**
  17. * 查看落地页
  18. * @param props
  19. * @returns
  20. */
  21. function LookLanding(props: Props) {
  22. let { visible, onClose, id } = props
  23. const [pageBackColor, setPageBackColor] = useState<string>('#FFFFFF') // 背景颜色
  24. const [content, setContent] = useState<any[]>([]) // 内容
  25. const [globalData, setGlobalData] = useState<any>([]) // 浮窗
  26. const { get } = useModel('useLaunchAdq.useBdMediaPup')
  27. useEffect(() => {
  28. if (id) {
  29. get.run({ sysMediaId: id, mediaType: 'PAGE' }).then(res => {
  30. if (res) {
  31. const { pageSpecsList, globalSpec } = res
  32. setPageBackColor(pageSpecsList[0]?.bgColor)
  33. let pageElementsSpecList = pageSpecsList[0]?.pageElementsSpecList
  34. setContent(pageElementsSpecList?.map((item: any) => {
  35. let typeKey = getTypeKey(item?.elementType)
  36. if (typeKey) {
  37. let data = item[typeKey] || {}
  38. return {
  39. elementType: item?.elementType,
  40. ...data
  41. }
  42. }
  43. return item
  44. }))
  45. if (globalSpec && Object.keys(globalSpec).length > 0) {
  46. let globalElementsSpecList = globalSpec.globalElementsSpecList
  47. let newComponentItem = globalElementsSpecList?.map((item: { elementType: string }) => {
  48. let typeKey = getTypeKey(item.elementType)
  49. let { elementType, ...data } = item[typeKey]
  50. let typeKey1 = getTypeKey(elementType)
  51. let componentItem: any = data[typeKey1]
  52. if (componentItem) {
  53. componentItem['elementType'] = elementType
  54. }
  55. data.componentItem = componentItem
  56. data.elementType = item.elementType
  57. delete data[typeKey1]
  58. return data
  59. })
  60. setGlobalData(newComponentItem)
  61. }
  62. }
  63. })
  64. }
  65. }, [id])
  66. // 顶部组件
  67. const topCon = useMemo(() => {
  68. if (content?.length > 0) {
  69. let { imageUrl, elementType, imageUrlList, videoUrl } = content[0]
  70. return <>
  71. {
  72. elementType === 'TOP_IMAGE' ? <>
  73. <div className={`compt componentType41 ${content[0]?.comptActive && 'comptActive'}`}>
  74. <div className={'componentWrap'}>
  75. <div className={'componentContent'}>
  76. {
  77. imageUrl ? <img src={imageUrl} style={{ display: 'block', width: '100%', margin: 0 }} /> : <div className={'default'} style={{ width: 375, height: 300, margin: 0 }}>
  78. <div className={'defaultIcon'} style={{ marginTop: 80 }}>
  79. <Topimg />
  80. </div>
  81. </div>
  82. }
  83. </div>
  84. </div>
  85. </div>
  86. </> :
  87. elementType === 'TOP_SLIDER' ? <>
  88. <div className={`compt componentType101 ${content[0]?.comptActive && 'comptActive'}`}>
  89. <div className={'componentWrap'}>
  90. <div className={'componentContent'}>
  91. <Carousel autoplay style={{ width: 375, height: 375 }}>
  92. {imageUrlList?.map((item: any, index: number) => {
  93. return <div style={{ width: 375, height: 375 }} key={index}><img style={{ width: 375, height: 375 }} src={item} /></div>
  94. })}
  95. </Carousel>
  96. </div>
  97. </div>
  98. </div>
  99. </> :
  100. elementType === 'TOP_VIDEO' ? <>
  101. <div className={`compt componentType61 ${content[0]?.comptActive && 'comptActive'}`}>
  102. <div className={'componentWrap'}>
  103. <div className={'componentContent'}>
  104. {
  105. videoUrl && <div className="videoPlay">
  106. <VideoNews src={videoUrl} style={{ display: 'block', width: '100%', margin: 0, height: '100%' }} maskImgStyle={{ position: 'absolute', top: '50%', left: '50%', width: 40, height: 40, transform: 'translate(-50%, -50%)', zIndex: 10 }} />
  107. </div>
  108. }
  109. </div>
  110. </div>
  111. </div>
  112. </> : null
  113. }
  114. </>
  115. } else {
  116. return null
  117. }
  118. }, [content])
  119. const comptCon = () => {
  120. if (content?.length === 0) {
  121. return null
  122. } else {
  123. return <div className="page-0" style={globalData?.some((item: any) => item?.elementType === 'FLOAT_BUTTON') ? { paddingBottom: 90, minHeight: 510 } : {}}>
  124. {content.map((value: any, index: number) => {
  125. if (value.elementType === 'IMAGE') {
  126. let { imageUrl, paddingTop, paddingBottom } = value
  127. return <div className={`compt componentType41`} key={index}>
  128. <div className={'componentWrap'}>
  129. <div className={'componentContent'}>
  130. {
  131. imageUrl ? <img src={imageUrl} style={{ display: 'block', width: '100%', margin: 0, marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px' }} /> : <div className={'default'} style={{ width: 375, height: 222, margin: 0, marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px' }}>
  132. <div className={'defaultIcon'} style={{ marginTop: 44 }}>
  133. <Img />
  134. </div>
  135. </div>
  136. }
  137. </div>
  138. </div>
  139. </div>
  140. } else if (value.elementType === 'TEXT') {
  141. let { fontSize, fontColor, textAlignment, text, fontStyle, paddingTop, paddingBottom } = value
  142. return <div className={`compt componentType1`} key={index}>
  143. <div className={'componentWrap'}>
  144. <div className={'componentContent'} style={{ backgroundColor: pageBackColor }}>
  145. <div className={'text'} style={{ lineHeight: fontSize * 1.5 + 'px', fontSize: Number(fontSize), color: fontColor, textAlign: textAlignment === 0 ? 'left' : textAlignment === 1 ? 'center' : 'right', fontWeight: fontStyle === 0 ? 'normal' : 'bold', maxWidth: '100%', display: 'block', marginLeft: 24, marginRight: 24, marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px' }}>
  146. <div>{text ?
  147. text?.split(/[\r\n]/g)?.map((item: any, index: number) => {
  148. if (item) {
  149. return <div key={`item${index}`}>
  150. {item?.split(' ')?.map((item1: any, ind: number) => {
  151. if (item1) {
  152. return <span key={`item1${ind}`}>{item1}</span>
  153. } else {
  154. return <span key={`item1${ind}`}>&nbsp;</span>
  155. }
  156. })}
  157. </div>
  158. } else {
  159. return <div key={`item${index}`}>&nbsp;</div>
  160. }
  161. })
  162. : '请输入文本内容'}</div>
  163. </div>
  164. <div className={'textAreaDiv'} style={{ lineHeight: fontSize * 1.5 + 'px', fontSize: Number(fontSize), margin: '11px 24px', marginLeft: 24, marginRight: 24, marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px' }}>
  165. <textarea readOnly value={text} className={'textarea'} style={{ color: fontColor, fontWeight: fontStyle === 0 ? 'normal' : 'bold', textAlign: textAlignment === 0 ? 'left' : textAlignment === 1 ? 'center' : 'right', backgroundColor: pageBackColor }}></textarea>
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. } else if (value.elementType === 'GH' || value.elementType === 'ENTERPRISE_WX') {
  171. let { paddingTop, paddingBottom, btnTitle, fontColor, btnBgColorTheme, btnBorderColorTheme, btnFontType, useIcon } = value
  172. return <div className={`compt componentType21`} key={index}>
  173. <div className={'componentWrap'}>
  174. <div className={'componentContent'}>
  175. <div style={{ marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px' }}>
  176. <div style={{ textAlign: 'center', lineHeight: 0, maxWidth: '100%', margin: '0 92.5px' }}>
  177. <a style={{
  178. textDecoration: 'none', color: fontColor || 'rgb(255,255,255)', backgroundColor: btnBgColorTheme || 'rgb(7, 193, 96)',
  179. border: ['#FFFFFF', '#ffffff', 'rgb(255, 255, 255)'].indexOf(btnBorderColorTheme) !== -1 ? '0px solid rgb(255, 255, 255)' : `2px solid ${btnBorderColorTheme}`, borderRadius: 4, display: 'flex', alignItems: 'center',
  180. overflow: 'hidden', justifyContent: 'center', whiteSpace: 'pre', fontWeight: btnFontType === 0 ? 'normal' : 'bold',
  181. height: 40, lineHeight: 40, width: '100%', fontSize: 15
  182. }}>{useIcon === '1' && <UserAddOutlined style={{ marginRight: 6 }} />}{btnTitle || ''}</a>
  183. </div>
  184. </div>
  185. </div>
  186. </div>
  187. </div>
  188. } else if (value?.elementType === 'shelfnew') {
  189. let { paddingTop, paddingBottom, layoutItems, borderColor, bgColor, type, wxad_align, id } = value
  190. if (type === '104') {
  191. let componentItem = layoutItems?.componentItem[0]?.layoutItems?.componentItem
  192. let otherData = componentItem[1]?.layoutItems?.componentItem
  193. return <div className={`compt componentType104`} key={id}>
  194. <div className={'componentWrap'}>
  195. <div className={'componentContent'}>
  196. <div className={'shelf listType'} style={{ marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px', marginLeft: 20, marginRight: 20 }}>
  197. <div className={'shelfItem'} style={{ border: `1px solid ${borderColor || "#e5e5e5"}`, backgroundColor: bgColor || "#ffffff" }}>
  198. <div className={'shelfItemImg'} style={{ marginLeft: 11.5, marginTop: 11.5 }}>
  199. {componentItem[0]?.pureImageUrl ? <img src={componentItem[0]?.pureImageUrl} style={{ display: 'flex', width: '100%', height: '100%' }} /> : <div className={'default'} style={{ width: '100%', height: '100%' }}>
  200. <div className={'defaultIcon'} style={{ marginTop: 27, width: 36, height: 36 }}>
  201. <Img />
  202. </div>
  203. </div>}
  204. </div>
  205. <div className={'shelfItemContent'} style={{ margin: '12px 20px 0 12px' }}>
  206. <p className={'title'} style={{ color: otherData[0]?.fontColor || "#353535", fontSize: 16 }}>{otherData[0]?.content || otherData[0]?.name}</p>
  207. <p className={'desc'} style={{ color: otherData[1]?.fontColor || "#B2B2B2" }}>{otherData[1]?.content || otherData[1]?.name}</p>
  208. <div
  209. className={'btn'}
  210. style={{
  211. color: otherData[2]?.fontColor || 'rgb(255, 255, 255)',
  212. textDecoration: 'none',
  213. fontWeight: otherData[2]?.btnFontType === '0' ? 'normal' : 'bold',
  214. backgroundColor: otherData[2]?.btnBgColorTheme || "#07C160",
  215. border: ['#FFFFFF', '#ffffff', 'rgb(255, 255, 255)'].indexOf(otherData[2]?.btnBorderColorTheme) !== -1 ? '0px solid rgb(255, 255, 255)' : `2px solid ${otherData[2]?.btnBorderColorTheme}`,
  216. borderRadius: 4
  217. }}
  218. >{otherData[2]?.btnTitle}</div>
  219. </div>
  220. </div>
  221. </div>
  222. </div>
  223. </div>
  224. </div>
  225. } else if (type === '103') {
  226. let componentItem = layoutItems?.componentItem
  227. return <div className={`compt componentType103`} key={id}>
  228. <div className={'componentWrap'}>
  229. <div className={'componentContent'}>
  230. <div className='shelf gridType' style={{ marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px', marginLeft: 20 }}>
  231. {
  232. componentItem?.map((item: any, index: number) => {
  233. let shelfnewItem = item?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  234. return <div className='shelfItem-3q' key={index} style={{ borderWidth: 1, borderStyle: 'solid', borderColor: item?.borderColor, backgroundColor: item?.bgColor || 'rgb(255,255,255)', marginLeft: index === 1 ? 11 : 0 }}>
  235. <div className='shelfItemImg' style={{ marginLeft: 5.5, marginTop: 5.5 }}>
  236. {shelfnewItem[0]?.pureImageUrl ? <img src={shelfnewItem[0]?.pureImageUrl} style={{ display: 'flex', width: '100%', height: '100%' }} /> : <div className="default" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  237. <div className={'defaultIcon'} style={{ width: 36, height: 36 }}>
  238. <Img />
  239. </div>
  240. </div>}
  241. </div>
  242. <div className='shelfItemContent' style={{ marginLeft: 12, textAlign: wxad_align === 0 ? 'left' : 'center' }}>
  243. <p className='title' style={{ color: shelfnewItem[1]?.fontColor || 'rgb(53, 53, 53)', fontSize: 16, marginBottom: 4 }}>{shelfnewItem[1]?.content || shelfnewItem[1]?.name}</p>
  244. <p className='desc' style={{ color: shelfnewItem[2]?.fontColor || 'rgb(178, 178, 178)', marginBottom: 14 }}>{shelfnewItem[2]?.content || shelfnewItem[2]?.name}</p>
  245. <p className='btn' style={{
  246. textDecoration: 'none',
  247. fontWeight: shelfnewItem[3]?.btnFontType === '0' ? 400 : 'bold',
  248. color: shelfnewItem[3]?.fontColor || 'rgb(255, 255, 255)',
  249. backgroundColor: shelfnewItem[3]?.btnBgColorTheme || 'rgb(7,193,96)',
  250. borderWidth: shelfnewItem[3]?.borderSize ? Number(shelfnewItem[3]?.borderSize) : 0,
  251. borderStyle: 'solid',
  252. borderColor: shelfnewItem[3]?.btnBorderColorTheme,
  253. borderRadius: 4
  254. }}>{shelfnewItem[3]?.btnTitle}</p>
  255. </div>
  256. </div>
  257. })
  258. }
  259. </div>
  260. </div>
  261. </div>
  262. </div>
  263. } else {
  264. return null
  265. }
  266. } else if (value?.elementType === 'IMAGE_TEXT') {
  267. let { imageTextItem, alignMode } = value
  268. let paddingTop = 28, paddingBottom = 28
  269. if (imageTextItem.length === 2) {
  270. return <div className={`compt componentType103}`} key={id}>
  271. <div className={'componentWrap'}>
  272. <div className={'componentContent'}>
  273. <div className='shelf gridType' style={{ marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px', marginLeft: 20 }}>
  274. {imageTextItem?.map((item: any, index1: number) => {
  275. let { bgColor, borderColor, desc, descColor, imageUrl, title, titleColor, subElemType } = item
  276. let key = 'ghSpec'
  277. if (subElemType === 'GH') {
  278. key = 'ghSpec'
  279. } else {
  280. key = 'enterpriseWxSpec'
  281. }
  282. let { btnTitle, btnBgColorTheme, btnBorderColorTheme, fontColor, btnFontType } = item[key]
  283. return <div className='shelfItem-3q' key={index1} style={{ borderWidth: 1, borderStyle: 'solid', borderColor: borderColor, backgroundColor: bgColor || 'rgb(255,255,255)', marginLeft: index1 === 1 ? 11 : 0 }}>
  284. <div className='shelfItemImg' style={{ marginLeft: 5.5, marginTop: 5.5 }}>
  285. {imageUrl ? <img src={imageUrl} style={{ display: 'flex', width: '100%', height: '100%' }} /> : <div className="default" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
  286. <div className={'defaultIcon'} style={{ width: 36, height: 36 }}>
  287. <Img />
  288. </div>
  289. </div>}
  290. </div>
  291. <div className='shelfItemContent' style={{ padding: '0 12px', boxSizing: 'border-box', textAlign: alignMode === 0 ? 'left' : 'center' }}>
  292. <p className='title' style={{ color: titleColor || 'rgb(53, 53, 53)', fontSize: 16, marginBottom: 4 }}>{title || '标题'}</p>
  293. <p className='desc' style={{ color: descColor || 'rgb(178, 178, 178)', marginBottom: 14 }}>{desc || '描述'}</p>
  294. <p className='btn' style={{
  295. textDecoration: 'none',
  296. fontWeight: btnFontType == '1' ? 'bold' : 400,
  297. color: fontColor || 'rgb(255, 255, 255)',
  298. backgroundColor: btnBgColorTheme || 'rgb(7,193,96)',
  299. borderStyle: 'solid',
  300. borderColor: '#FFFFFF', //btnBorderColorTheme,
  301. borderRadius: 4
  302. }}>{btnTitle}</p>
  303. </div>
  304. </div>
  305. })}
  306. </div>
  307. </div>
  308. </div>
  309. </div>
  310. } else {
  311. let { bgColor, borderColor, desc, descColor, imageUrl, title, titleColor, subElemType } = imageTextItem[0]
  312. let key = 'ghSpec'
  313. if (subElemType === 'GH') {
  314. key = 'ghSpec'
  315. } else {
  316. key = 'enterpriseWxSpec'
  317. }
  318. let { btnTitle, btnBgColorTheme, btnBorderColorTheme, fontColor, btnFontType } = imageTextItem[0][key]
  319. return <div className={`compt componentType104`} key={id}>
  320. <div className={'componentWrap'}>
  321. <div className={'componentContent'}>
  322. <div className={'shelf listType'} style={{ marginTop: paddingTop / 2 + 'px', marginBottom: paddingBottom / 2 + 'px', marginLeft: 20, marginRight: 20 }}>
  323. <div className={'shelfItem'} style={{ border: `1px solid ${borderColor || "#e5e5e5"}`, backgroundColor: bgColor || "#ffffff" }}>
  324. <div className={'shelfItemImg'} style={{ marginLeft: 11.5, marginTop: 11.5 }}>
  325. {imageUrl ? <img src={imageUrl} style={{ display: 'flex', width: '100%', height: '100%' }} /> : <div className={'default'} style={{ width: '100%', height: '100%' }}>
  326. <div className={'defaultIcon'} style={{ marginTop: 27, width: 36, height: 36 }}>
  327. <Img />
  328. </div>
  329. </div>}
  330. </div>
  331. <div className={'shelfItemContent'} style={{ margin: '12px 20px 0 12px' }}>
  332. <p className={'title'} style={{ color: titleColor || "#353535", fontSize: 16 }}>{title || '标题'}</p>
  333. <p className={'desc'} style={{ color: descColor || "#B2B2B2" }}>{desc || '描述'}</p>
  334. <div
  335. className={'btn'}
  336. style={{
  337. color: fontColor || 'rgb(255, 255, 255)',
  338. textDecoration: 'none',
  339. fontWeight: btnFontType == '1' ? 'bold' : 'normal',
  340. backgroundColor: btnBgColorTheme || "#07C160",
  341. border: ['#FFFFFF', '#ffffff', 'rgb(255, 255, 255)'].indexOf(btnBorderColorTheme) !== -1 ? '0px solid rgb(255, 255, 255)' : `2px solid ${btnBorderColorTheme}`,
  342. borderRadius: 4
  343. }}
  344. >{btnTitle}</div>
  345. </div>
  346. </div>
  347. </div>
  348. </div>
  349. </div>
  350. </div>
  351. }
  352. } else {
  353. return null
  354. }
  355. })}
  356. {globalData.map((value: any, index: number) => {
  357. if (value?.elementType === 'FLOAT_BUTTON') {
  358. let { titleColor, descColor, componentItem, imageUrl, title, desc, styleType } = value
  359. return <div className={`compt componentType134 comptFixedBottom`} key={'floatbutton' + index}>
  360. <div className={'componentWrap'}>
  361. <div className="componentContent">
  362. <div className="floatButtonWrapper">
  363. <div className="floatButton">
  364. {styleType === 0 && (imageUrl ? <img src={imageUrl} className="floatButtonAvatar" /> : <div className="floatButtonAvatarPlaceholder"></div>)}
  365. <div className="floatButtonTexts">
  366. <div className="floatButtonTitle" style={{ color: titleColor || 'rgb(23, 23, 23)' }}>{title || '标题'}</div>
  367. {(styleType === 1 || styleType === 0) && <div className="floatButtonDesc" style={{ color: descColor || 'rgb(76, 76, 76)' }}>{desc || '描述'}</div>}
  368. </div>
  369. <div className="floatButtonLink" style={{
  370. color: componentItem?.fontColor || 'rgb(255,255,255)',
  371. fontWeight: componentItem?.btnFontType === '0' ? 'normal' : 'bold',
  372. backgroundColor: componentItem?.btnBgColorTheme || 'rgb(7, 193, 96)',
  373. width: ((componentItem?.layoutWidth || 160) / 2) + 'px',
  374. textAlign: 'center',
  375. overflow: 'hidden',
  376. whiteSpace: 'pre'
  377. }}>{componentItem?.btnTitle}</div>
  378. </div>
  379. </div>
  380. </div>
  381. </div>
  382. </div>
  383. }
  384. return null
  385. })}
  386. </div>
  387. }
  388. }
  389. return <Drawer
  390. title="查看"
  391. placement="right"
  392. closable={false}
  393. onClose={() => { onClose && onClose() }}
  394. visible={visible}
  395. width={420}
  396. >
  397. <Spin spinning={get.loading}>
  398. <div className={style.page} style={{ backgroundColor: pageBackColor || '#FFFFFF' }}>
  399. {/* 头部 */}
  400. {topCon}
  401. {/* 内容*/}
  402. <div className={`comptPlaceholder lastChild`} id="comptCon">
  403. {comptCon()}
  404. </div>
  405. </div>
  406. </Spin>
  407. </Drawer>
  408. }
  409. export default React.memo(LookLanding)