index.tsx 164 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298
  1. import { Button, Checkbox, Col, Drawer, Form, Input, InputNumber, message, Modal, Radio, RadioChangeEvent, Row, Select, Slider, Space, Spin, Switch, Tooltip } from 'antd'
  2. import React, { useCallback, useEffect, useMemo, useState } from "react"
  3. import modal from "antd/lib/modal"
  4. import style from './index.less'
  5. import './index1.less'
  6. import { ReactComponent as Topimg } from '@/assets/topimg.svg'
  7. import { ReactComponent as Topslider } from '@/assets/topslider.svg'
  8. import { ReactComponent as Topvideo } from '@/assets/topvideo.svg'
  9. import { ReactComponent as Img } from '@/assets/img.svg'
  10. import { ReactComponent as MyText } from '@/assets/text.svg'
  11. import { ReactComponent as TopNullBack } from '@/assets/topNullBack.svg'
  12. import { ReactComponent as FollowAcc } from '@/assets/followAcc.svg'
  13. import { ReactComponent as EditSvg } from '@/assets/edit.svg'
  14. import { ReactComponent as SliderImgSvg } from '@/assets/sliderImgSvg.svg'
  15. import { ReactComponent as JumpLink } from '@/assets/jumpLink.svg'
  16. import { ReactComponent as ImgText } from '@/assets/imgText.svg'
  17. import { ReactComponent as FloatbuttonSvg } from '@/assets/floatbuttonSvg.svg'
  18. import { ReactComponent as WxAutoSvg } from '@/assets/wxAutoSvg.svg'
  19. import { AlignCenterOutlined, AlignLeftOutlined, AlignRightOutlined, DeleteOutlined, PlusOutlined, QuestionCircleOutlined, RetweetOutlined, SwapLeftOutlined, SwapRightOutlined } from '@ant-design/icons'
  20. import { useDrop, useDrag } from 'ahooks'
  21. import arrayMove from "array-move";
  22. import ColorPicker from '@/components/ColorPicker1'
  23. import TextArea from 'antd/lib/input/TextArea'
  24. import moment from 'moment'
  25. import { TopImg, TopVideo, Text, Img as ImgProps, GhButton, TopSlider, LinkButton, Shelfnew, WxAutoButton, Floatbutton } from '../../req'
  26. import { imgContent, txtContent, ghContent, topvideoNewContent, linkContent, topsliderContent, topimgContent, topvideoContent, shelfnewContent, shelfnewContent2, btModelJumpGh, btModelJumpLink, btModelJumpLink103, btModelJumpGh103, jumpLink104, jumpGh104, jumpLink103, jumpGh103, wxAutoContent, jumpWxAuto104, jumpWxAuto103, btModelJumpWxAuto, btModelJumpWxAuto103, floatbuttonContent, floatbuttonBtTypeWxAuto, floatbuttonBtTypeGh } from './content'
  27. import { landingPageReducer, Content, Props } from './landingPageReducer'
  28. import {
  29. SortableList,
  30. SortableItemText,
  31. SortableItemImg,
  32. SortableItemFollowAcc,
  33. SortableItemImgText,
  34. SortableUlList,
  35. SortableItemNoLi,
  36. SortableItemLi,
  37. SortableItemJumpLink,
  38. SortableItemWxAuto,
  39. SortableItemFloatbutton
  40. } from './sortable'
  41. import { useModel } from 'umi'
  42. import SelectCloud from '../selectCloud'
  43. import { getTypeKey, txtLength } from '@/utils/utils'
  44. const { Option } = Select;
  45. function AddLandingPage(props: Props) {
  46. let { visible, hideModal, ajax, id } = props
  47. const { state, stateGlobal, dispatch, dispatchGlobal } = landingPageReducer()
  48. const { content, pageBackColor } = state
  49. const { componentItem } = stateGlobal
  50. const { currentUser }: any = useModel('@@initialState', model => ({ currentUser: model.initialState?.currentUser }))
  51. const { init, add, get } = useModel('useLaunchAdq.useBdMediaPup')
  52. const { state: { parentId, belongUser } } = useModel('useLaunchAdq.useBdMedia')
  53. /** 变量开始 */
  54. const [selectImgVisible, setSelectImgVisible] = useState<boolean>(false) // 选择图片弹窗
  55. const [lastVisible, setLastVisible] = useState<boolean>(false) // 最后保存设置
  56. const [shareTittle, setShareTittle] = useState<string>('') // 分享标题
  57. const [shareDesc, setShareDesc] = useState<string>('') // 分享描述
  58. const [pageName, setPageName] = useState<string>('') // 落地页名称
  59. const [sort, setSort] = useState<number>(0) // 排序
  60. const [imgSize, setImgSize] = useState<{
  61. aspectRatio?: string, //宽高比
  62. minWidth?: string, //最小宽度
  63. maxWidth?: string, //最大宽度
  64. minHeight?: string, //最小高度
  65. maxHeight?: string, //最大高度
  66. minMediaSize?: number, // 最小媒体大小
  67. maxMediaSize?: number, // 最大媒体大小
  68. minVideoLength?: number, // 最小视频时长
  69. maxVideoLength?: number, // 最大视频时长
  70. minVideoBitRate?: number, // 最小视频比特率
  71. maxVideoBitRate?: number, // 最大视频比特率
  72. mediaType?: 'IMG' | 'VIDEO' | 'PAGE', // 内容类型 1 图片 2 视频
  73. }>({}) // 要选择的素材信息
  74. const [isFootlock, setIsFootlock] = useState<boolean>(false) // 是否横板视频
  75. const [scType, setCcType] = useState<1 | 2 | 3 | 4 | 5>(1) // 视频 单图片 多图片处理
  76. const [sliderImgContent, setSliderImgContent] = useState<{ url: string, width?: number, height?: number }[]>([]) // 保存回填数据
  77. const [imgTextButtonShow, setImgTextButtonShow] = useState<boolean>(false)
  78. const [goodsCount, setGoodsCount] = useState<number>(0)
  79. /** 变量结束 */
  80. // console.log('content---->', content)
  81. // 回填
  82. useEffect(() => {
  83. if (id) {
  84. get.run({ sysMediaId: id, mediaType: 'PAGE' }).then(res => {
  85. if (res) {
  86. const { pageSpecsList, shareContentSpec, globalSpec } = res
  87. dispatch({ type: 'setPageBackColor', params: { pageBackColor: pageSpecsList[0]?.bgColor } })
  88. let pageElementsSpecList = pageSpecsList[0]?.pageElementsSpecList
  89. dispatch({
  90. type: 'setCon', params: {
  91. content: pageElementsSpecList?.map((item: any) => {
  92. let typeKey = getTypeKey(item?.elementType)
  93. if (typeKey) {
  94. let data = item[typeKey] || {}
  95. return {
  96. elementType: item?.elementType,
  97. ...data
  98. }
  99. }
  100. return item
  101. })
  102. }
  103. })
  104. setShareDesc(() => shareContentSpec?.shareTitle || '')
  105. setShareTittle(() => shareContentSpec?.shareDescription || '')
  106. if (globalSpec && Object.keys(globalSpec).length > 0) {
  107. let globalElementsSpecList = globalSpec.globalElementsSpecList
  108. let newComponentItem = globalElementsSpecList?.map((item: { elementType: string }) => {
  109. let typeKey = getTypeKey(item.elementType)
  110. let { elementType, ...data } = item[typeKey]
  111. let typeKey1 = getTypeKey(elementType)
  112. let componentItem: any = data[typeKey1]
  113. if (componentItem) {
  114. componentItem['elementType'] = elementType
  115. }
  116. data.componentItem = componentItem
  117. data.elementType = item.elementType
  118. delete data[typeKey1]
  119. return data
  120. })
  121. dispatchGlobal({ type: "setConItem", params: { componentItem: newComponentItem || [] } })
  122. }
  123. }
  124. })
  125. } else {
  126. // dispatch({ type: 'init', params: { elementType: 'empty' } })
  127. }
  128. }, [id])
  129. console.log('componentItem------>', componentItem);
  130. const config = {
  131. title: '警告!',
  132. cancelText: '取消',
  133. okText: '确定',
  134. onOk: () => { hideModal() },
  135. content: (
  136. <>
  137. <div>不会保存您所做的更改,确定关闭?</div>
  138. </>
  139. ),
  140. };
  141. /** 获取选中内容对应图片视频尺寸大小 */
  142. useEffect(() => {
  143. let selectData = content?.find((item: Content) => item.comptActive)
  144. if (!selectData) {
  145. selectData = componentItem?.find((item: { comptActive: boolean }) => item.comptActive)
  146. }
  147. if (selectData?.elementType === "TOP_IMAGE") {
  148. setIsFootlock(() => false)
  149. if (selectData?.adLocation === 'sns') { // 朋友圈信息流
  150. if (selectData?.outerStyle === 0) { // 常规广告
  151. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 800, height: 800 }]], maxSize: 300 * 1024 })
  152. } else { // 卡片广告
  153. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 800, height: 450 }]], maxSize: 300 * 1024 })
  154. }
  155. } else { // 公众号及其他
  156. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 800, height: 800 }], [{ relation: '=', width: 800, height: 450 }], [{ relation: '=', width: 800, height: 640 }], [{ relation: '=', width: 640, height: 800 }]], maxSize: 300 * 1024 })
  157. }
  158. } else if (selectData?.elementType === 'IMAGE') { // 内容图片
  159. setIsFootlock(() => false)
  160. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 750, height: null }, { relation: '<=', width: null, height: 1536 }]], maxSize: 300 * 1024 })
  161. } else if (selectData?.elementType === 'TOP_SLIDER') { // 轮播图
  162. init({ mediaType: 'IMG', num: selectData?.imageUrlList?.length || 3, cloudSize: [[{ relation: '=', width: 800, height: 800 }]], maxSize: 300 * 1024 })
  163. setIsFootlock(() => false)
  164. } else if (selectData?.elementType === 'TOP_VIDEO') { // 视频
  165. if (selectData?.adLocation === 'sns') { // 朋友圈信息流
  166. if (selectData?.outerStyle === 0) { // 常规广告
  167. init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: 640, height: 480 }], [{ relation: '=', width: 640, height: 360 }], [{ relation: '=', width: 750, height: 1334 }], [{ relation: '=', width: 720, height: 1280 }]], maxSize: 20 * 1024 * 1024 })
  168. } else { // 卡片广告
  169. init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: 750, height: null }, { relation: '<=', width: null, height: 1536 }]], maxSize: 20 * 1024 * 1024 })
  170. }
  171. } else { // 公众号及其它
  172. init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: 750, height: null }, { relation: '<=', width: null, height: 1536 }]], maxSize: 20 * 1024 * 1024 })
  173. setIsFootlock(() => false)
  174. }
  175. } else if (selectData?.elementType === 'shelfnew') { // 图文复合组件 1个
  176. if (selectData?.type === '104') {
  177. setIsFootlock(() => false)
  178. setImgSize(() => ({ minWidth: '360', maxWidth: '360', minHeight: '360', maxHeight: '360', minMediaSize: 0, maxMediaSize: 307200, mediaType: 'IMG' }))
  179. } else if (selectData?.type === '103') {
  180. setIsFootlock(() => false)
  181. setImgSize(() => ({ minWidth: '480', maxWidth: '480', minHeight: '480', maxHeight: '480', minMediaSize: 0, maxMediaSize: 307200, mediaType: 'IMG' }))
  182. }
  183. } else if (selectData?.elementType === 'FLOAT_BUTTON') {
  184. setIsFootlock(() => false)
  185. init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: 96, height: 96 }]], maxSize: 300 * 1024 })
  186. }
  187. }, [content])
  188. const [dragging, setDragging] = useState<string | null>(null);
  189. const getDragProps = useDrag({
  190. onDragStart: (data) => {
  191. setDragging(data);
  192. },
  193. onDragEnd: () => {
  194. setDragging(null);
  195. },
  196. });
  197. // 头部内容拖到接收区
  198. const [dropProps] = useDrop({
  199. onDom: (con: string, e) => { // 头部
  200. let newCon = content?.map((item: TopImg | TopVideo | TopSlider) => {
  201. return { ...item, comptActive: false }
  202. })
  203. let topCon = newCon[0]
  204. topCon.type = con
  205. topCon.comptActive = true
  206. let conContent: TopImg | TopVideo | TopSlider
  207. if (con === 'TOP_SLIDER') {
  208. conContent = { ...topsliderContent, comptActive: true } as TopSlider
  209. } else if (con === 'TOP_IMAGE') {
  210. conContent = { ...topimgContent, comptActive: true } as TopImg
  211. } else if (con === 'TOP_VIDEO') {
  212. conContent = { ...topvideoNewContent, comptActive: true } as TopVideo
  213. } else {
  214. return
  215. }
  216. topCon = { ...conContent }
  217. newCon[0] = topCon
  218. dispatch({ type: 'setCon', params: { content: newCon } })
  219. },
  220. });
  221. const [draggingCon, setDraggingCon] = useState<string | null>(null);
  222. const getDragPropsCon = useDrag({
  223. onDragStart: (data) => {
  224. setDraggingCon(data);
  225. },
  226. onDragEnd: () => {
  227. setDraggingCon(null);
  228. },
  229. });
  230. // 内容拖到接收区
  231. const [dropConProps, { isHovering: isHoveringCon }] = useDrop({
  232. onDom: (con: string, e) => { // 内容
  233. let newCon: Content[] = content?.map((item: Text | ImgProps | GhButton) => { // | LinkButton | WxAutoButton
  234. return { ...item, comptActive: false }
  235. })
  236. let newConItem = componentItem?.map((item: Floatbutton) => {
  237. return { ...item, comptActive: false }
  238. })
  239. if (con === 'TEXT') {
  240. newCon.push({ ...txtContent, comptActive: true } as any)
  241. } else if (con === 'IMAGE') {
  242. newCon.push({ ...imgContent, comptActive: true } as any)
  243. } else if (con === 'GH') {
  244. newCon.push({ ...ghContent, comptActive: true } as any)
  245. // } else if (con === 'JumpLink') {
  246. // newCon.push({ ...linkContent, comptActive: true } as any)
  247. // } else if (con === 'shelfnew') {
  248. // newCon.push({ ...shelfnewContent, comptActive: true } as any)
  249. } else if (con === 'ENTERPRISE_WX') {
  250. newCon.push({ ...wxAutoContent, comptActive: true } as any)
  251. } else if (con === 'FLOAT_BUTTON') {
  252. newConItem.push({ ...floatbuttonContent, comptActive: true })
  253. setDraggingCon(null);
  254. } else {
  255. return
  256. }
  257. dispatch({ type: 'setCon', params: { content: newCon } })
  258. dispatchGlobal({ type: "setConItem", params: { componentItem: newConItem } })
  259. },
  260. });
  261. /** 选中设置 */
  262. const installActive = useCallback((e, index: number) => {
  263. e.stopPropagation(); e.preventDefault();
  264. let newCon = content?.map((item: any) => {
  265. return { ...item, comptActive: false }
  266. })
  267. let newConItem = componentItem?.map((item: { elementType: string }) => {
  268. return { ...item, comptActive: false }
  269. })
  270. setImgTextButtonShow(false)
  271. if (index === 99999) {
  272. newConItem = newConItem?.map((item: { elementType: string }) => {
  273. if (item.elementType === 'FLOAT_BUTTON') {
  274. return { ...item, comptActive: true }
  275. }
  276. return item
  277. })
  278. } else {
  279. newCon[index].comptActive = true
  280. }
  281. dispatch({ type: 'setCon', params: { content: newCon } })
  282. dispatchGlobal({ type: "setConItem", params: { componentItem: newConItem } })
  283. }, [content, imgTextButtonShow, componentItem])
  284. /** 清除选中 */
  285. const installActiveNull = useCallback((e) => {
  286. e.stopPropagation(); e.preventDefault();
  287. let newCon = content?.map((item: any) => {
  288. return { ...item, comptActive: false }
  289. })
  290. setImgTextButtonShow(false)
  291. dispatch({ type: 'setCon', params: { content: newCon } })
  292. let newConItem = componentItem?.map((item: { widgetTypeV2: string }) => {
  293. return { ...item, comptActive: false }
  294. })
  295. dispatchGlobal({ type: "setConItem", params: { componentItem: newConItem } })
  296. }, [content])
  297. /** 内容功能按钮区 */
  298. const handleBtn = useCallback((type: string, index: number) => {
  299. let newContent = JSON.parse(JSON.stringify(content))
  300. switch (type) {
  301. case 'lower': // 下移动
  302. dispatch({ type: 'setCon', params: { content: arrayMove(content, index, index + 1) } })
  303. break;
  304. case 'upper': // 上移动
  305. dispatch({ type: 'setCon', params: { content: arrayMove(content, index, index - 1) } })
  306. break;
  307. case 'IMAGE': // 图片
  308. newContent.splice(index, 0, { ...imgContent });
  309. dispatch({ type: 'setCon', params: { content: newContent } })
  310. break;
  311. case 'TEXT': // 文本
  312. newContent.splice(index, 0, { ...txtContent });
  313. dispatch({ type: 'setCon', params: { content: newContent } })
  314. break;
  315. case 'GH': // 关注公众号按钮
  316. newContent.splice(index, 0, { ...ghContent });
  317. dispatch({ type: 'setCon', params: { content: newContent } })
  318. break;
  319. // case 'link': // 跳转链接按钮
  320. // newContent.splice(index, 0, { ...linkContent });
  321. // dispatch({ type: 'setCon', params: { content: newContent } })
  322. // break;
  323. // case 'shelfnew': // 图文复合组件
  324. // newContent.splice(index, 0, { ...shelfnewContent });
  325. // dispatch({ type: 'setCon', params: { content: newContent } })
  326. // break;
  327. case 'ENTERPRISE_WX': // 图文复合组件
  328. newContent.splice(index, 0, { ...wxAutoContent });
  329. dispatch({ type: 'setCon', params: { content: newContent } })
  330. break;
  331. }
  332. }, [content])
  333. /** 头部删除 */
  334. const topDelType = useCallback(() => {
  335. setDragging(null);
  336. content[0] = {
  337. elementType: 'empty',
  338. comptActive: false
  339. }
  340. dispatch({ type: 'setCon', params: { content } })
  341. }, [content, dragging])
  342. /** 内容删除 */
  343. const delType = useCallback((e, index: number) => {
  344. e.stopPropagation(); e.preventDefault();
  345. setImgTextButtonShow(false)
  346. if (index === 99999) { // 删除悬浮组件
  347. let newContentItem = JSON.parse(JSON.stringify(componentItem))
  348. newContentItem = newContentItem?.filter((item: { elementType: string }) => item.elementType !== 'FLOAT_BUTTON')
  349. dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(newContentItem)) } })
  350. } else {
  351. let newContent = JSON.parse(JSON.stringify(content))
  352. newContent?.splice(index, 1)
  353. dispatch({ type: 'setCon', params: { content: JSON.parse(JSON.stringify(newContent)) } })
  354. }
  355. }, [content, componentItem, imgTextButtonShow])
  356. const onSortEnd = ({ oldIndex, newIndex }: { oldIndex: number, newIndex: number }) => {
  357. dispatch({ type: 'setCon', params: { content: arrayMove(content, oldIndex, newIndex) } })
  358. }
  359. // 基础内容
  360. const comptCon = () => {
  361. if (content?.length === 0) {
  362. return null
  363. } else {
  364. return <SortableList axis='y' onSortEnd={onSortEnd} useDragHandle isFloatButton={componentItem?.some((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON')}>
  365. {content.map((value: Text | ImgProps | GhButton, index: number) => {
  366. if (value?.elementType === 'IMAGE') {
  367. return <SortableItemImg key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} upload={(num: number) => { clickUpdateImg(num) }} handleBtn={handleBtn} />
  368. } else if (value?.elementType === 'TEXT') {
  369. return <SortableItemText key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} pageBackColor={pageBackColor} handleBtn={handleBtn} />
  370. } else if (value?.elementType === 'GH') {
  371. return <SortableItemFollowAcc key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} handleBtn={handleBtn} />
  372. } else if (value?.elementType === 'ENTERPRISE_WX') {
  373. return <SortableItemWxAuto key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} handleBtn={handleBtn} />
  374. // } else if (value?.elementType === 'link') {
  375. // return <SortableItemJumpLink key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} handleBtn={handleBtn} />
  376. // } else if (value?.elementType === 'shelfnew') {
  377. // return <SortableItemImgText key={`item-${value.elementType}-${index}`} index={index} data={{ length: content?.length, index }} item={value} click={(e: any) => { installActive(e, index) }} del={(e: any) => { delType(e, index) }} handleBtn={handleBtn} />
  378. } else {
  379. return null
  380. }
  381. })}
  382. <div className={`comptCon ${isHoveringCon && 'hovering'} ${draggingCon && 'draggingCon'}`} {...dropConProps}>{(isHoveringCon || draggingCon) && '请拖至此处'}</div>
  383. {componentItem?.some((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON') && <SortableItemFloatbutton index={99999} item={componentItem.find((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON')} click={(e: any) => { installActive(e, 99999) }} del={(e: any) => { delType(e, 99999) }} />}
  384. </SortableList>
  385. }
  386. }
  387. /** 设置start */
  388. const setCon = useCallback((key: string, value: any, isTopImg?: boolean) => {
  389. let newContent = JSON.parse(JSON.stringify(content))
  390. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  391. let oldContent = newContent
  392. if (selectIndex !== -1) {
  393. let selectCon = oldContent[selectIndex]
  394. selectCon[key] = value
  395. if (selectCon?.elementType === 'TOP_VIDEO' && (key === 'adLocation' || key === 'outerStyle')) {
  396. selectCon['videoUrl'] = ''
  397. }
  398. let newSelectCon = { ...selectCon }
  399. oldContent[selectIndex] = newSelectCon
  400. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  401. }
  402. }, [content, goodsCount])
  403. /** 设置end */
  404. // 顶部组件
  405. const topCon = useMemo(() => {
  406. let { imageUrl, elementType, activeIndex, imageUrlList, videoUrl } = content[0]
  407. return <>
  408. {
  409. elementType === 'TOP_IMAGE' ? <>
  410. <div className={`compt componentType41 ${content[0]?.comptActive && 'comptActive'}`} onClick={(e) => { installActive(e, 0) }}>
  411. <div className={'componentWrap'}>
  412. <div className={'componentContent'}>
  413. {
  414. imageUrl ? <img src={imageUrl} style={{ display: 'block', width: '100%', margin: 0 }} /> : <div className={'default'} style={{ width: 375, height: 300, margin: 0 }}>
  415. <div className={'defaultIcon'} style={{ marginTop: 80 }}>
  416. <Topimg />
  417. </div>
  418. </div>
  419. }
  420. </div>
  421. </div>
  422. {
  423. !imageUrl && <div className={'comptUpload'} style={{ margin: 0 }}>
  424. <button style={{ marginTop: 150 }} className={'comptEditButton'} onClick={() => { clickUpdateImg(1) }}>上传图片</button>
  425. </div>
  426. }
  427. <section className={'comptEditBtns'}>
  428. <div className={'comptEditBtnsInner'}>
  429. {imageUrl && <button onClick={() => { editSelectImg(imageUrl) }}><EditSvg /></button>}
  430. <button onClick={topDelType}><DeleteOutlined /></button>
  431. </div>
  432. </section>
  433. </div>
  434. </> :
  435. elementType === 'TOP_SLIDER' ? <>
  436. <div className={`compt componentType101 ${content[0]?.comptActive && 'comptActive'}`} onClick={(e) => { installActive(e, 0) }}>
  437. <div className={'componentWrap'}>
  438. <div className={'componentContent'}>
  439. {imageUrlList?.length > 0 ? <div style={{ position: 'relative', width: 375, height: 375 }}>
  440. {imageUrlList?.map((imgUrl: any, index: number) => {
  441. if (imgUrl) {
  442. return <img src={imgUrl} key={index} style={{ maxWidth: '100%', position: 'absolute', display: 'block', zIndex: activeIndex === index ? 1 : 0 }} />
  443. } else {
  444. return <div className="default" key={index} style={{ width: 375, zIndex: activeIndex === index ? 1 : 0, height: '100%', position: 'absolute', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  445. <div className="defaultIcon">
  446. <SliderImgSvg />
  447. </div>
  448. </div>
  449. }
  450. })}
  451. <div className={'sliderD'}>
  452. {imageUrlList.map((item: any, index: number) => <i key={index} style={activeIndex === index ? { backgroundColor: 'rgba(0, 0, 0, .4)' } : {}}></i>)}
  453. </div>
  454. </div> : <div style={{ position: 'relative', height: 222, width: 375 }} className={'sliderCon'}>
  455. <div className={'default'}>
  456. <div className={'defaultIcon'}>
  457. <Topslider />
  458. </div>
  459. </div>
  460. <div className={'sliderD'}>
  461. {imageUrlList.fill('').map((item: any, index: number) => <i key={index} style={activeIndex === index ? { backgroundColor: 'rgba(0, 0, 0, .4)' } : {}}></i>)}
  462. </div>
  463. </div>}
  464. </div>
  465. </div>
  466. <section className={'comptEditBtns'}>
  467. <div className={'comptEditBtnsInner'}>
  468. <button onClick={topDelType}><DeleteOutlined /></button>
  469. </div>
  470. </section>
  471. </div>
  472. </> :
  473. elementType === 'TOP_VIDEO' ? <>
  474. <div className={`compt componentType61 ${content[0]?.comptActive && 'comptActive'}`} onClick={(e) => { installActive(e, 0) }}>
  475. <div className={'componentWrap'}>
  476. <div className={'componentContent'}>
  477. {
  478. videoUrl ? <div className="videoPlay">
  479. <video src={videoUrl} style={{ display: 'block', width: '100%', margin: 0 }} />
  480. <span></span>
  481. </div>
  482. : <div className={'default'} style={{ width: 375, height: 300, margin: 0 }}>
  483. <div className={'defaultIcon'} style={{ marginTop: 80 }}>
  484. <Topvideo />
  485. </div>
  486. </div>
  487. }
  488. </div>
  489. </div>
  490. {!videoUrl && <div className={'comptUpload'} style={{ margin: 0 }}>
  491. <button style={{ marginTop: 150 }} className={'comptEditButton'} onClick={() => { clickUpdateVideo() }}>上传视频</button>
  492. </div>}
  493. <section className={'comptEditBtns'}>
  494. <div className={'comptEditBtnsInner'}>
  495. {videoUrl && <button onClick={() => { clickUpdateVideo() }}><EditSvg /></button>}
  496. <button onClick={topDelType}><DeleteOutlined /></button>
  497. </div>
  498. </section>
  499. </div>
  500. </> :
  501. <div className={`compt topComptArea ${dragging ? 'dragging' : ''}`} {...dropProps}>
  502. <TopNullBack />
  503. {dragging ? <div className="topAreaTitle" style={{ marginTop: 30 }}>
  504. 拖至此处
  505. </div> : <>
  506. <p className={'topAreaTitle'}>顶部组件区</p>
  507. <div className={'desc'}>在左上方,选择顶部组件添加到此处</div>
  508. </>}
  509. </div>
  510. }
  511. </>
  512. }, [content, state, dragging])
  513. /** 图标开启与关闭 */
  514. const iconHandle = (e: boolean) => {
  515. let newContent = JSON.parse(JSON.stringify(content))
  516. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  517. let oldContent = newContent
  518. if (selectIndex !== -1) {
  519. let selectCon = oldContent[selectIndex]
  520. selectCon['useIcon'] = e ? 1 : 0
  521. oldContent[selectIndex] = selectCon
  522. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  523. }
  524. }
  525. /** 视频切换广告位 */
  526. const changeAdLocation = (value: 'sns' | 'gh') => {
  527. let newContent = JSON.parse(JSON.stringify(content))
  528. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  529. let oldContent = newContent
  530. if (selectIndex !== -1) {
  531. let selectCon = oldContent[selectIndex]
  532. selectCon['adLocation'] = value
  533. if (value === 'gh') {
  534. selectCon['styleType'] = 1
  535. } else {
  536. selectCon['styleType'] = 0
  537. }
  538. selectCon['videoUrl'] = ''
  539. oldContent[selectIndex] = selectCon
  540. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  541. }
  542. }
  543. /** 视频切换外层样式 */
  544. const changeOuterLayout = (value: string) => {
  545. let newContent = JSON.parse(JSON.stringify(content))
  546. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  547. let oldContent = newContent
  548. if (selectIndex !== -1) {
  549. let selectCon = oldContent[selectIndex]
  550. selectCon['viewType'] = value
  551. let newSelectCon: any
  552. if (value === '0') {
  553. let { outerUseTopMaterial, streamDisplayWidth, streamDisplayHeight, streamVideoThumb, streamVideoUrl, streamDisplayType, streamThumbMd5, streamVideoMd5, displayType, ...clearSelectCon } = selectCon
  554. newSelectCon = {
  555. ...clearSelectCon
  556. }
  557. } else {
  558. newSelectCon = {
  559. ...selectCon,
  560. outerUseTopMaterial: '0',
  561. styleType: '0'
  562. }
  563. }
  564. oldContent[selectIndex] = newSelectCon
  565. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  566. }
  567. }
  568. /** 轮播图选择点击切换图片 多张图片 */
  569. const sliderSelect = (index: number, count: number) => {
  570. let newContent = JSON.parse(JSON.stringify(content))
  571. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  572. if (selectIndex !== -1) {
  573. let selectCon = newContent[selectIndex]
  574. let imgList: any[] = []
  575. selectCon?.imageUrlList?.forEach((item: string) => {
  576. if (item) {
  577. imgList.push({ url: item })
  578. }
  579. })
  580. setSliderImgContent(imgList)
  581. }
  582. setCon('activeIndex', index)
  583. setCcType(3)
  584. setSelectImgVisible(true)
  585. }
  586. /** 轮播图图片数量设置 */
  587. const sliderImgNum = useCallback((num: string) => {
  588. let newContent = JSON.parse(JSON.stringify(content))
  589. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  590. let oldContent = newContent
  591. if (selectIndex !== -1) {
  592. let selectCon = oldContent[selectIndex]
  593. let { imageUrlList } = selectCon
  594. if (imageUrlList?.length > Number(num)) { // 减少
  595. selectCon['imageUrlList'] = [...imageUrlList?.splice(0, Number(num))]
  596. } else { // 增加
  597. let newGroup = Array(Number(num) - imageUrlList?.length).fill('').map(() => "")
  598. imageUrlList = [...imageUrlList, ...newGroup]
  599. selectCon['imageUrlList'] = imageUrlList
  600. }
  601. oldContent[selectIndex] = { ...selectCon }
  602. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  603. }
  604. }, [content])
  605. /** 轮播图位置拖动切换顺序 */
  606. const onSortEndSlider = useCallback(({ oldIndex, newIndex }: { oldIndex: number, newIndex: number }) => {
  607. let newContent = JSON.parse(JSON.stringify(content))
  608. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  609. let oldContent = newContent
  610. if (selectIndex !== -1) {
  611. let selectCon = oldContent[selectIndex]
  612. let { imageUrlList } = selectCon
  613. imageUrlList = arrayMove(imageUrlList, oldIndex, newIndex)
  614. selectCon['imageUrlList'] = imageUrlList
  615. oldContent[selectIndex] = { ...selectCon }
  616. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  617. }
  618. }, [content])
  619. /** 图文单个设置 */
  620. const onShelfnewTxtCon = useCallback((value: string, count: number, parameter: string) => {
  621. let newContent = JSON.parse(JSON.stringify(content))
  622. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  623. let oldContent = newContent
  624. if (selectIndex !== -1) {
  625. let selectCon = oldContent[selectIndex]
  626. if (selectCon?.type === '103') {
  627. let componentItem = selectCon?.layoutItems.componentItem[goodsCount]
  628. let shelfnewItem = componentItem?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  629. shelfnewItem[count + 1][parameter] = value
  630. if (count + 1 === 2 && parameter === 'content') {
  631. if (shelfnewItem[count + 1]?.name === '价格') {
  632. shelfnewItem[count + 1][parameter] = '¥' + value
  633. } else {
  634. shelfnewItem[count + 1][parameter] = value
  635. }
  636. }
  637. } else if (selectCon?.type === '104') {
  638. let componentItem = selectCon?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  639. let textData = componentItem[1]?.layoutItems?.componentItem
  640. textData[count][parameter] = value
  641. if (count === 1 && parameter === 'content') {
  642. let name = textData[count]?.name
  643. if (name === '价格') {
  644. textData[count][parameter] = '¥' + value
  645. } else {
  646. textData[count][parameter] = value
  647. }
  648. }
  649. }
  650. oldContent[selectIndex] = { ...selectCon }
  651. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  652. }
  653. }, [content, goodsCount])
  654. /** 设置描述类型 */
  655. const onSetShelfnewDescType = useCallback((e: RadioChangeEvent) => {
  656. let newContent = JSON.parse(JSON.stringify(content))
  657. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  658. let oldContent = newContent
  659. if (selectIndex !== -1) {
  660. let selectCon = oldContent[selectIndex]
  661. if (selectCon?.type === '103') {
  662. let componentItem = selectCon?.layoutItems.componentItem[goodsCount]
  663. let shelfnewItem = componentItem?.layoutItems?.componentItem[0]
  664. shelfnewItem.descType = e.target.value
  665. let textData = shelfnewItem?.layoutItems?.componentItem
  666. if (e.target.value === 'price') {
  667. textData[2] = {
  668. ...textData[2],
  669. name: '价格',
  670. content: '',
  671. fontColor: '#353535',
  672. fontSize: '32',
  673. showType: "1",
  674. }
  675. } else {
  676. let { showType, ...desc } = textData[2]
  677. textData[2] = {
  678. ...desc,
  679. name: '描述',
  680. content: '',
  681. fontColor: '#4D4D4D',
  682. fontSize: '24'
  683. }
  684. }
  685. } else if (selectCon?.type === '104') {
  686. let componentItem = selectCon?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  687. componentItem[1].descType = e.target.value
  688. let textData = componentItem[1]?.layoutItems?.componentItem
  689. if (e.target.value === 'price') {
  690. textData[1] = {
  691. ...textData[1],
  692. name: '价格',
  693. content: '',
  694. fontColor: '#353535',
  695. fontSize: '32',
  696. showType: "1",
  697. }
  698. } else {
  699. let { showType, ...desc } = textData[1]
  700. textData[1] = {
  701. ...desc,
  702. name: '描述',
  703. content: '',
  704. fontColor: '#4D4D4D',
  705. fontSize: '24'
  706. }
  707. }
  708. }
  709. oldContent[selectIndex] = { ...selectCon }
  710. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  711. }
  712. }, [content, goodsCount])
  713. /** 设置跳转方式 */
  714. const onSetShelfnewJumpMode = useCallback((e: RadioChangeEvent) => {
  715. let newContent = JSON.parse(JSON.stringify(content))
  716. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  717. let oldContent = newContent
  718. if (selectIndex !== -1) {
  719. let selectCon = oldContent[selectIndex]
  720. if (selectCon?.type === '103') {
  721. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].jumpMode = e.target.value
  722. let jumpData = selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3]
  723. let widgetTypeV2 = jumpData?.widgetTypeV2
  724. let componentItem = selectCon?.layoutItems?.componentItem[goodsCount]?.layoutItems?.componentItem
  725. if (e.target.value === 'btn_jump') {
  726. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem = [{ ...componentItem[0] }]
  727. } else {
  728. switch (widgetTypeV2) {
  729. case 'link':
  730. componentItem[1] = { ...btModelJumpLink103, origBtnJumpUrl: jumpData?.origBtnJumpUrl }
  731. break
  732. case 'gh':
  733. componentItem[1] = { ...btModelJumpGh103, subType: jumpData?.subType, btnFontType: jumpData?.btnFontType }
  734. break
  735. case 'enterprise_wx_auto':
  736. componentItem[1] = { ...btModelJumpWxAuto103, subType: jumpData?.subType, btnFontType: jumpData?.btnFontType }
  737. break
  738. }
  739. }
  740. } else if (selectCon?.type === '104') {
  741. selectCon.layoutItems.componentItem[0].jumpMode = e.target.value
  742. let textData = selectCon?.layoutItems?.componentItem[0]?.layoutItems?.componentItem[1]?.layoutItems?.componentItem
  743. let widgetTypeV2 = textData[2].widgetTypeV2
  744. let componentItem = selectCon?.layoutItems?.componentItem
  745. if (e.target.value === 'btn_jump') {
  746. selectCon.layoutItems.componentItem = [{ ...componentItem[0] }]
  747. } else {
  748. switch (widgetTypeV2) {
  749. case 'link':
  750. componentItem[1] = { ...btModelJumpLink, origBtnJumpUrl: textData[2]?.origBtnJumpUrl }
  751. break
  752. case 'gh':
  753. componentItem[1] = { ...btModelJumpGh, subType: textData[2]?.subType, btnFontType: textData[2]?.btnFontType }
  754. break
  755. case 'enterprise_wx_auto':
  756. componentItem[1] = { ...btModelJumpWxAuto, subType: textData[2]?.subType, btnFontType: textData[2]?.btnFontType }
  757. break
  758. }
  759. }
  760. }
  761. oldContent[selectIndex] = { ...selectCon }
  762. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  763. }
  764. }, [content, goodsCount])
  765. // 设置图文跳转链接按钮
  766. const onSetShelfnewButton = useCallback((value: string) => {
  767. let newContent = JSON.parse(JSON.stringify(content))
  768. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  769. let oldContent = newContent
  770. if (selectIndex !== -1) {
  771. let selectCon = oldContent[selectIndex]
  772. // "btn_jump" "total_jump"
  773. if (selectCon?.type === '103') {
  774. let jumpMode = selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].jumpMode
  775. let btnContent = selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3]
  776. if (value === 'link') {
  777. if (jumpMode === "total_jump") {
  778. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[1] = { ...btModelJumpLink103 }
  779. }
  780. if (btnContent?.horizontalAlignment) {
  781. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpLink103, horizontalAlignment: '1' }
  782. } else {
  783. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpLink103 }
  784. }
  785. } else if (value === 'gh') {
  786. if (jumpMode === "total_jump") {
  787. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[1] = { ...btModelJumpGh103 }
  788. }
  789. if (btnContent?.horizontalAlignment) {
  790. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpGh103, horizontalAlignment: '1' }
  791. } else {
  792. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpGh103 }
  793. }
  794. } else if (value === 'enterprise_wx_auto') {
  795. if (jumpMode === "total_jump") {
  796. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[1] = { ...btModelJumpWxAuto103 }
  797. }
  798. if (btnContent?.horizontalAlignment) {
  799. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpWxAuto103, horizontalAlignment: '1' }
  800. } else {
  801. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3] = { ...jumpWxAuto103 }
  802. }
  803. }
  804. } else if (selectCon?.type === '104') {
  805. let jumpMode = selectCon.layoutItems.componentItem[0].jumpMode
  806. if (value === 'link') {
  807. if (jumpMode === "total_jump") {
  808. selectCon.layoutItems.componentItem[1] = { ...btModelJumpLink }
  809. }
  810. selectCon.layoutItems.componentItem[0].layoutItems.componentItem[1].layoutItems.componentItem[2] = { ...jumpLink104 }
  811. } else if (value === 'gh') {
  812. if (jumpMode === "total_jump") {
  813. selectCon.layoutItems.componentItem[1] = { ...btModelJumpGh }
  814. }
  815. selectCon.layoutItems.componentItem[0].layoutItems.componentItem[1].layoutItems.componentItem[2] = { ...jumpGh104 }
  816. } else if (value === 'enterprise_wx_auto') {
  817. if (jumpMode === "total_jump") {
  818. selectCon.layoutItems.componentItem[1] = { ...btModelJumpWxAuto }
  819. }
  820. selectCon.layoutItems.componentItem[0].layoutItems.componentItem[1].layoutItems.componentItem[2] = { ...jumpWxAuto104 }
  821. }
  822. }
  823. oldContent[selectIndex] = { ...selectCon }
  824. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  825. }
  826. }, [content, goodsCount])
  827. // 配置图文跳转链接按钮字段
  828. const onSetShelfnewButtonField = useCallback((field: string, value: string) => {
  829. let newContent = JSON.parse(JSON.stringify(content))
  830. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  831. let oldContent = newContent
  832. if (selectIndex !== -1) {
  833. let selectCon = oldContent[selectIndex]
  834. if (selectCon?.type === '103') {
  835. let jumpMode = selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].jumpMode
  836. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3][field] = value
  837. if (field === 'btnBorderColorTheme') {
  838. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[0].layoutItems.componentItem[3]['borderSize'] = "2"
  839. }
  840. if (jumpMode === 'total_jump' && (field === 'subType' || field === 'btnFontType')) {
  841. selectCon.layoutItems.componentItem[goodsCount].layoutItems.componentItem[1][field] = value
  842. }
  843. } else if (selectCon?.type === '104') {
  844. let jumpMode = selectCon.layoutItems.componentItem[0].jumpMode
  845. selectCon.layoutItems.componentItem[0].layoutItems.componentItem[1].layoutItems.componentItem[2][field] = value
  846. if (field === 'btnBorderColorTheme') {
  847. selectCon.layoutItems.componentItem[0].layoutItems.componentItem[1].layoutItems.componentItem[2]['borderSize'] = "2"
  848. }
  849. if (jumpMode === 'total_jump' && (field === 'subType' || field === 'btnFontType')) {
  850. selectCon.layoutItems.componentItem[1][field] = value
  851. }
  852. }
  853. oldContent[selectIndex] = { ...selectCon }
  854. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  855. }
  856. }, [content, goodsCount])
  857. // 设置图文复合组件类型
  858. const setShelfnewType = useCallback((value: string) => {
  859. let newContent = JSON.parse(JSON.stringify(content))
  860. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  861. if (selectIndex !== -1) {
  862. if (value === '103') {
  863. newContent[selectIndex] = { ...shelfnewContent2, comptActive: true }
  864. } else if (value === '104') {
  865. newContent[selectIndex] = { ...shelfnewContent, comptActive: true }
  866. }
  867. dispatch({ type: 'setCon', params: { content: [...newContent] } })
  868. }
  869. }, [content])
  870. // 设置对齐方式
  871. const setAilgin103 = useCallback((align: number) => {
  872. let newContent = JSON.parse(JSON.stringify(content))
  873. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  874. if (selectIndex !== -1) {
  875. let selectCon = newContent[selectIndex]
  876. selectCon.wxad_align = align
  877. let componentItem = selectCon?.layoutItems?.componentItem?.map((item: any) => {
  878. let shelfnewItem = item?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  879. if (align === 0) {
  880. shelfnewItem = shelfnewItem?.map((oldItem: any, index: number) => {
  881. if (index === 0) {
  882. return oldItem
  883. } else if (index === 1 || index === 2) {
  884. let { textAlignment, ...newItem } = oldItem
  885. return newItem
  886. } else {
  887. let { horizontalAlignment, ...newItem } = oldItem
  888. return newItem
  889. }
  890. })
  891. } else {
  892. shelfnewItem = shelfnewItem?.map((newItem: any, index: number) => {
  893. if (index === 0) {
  894. return newItem
  895. } else if (index === 1 || index === 2) {
  896. return { ...newItem, textAlignment: "1" }
  897. } else {
  898. return { ...newItem, horizontalAlignment: "1" }
  899. }
  900. })
  901. }
  902. item.layoutItems.componentItem[0].layoutItems.componentItem = shelfnewItem
  903. return item
  904. })
  905. selectCon.layoutItems.componentItem = componentItem
  906. newContent[selectIndex] = { ...selectCon }
  907. dispatch({ type: 'setCon', params: { content: [...newContent] } })
  908. }
  909. }, [content])
  910. // 设置悬浮弹窗
  911. const setGlobalComponentItem = (key: string, value: any, isDel = false) => {
  912. let newConItem = JSON.parse(JSON.stringify(componentItem))
  913. let selectIndex = newConItem?.findIndex((item: Content) => item.comptActive)
  914. let oldContent = newConItem
  915. if (selectIndex !== -1) {
  916. let selectCon = oldContent[selectIndex]
  917. // 设置悬浮窗 转化按钮
  918. if (key === 'componentItem' && (value === 'GH' || value === 'ENTERPRISE_WX')) {
  919. if (value === 'GH') {
  920. selectCon[key] = floatbuttonBtTypeGh
  921. } else if (value === 'ENTERPRISE_WX') {
  922. selectCon[key] = floatbuttonBtTypeWxAuto
  923. }
  924. } else {
  925. if (!isDel) {
  926. selectCon[key] = value
  927. if (key === 'styleType') {
  928. if (value === 0) {
  929. selectCon['imageUrl'] = ""
  930. selectCon['desc'] = selectCon?.desc || ""
  931. } else if (value === 1) {
  932. delete selectCon['imageUrl']
  933. selectCon['desc'] = selectCon?.desc || ""
  934. } else if (value === 2) {
  935. delete selectCon['imageUrl']
  936. delete selectCon['desc']
  937. }
  938. selectCon[key] = value
  939. }
  940. } else {
  941. delete selectCon[key]
  942. }
  943. }
  944. dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(oldContent)) } })
  945. }
  946. }
  947. // 选中设置
  948. const rightCon = () => {
  949. let selectCon = content?.find((item: Content) => item.comptActive)
  950. if (!selectCon) {
  951. selectCon = componentItem?.find((item: { comptActive: boolean }) => item.comptActive)
  952. }
  953. if (selectCon) {
  954. let { elementType, adLocation, outerStyle, imageUrlList, imageUrl, text, fontColor, fontSize, fontStyle, textAlignment,
  955. paddingTop, paddingBottom, fastFollow, btnTitle, btnFontType, btnBorderColorTheme, btnBgColorTheme, useIcon,
  956. styleType, type, initHeight, outerUseTopMaterial, componentCount, activeIndex, componentGroupList, origBtnJumpUrl,
  957. layoutItems, borderColor, bgColor, title, desc, titleColor, descColor, componentItem, appearType, disappearType } = selectCon
  958. let descType = "text"
  959. let jumpMode = "btn_jump"
  960. let shelfnewImgData: { pureImageUrl: string } = { pureImageUrl: '' } // 图片信息
  961. let shelfnewTitleData: { content: string, fontColor: string } = { content: "", fontColor: "#353535" } // 标题信息
  962. let shelfnewDescData: { name: string, content: string, fontColor: string } = { name: '', content: "", fontColor: "#B2B2B2" } // 描述信息
  963. let shelfnewBtData: {
  964. widgetTypeV2: string, btnTitle: string, btnBgColorTheme: string,
  965. subType: '17' | '1', btnFontType: '0' | '1',
  966. btnBorderColorTheme: string, fontColor: string, origBtnJumpUrl: string,
  967. custorData: any[]
  968. } = { widgetTypeV2: '', btnFontType: '0', subType: '17', btnTitle: "", btnBgColorTheme: "#07C160", btnBorderColorTheme: "#FFFFFF", fontColor: "#FFFFFF", origBtnJumpUrl: "", custorData: [] }
  969. let custorGroup = []
  970. if (elementType === 'enterprise_wx_auto') {
  971. custorGroup = selectCon?.custorData || []
  972. } else if (elementType === 'shelfnew') {
  973. if (type === '104') { // 图文复合组件 单个
  974. let shelfnewData = layoutItems?.componentItem[0]?.layoutItems?.componentItem
  975. jumpMode = layoutItems?.componentItem[0]?.jumpMode
  976. descType = shelfnewData[1]?.descType
  977. shelfnewImgData = shelfnewData[0]
  978. shelfnewTitleData = shelfnewData[1]?.layoutItems?.componentItem[0]
  979. shelfnewDescData = shelfnewData[1]?.layoutItems?.componentItem[1]
  980. shelfnewBtData = shelfnewData[1]?.layoutItems?.componentItem[2]
  981. } else if (type === '103') {
  982. // goodsCount
  983. let componentItems = layoutItems.componentItem
  984. let componentItem = componentItems[goodsCount]
  985. borderColor = componentItem?.borderColor || "#e5e5e5"
  986. bgColor = componentItem?.bgColor || "#ffffff"
  987. jumpMode = componentItem?.layoutItems?.componentItem[0]?.jumpMode
  988. let shelfnewItem = componentItem?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  989. descType = componentItem?.layoutItems?.componentItem[0]?.descType
  990. shelfnewImgData = shelfnewItem[0]
  991. shelfnewTitleData = shelfnewItem[1]
  992. shelfnewDescData = shelfnewItem[2]
  993. shelfnewBtData = shelfnewItem[3]
  994. }
  995. }
  996. return <>
  997. {
  998. elementType === 'TOP_IMAGE' ? <div className="widget">
  999. <div className="caption section">
  1000. <div className="caption-title">顶部组件:图片</div>
  1001. </div>
  1002. <div className="form section">
  1003. <div className="form-caption">广告位与样式</div>
  1004. <div className="adui-form-item">
  1005. <div className="adui-form-label">广告位</div>
  1006. <div className="adui-form-control">
  1007. <Radio.Group onChange={(e) => { setCon('adLocation', e.target.value, true) }} value={adLocation} size='small'>
  1008. <Radio value='sns'>朋友圈信息流</Radio>
  1009. <Radio value='gzh'>公众号及其他</Radio>
  1010. </Radio.Group>
  1011. </div>
  1012. </div>
  1013. {adLocation === 'sns' && <div className="adui-form-item">
  1014. <div className="adui-form-label">外层样式</div>
  1015. <div className="adui-form-control">
  1016. <Select value={outerStyle} style={{ width: 100 }} onChange={(e) => { setCon('outerStyle', e, true) }}>
  1017. <Option value={0}>常规广告</Option>
  1018. <Option value={1}>卡片广告</Option>
  1019. </Select>
  1020. </div>
  1021. </div>}
  1022. </div>
  1023. <div className="form section">
  1024. <div className="form-caption">素材设置</div>
  1025. <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1026. <div className="adui-form-label">图片素材</div>
  1027. <div className="adui-form-control">
  1028. <div className={`upload-img-item ${imageUrl ? 'upload-img-item_uploaded' : ''}`}>
  1029. {imageUrl ? <div className="upload-img-item-inner" style={{ backgroundImage: `url(${imageUrl})` }}>
  1030. <div className='upload-img-item-action' onClick={() => { clickUpdateImg(1) }}>
  1031. <RetweetOutlined />
  1032. </div>
  1033. </div> : <div className="upload-img-item-inner" onClick={() => { clickUpdateImg(1) }}>
  1034. <PlusOutlined />
  1035. </div>}
  1036. </div>
  1037. </div>
  1038. </div>
  1039. </div>
  1040. </div>
  1041. :
  1042. elementType === 'TOP_SLIDER' ? <div className="widget">
  1043. <div className="caption section">
  1044. <div className="caption-title">顶部组件:轮播图</div>
  1045. </div>
  1046. <div className="form section">
  1047. <div className="form-caption">素材设置</div>
  1048. <div className="adui-form-item">
  1049. <div className="adui-form-label">图片数量</div>
  1050. <div className="adui-form-control">
  1051. <Radio.Group onChange={(e) => { sliderImgNum(e.target.value) }} value={imageUrlList?.length || 3} size='small'>
  1052. <Radio.Button value={3}>3张</Radio.Button>
  1053. <Radio.Button value={4}>4张</Radio.Button>
  1054. <Radio.Button value={6}>6张</Radio.Button>
  1055. </Radio.Group>
  1056. </div>
  1057. </div>
  1058. </div>
  1059. <div className="form section">
  1060. <div className="form-caption">上传素材</div>
  1061. <SortableUlList axis='xy' onSortEnd={onSortEndSlider} useDragHandle>
  1062. {imageUrlList?.map((item: any, index: number) => {
  1063. if (item) {
  1064. return <SortableItemLi key={`slider-${index}`} index={index} isActive={activeIndex === index} pureImageUrl={item} click={() => { sliderSelect(index, imageUrlList.length) }} setActiveIndex={() => { setCon('activeIndex', index) }}></SortableItemLi>
  1065. } else {
  1066. return <SortableItemNoLi key={`slider-${index}`} index={index} isActive={activeIndex === index} click={() => { sliderSelect(index, imageUrlList.length) }}></SortableItemNoLi>
  1067. }
  1068. })}
  1069. </SortableUlList>
  1070. </div>
  1071. </div>
  1072. :
  1073. elementType === 'TOP_VIDEO' ? <div className="widget">
  1074. <div className="caption section">
  1075. <div className="caption-title">顶部组件:视频</div>
  1076. </div>
  1077. <div className="form section">
  1078. <div className="form-caption">广告位与样式</div>
  1079. <div className="adui-form-item">
  1080. <div className="adui-form-label">广告位</div>
  1081. <div className="adui-form-control">
  1082. <Radio.Group onChange={(e) => { changeAdLocation(e.target.value) }} value={adLocation} size='small'>
  1083. <Radio value='sns'>朋友圈信息流</Radio>
  1084. <Radio value='gzh'>公众号及其他</Radio>
  1085. </Radio.Group>
  1086. </div>
  1087. </div>
  1088. {adLocation === 'sns' && <div className="adui-form-item">
  1089. <div className="adui-form-label">外层样式</div>
  1090. <div className="adui-form-control">
  1091. <Select size="small" value={outerStyle} style={{ width: 100 }} onChange={(e) => { changeOuterLayout(e) }}>
  1092. <Option value={0}>常规广告</Option>
  1093. <Option value={1} disabled>卡片广告</Option>
  1094. </Select>
  1095. </div>
  1096. </div>}
  1097. {/* {
  1098. adLocation === 'sns' && outerStyle === 0 && <div className="adui-form-item">
  1099. <div className="adui-form-label">视频类型</div>
  1100. <div className="adui-form-control">
  1101. <Radio.Group onChange={(e) => { viewTypeChange(e.target.value, 1) }} value={styleType} size='small'>
  1102. <Radio value='0'>横板视频</Radio>
  1103. <Radio value='1'>竖版视频</Radio>
  1104. </Radio.Group>
  1105. </div>
  1106. </div>
  1107. }
  1108. {
  1109. adLocation === 'sns' && outerStyle === 1 && <div className="adui-form-item">
  1110. <div className="adui-form-label">外层素材</div>
  1111. <div className="adui-form-control">
  1112. <Checkbox onChange={(e: CheckboxChangeEvent) => { outerUseTopMaterialHandle(e.target.checked) }} checked={outerUseTopMaterial === '0' ? false : true}>顶部素材不用于广告外层</Checkbox>
  1113. </div>
  1114. </div>
  1115. } */}
  1116. {/* {
  1117. outerUseTopMaterial === '1' && <div className="adui-form-item">
  1118. <div className="adui-form-label">视频类型</div>
  1119. <div className="adui-form-control">
  1120. <Radio.Group onChange={(e) => { viewTypeChange(e.target.value, 2) }} value={type} size='small'>
  1121. <Radio value='61'>短视频</Radio>
  1122. <Radio value='62'>长视频</Radio>
  1123. </Radio.Group>
  1124. </div>
  1125. </div>
  1126. } */}
  1127. {/* {
  1128. adLocation === 'gh' && <div className="adui-form-item">
  1129. <div className="adui-form-label">视频类型</div>
  1130. <div className="adui-form-control">
  1131. <Radio.Group onChange={(e) => { viewTypeChange(e.target.value, 2) }} value={type} size='small'>
  1132. <Radio value='61'>短视频</Radio>
  1133. <Radio value='62'>长视频</Radio>
  1134. </Radio.Group>
  1135. </div>
  1136. </div>
  1137. } */}
  1138. {adLocation === 'sns' && styleType === '1' && <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1139. <div className="adui-form-label" style={{ marginTop: 2 }}>视频尺寸</div>
  1140. <div className="adui-form-control">
  1141. <Radio.Group value={initHeight} onChange={(e) => { setCon('initHeight', e.target.value) }}>
  1142. <Radio value={1536}>750像素 x 1536像素</Radio>
  1143. <Radio value={1334}>750像素 x 1334像素</Radio>
  1144. <Radio value={1280}>720像素 x 1280像素</Radio>
  1145. </Radio.Group>
  1146. </div>
  1147. </div>}
  1148. </div>
  1149. </div>
  1150. :
  1151. elementType === 'TEXT' ? <div className="widget">
  1152. <div className="caption section">
  1153. <div className="caption-title">文本</div>
  1154. </div>
  1155. <div className="form section">
  1156. <div className="form-caption">推广文案</div>
  1157. <TextArea
  1158. placeholder="请输入"
  1159. autoSize={{ minRows: 4, maxRows: 6 }}
  1160. value={text}
  1161. onChange={(e) => { setCon('text', e.target.value) }}
  1162. />
  1163. </div>
  1164. <div className="form section">
  1165. <div className="form-caption">字符与段落</div>
  1166. <div className="adui-form-item">
  1167. <div className="adui-form-label">字符样式</div>
  1168. <div className="adui-form-control">
  1169. <div className="fl-sb">
  1170. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1171. <Space>
  1172. <Select value={fontSize} style={{ width: 60 }} onChange={(e) => { setCon('fontSize', e) }}>
  1173. {[14, 15, 16, 18, 20, 24, 36].map((item: number) => (<Option value={item} key={item}>{item}</Option>))}
  1174. </Select>
  1175. <ColorPicker onColor={(color: string) => { setCon('fontColor', color) }} color={fontColor}></ColorPicker>
  1176. </Space>
  1177. </div>
  1178. <Radio.Group onChange={(e) => { setCon('fontStyle', e.target.value) }} value={fontStyle}>
  1179. <Radio.Button value={0}>常规</Radio.Button>
  1180. <Radio.Button value={1}>加粗</Radio.Button>
  1181. </Radio.Group>
  1182. </div>
  1183. </div>
  1184. </div>
  1185. <div className="adui-form-item">
  1186. <div className="adui-form-label">对齐方式</div>
  1187. <div className="adui-form-control">
  1188. <Radio.Group onChange={(e) => { setCon('textAlignment', e.target.value) }} value={textAlignment}>
  1189. <Radio.Button value={0}><AlignLeftOutlined /></Radio.Button>
  1190. <Radio.Button value={1}><AlignCenterOutlined /></Radio.Button>
  1191. <Radio.Button value={2}><AlignRightOutlined /></Radio.Button>
  1192. </Radio.Group>
  1193. </div>
  1194. </div>
  1195. </div>
  1196. <div className="form section">
  1197. <div className="form-caption">边距</div>
  1198. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1199. <div className="adui-form-label">上边距</div>
  1200. <div className="adui-form-control">
  1201. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1202. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1203. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1204. </div>
  1205. </div>
  1206. </div>
  1207. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1208. <div className="adui-form-label">下边距</div>
  1209. <div className="adui-form-control">
  1210. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1211. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1212. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1213. </div>
  1214. </div>
  1215. </div>
  1216. </div>
  1217. </div>
  1218. :
  1219. elementType === 'IMAGE' ? <div className="widget">
  1220. <div className="caption section">
  1221. <div className="caption-title">图片</div>
  1222. </div>
  1223. <div className="form section">
  1224. <div className="form-caption">素材设置</div>
  1225. <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1226. <div className="adui-form-label">图片素材</div>
  1227. <div className="adui-form-control">
  1228. <div className={`upload-img-item ${imageUrl ? 'upload-img-item_uploaded' : ''}`}>
  1229. {
  1230. imageUrl ? <div className="upload-img-item-inner" style={{ backgroundImage: `url(${imageUrl ? imageUrl : ""})` }}>
  1231. <div className='upload-img-item-action' onClick={() => { clickUpdateImg(1) }}>
  1232. <RetweetOutlined />
  1233. </div>
  1234. </div>
  1235. :
  1236. <div className="upload-img-item-inner" onClick={() => { clickUpdateImg(1) }}>
  1237. <PlusOutlined />
  1238. </div>
  1239. }
  1240. </div>
  1241. </div>
  1242. </div>
  1243. </div>
  1244. <div className="form section">
  1245. <div className="form-caption">边距</div>
  1246. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1247. <div className="adui-form-label">上边距</div>
  1248. <div className="adui-form-control">
  1249. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1250. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1251. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1252. </div>
  1253. </div>
  1254. </div>
  1255. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1256. <div className="adui-form-label">下边距</div>
  1257. <div className="adui-form-control">
  1258. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1259. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1260. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1261. </div>
  1262. </div>
  1263. </div>
  1264. </div>
  1265. </div>
  1266. :
  1267. elementType === 'GH' ? <div className="widget">
  1268. <div className="caption section">
  1269. <div className="caption-title">关注公众号</div>
  1270. </div>
  1271. <div className="form section">
  1272. <Space>
  1273. <Switch size="small" checked={fastFollow === 1 ? true : false} onChange={(e) => { setCon('fastFollow', e ? 1 : 0) }} />
  1274. 一键关注
  1275. <Tooltip placement="top" title={'唤起公众号简介的半屏面板,点击其中按钮直接关注公众号'}>
  1276. <QuestionCircleOutlined />
  1277. </Tooltip>
  1278. </Space>
  1279. </div>
  1280. <div className="form section">
  1281. <div className="form-caption">按钮外观</div>
  1282. <div className="adui-form-item">
  1283. <div className="adui-form-label">按钮文案</div>
  1284. <div className="adui-form-control">
  1285. <div className="fl-sb">
  1286. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1287. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', border: '1px solid #d9d9d9', borderRadius: 2, paddingRight: 8 }}>
  1288. <Input maxLength={useIcon === 1 ? 8 : 10} style={{ width: 90 }} bordered={false} value={btnTitle} onChange={(e) => { setCon('btnTitle', e.target.value) }} /> <span>{btnTitle?.length}/{useIcon === 1 ? 8 : 10}</span>
  1289. </div>
  1290. </div>
  1291. <Radio.Group onChange={(e) => { setCon('btnFontType', e.target.value) }} value={btnFontType}>
  1292. <Radio.Button value={0}>常规</Radio.Button>
  1293. <Radio.Button value={1}>加粗</Radio.Button>
  1294. </Radio.Group>
  1295. </div>
  1296. </div>
  1297. </div>
  1298. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1299. <div className="adui-form-label">字体色</div>
  1300. <div className="adui-form-control">
  1301. <Space><ColorPicker onColor={(color: string) => { setCon('fontColor', color) }} color={fontColor}></ColorPicker><div className="colorShow">{fontColor}</div></Space>
  1302. </div>
  1303. </div>
  1304. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1305. <div className="adui-form-label">图标</div>
  1306. <div className="adui-form-control">
  1307. <Switch size="small" checked={useIcon === 1 ? true : false} onChange={(e) => { iconHandle(e) }} /> <span>{useIcon === 1 ? '已启用' : '未启用'}</span>
  1308. </div>
  1309. </div>
  1310. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1311. <div className="adui-form-label">边框色</div>
  1312. <div className="adui-form-control">
  1313. <Space><ColorPicker onColor={(color: string) => { setCon('btnBorderColorTheme', color) }} color={btnBorderColorTheme}></ColorPicker><div className="colorShow">{btnBorderColorTheme}</div></Space>
  1314. </div>
  1315. </div>
  1316. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1317. <div className="adui-form-label">背景色</div>
  1318. <div className="adui-form-control">
  1319. <Space><ColorPicker onColor={(color: string) => { setCon('btnBgColorTheme', color) }} color={btnBgColorTheme}></ColorPicker><div className="colorShow">{btnBgColorTheme}</div></Space>
  1320. </div>
  1321. </div>
  1322. </div>
  1323. <div className="form section">
  1324. <div className="form-caption">边距</div>
  1325. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1326. <div className="adui-form-label">上边距</div>
  1327. <div className="adui-form-control">
  1328. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1329. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1330. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1331. </div>
  1332. </div>
  1333. </div>
  1334. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1335. <div className="adui-form-label">下边距</div>
  1336. <div className="adui-form-control">
  1337. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1338. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1339. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1340. </div>
  1341. </div>
  1342. </div>
  1343. </div>
  1344. </div> :
  1345. elementType === 'ENTERPRISE_WX' ? <div className="widget">
  1346. <div className="caption section">
  1347. <div className="caption-title">添加商家微信</div>
  1348. </div>
  1349. <div className="form section">
  1350. <div className="form-caption">按钮外观</div>
  1351. <div className="adui-form-item">
  1352. <div className="adui-form-label">按钮文案</div>
  1353. <div className="adui-form-control">
  1354. <div className="fl-sb">
  1355. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1356. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', border: '1px solid #d9d9d9', borderRadius: 2, paddingRight: 8 }}>
  1357. <Input maxLength={useIcon === 1 ? 8 : 10} style={{ width: 90 }} bordered={false} value={btnTitle} onChange={(e) => { setCon('btnTitle', e.target.value) }} /> <span>{btnTitle?.length}/{useIcon === 1 ? 8 : 10}</span>
  1358. </div>
  1359. </div>
  1360. <Radio.Group onChange={(e) => { setCon('btnFontType', e.target.value) }} value={btnFontType}>
  1361. <Radio.Button value={0}>常规</Radio.Button>
  1362. <Radio.Button value={1}>加粗</Radio.Button>
  1363. </Radio.Group>
  1364. </div>
  1365. </div>
  1366. </div>
  1367. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1368. <div className="adui-form-label">字体色</div>
  1369. <div className="adui-form-control">
  1370. <Space><ColorPicker onColor={(color: string) => { setCon('fontColor', color) }} color={fontColor}></ColorPicker> <div className="colorShow">{fontColor}</div></Space>
  1371. </div>
  1372. </div>
  1373. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1374. <div className="adui-form-label">图标</div>
  1375. <div className="adui-form-control">
  1376. <Switch size="small" checked={useIcon === 1 ? true : false} onChange={(e) => { iconHandle(e) }} /> <span>{useIcon === 1 ? '已启用' : '未启用'}</span>
  1377. </div>
  1378. </div>
  1379. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1380. <div className="adui-form-label">边框色</div>
  1381. <div className="adui-form-control">
  1382. <Space><ColorPicker onColor={(color: string) => { setCon('btnBorderColorTheme', color) }} color={btnBorderColorTheme}></ColorPicker> <div className="colorShow">{btnBorderColorTheme}</div></Space>
  1383. </div>
  1384. </div>
  1385. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1386. <div className="adui-form-label">背景色</div>
  1387. <div className="adui-form-control">
  1388. <Space><ColorPicker onColor={(color: string) => { setCon('btnBgColorTheme', color) }} color={btnBgColorTheme}></ColorPicker> <div className="colorShow">{btnBgColorTheme}</div></Space>
  1389. </div>
  1390. </div>
  1391. </div>
  1392. <div className="form section">
  1393. <div className="form-caption">边距</div>
  1394. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1395. <div className="adui-form-label">上边距</div>
  1396. <div className="adui-form-control">
  1397. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1398. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1399. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1400. </div>
  1401. </div>
  1402. </div>
  1403. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1404. <div className="adui-form-label">下边距</div>
  1405. <div className="adui-form-control">
  1406. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1407. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1408. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1409. </div>
  1410. </div>
  1411. </div>
  1412. </div>
  1413. </div>
  1414. :
  1415. elementType === 'link' ? <div className="widget">
  1416. {/* <div className="caption section">
  1417. <div className="caption-title">跳转链接</div>
  1418. </div>
  1419. <div className="form section">
  1420. <div className="form-caption">链接设置</div>
  1421. <Input placeholder="以 http:// 或 https:// 开头" value={origBtnJumpUrl} onChange={(e) => { setCon('origBtnJumpUrl', e.target.value) }} />
  1422. </div>
  1423. <div className="form section">
  1424. <div className="form-caption">按钮外观</div>
  1425. <div className="adui-form-item">
  1426. <div className="adui-form-label">按钮文案</div>
  1427. <div className="adui-form-control">
  1428. <div className="fl-sb">
  1429. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1430. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', border: '1px solid #d9d9d9', borderRadius: 2, paddingRight: 8 }}>
  1431. <Input maxLength={10} style={{ width: 90 }} bordered={false} value={btnTitle} onChange={(e) => { setCon('btnTitle', e.target.value) }} /> <span>{btnTitle?.length}/10</span>
  1432. </div>
  1433. </div>
  1434. <Radio.Group onChange={(e) => { setCon('btnFontType', e.target.value) }} value={btnFontType}>
  1435. <Radio.Button value="0">常规</Radio.Button>
  1436. <Radio.Button value="1">加粗</Radio.Button>
  1437. </Radio.Group>
  1438. </div>
  1439. </div>
  1440. </div>
  1441. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1442. <div className="adui-form-label">字体色</div>
  1443. <div className="adui-form-control">
  1444. <Space><ColorPicker onColor={(color: string) => { setCon('fontColor', color) }} color={fontColor}></ColorPicker><div className="colorShow">{fontColor}</div></Space>
  1445. </div>
  1446. </div>
  1447. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1448. <div className="adui-form-label">图标</div>
  1449. <div className="adui-form-control">
  1450. <Switch size="small" checked={useIcon === '1' ? true : false} onChange={(e) => { iconHandle(e) }} /> <span>{useIcon === '1' ? '已启用' : '未启用'}</span>
  1451. </div>
  1452. </div>
  1453. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1454. <div className="adui-form-label">边框色</div>
  1455. <div className="adui-form-control">
  1456. <Space><ColorPicker onColor={(color: string) => { setCon('btnBorderColorTheme', color) }} color={btnBorderColorTheme}></ColorPicker><div className="colorShow">{btnBorderColorTheme}</div></Space>
  1457. </div>
  1458. </div>
  1459. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1460. <div className="adui-form-label">背景色</div>
  1461. <div className="adui-form-control">
  1462. <Space><ColorPicker onColor={(color: string) => { setCon('btnBgColorTheme', color) }} color={btnBgColorTheme}></ColorPicker><div className="colorShow">{btnBgColorTheme}</div></Space>
  1463. </div>
  1464. </div>
  1465. </div>
  1466. <div className="form section">
  1467. <div className="form-caption">边距</div>
  1468. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1469. <div className="adui-form-label">上边距</div>
  1470. <div className="adui-form-control">
  1471. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1472. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1473. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1474. </div>
  1475. </div>
  1476. </div>
  1477. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1478. <div className="adui-form-label">下边距</div>
  1479. <div className="adui-form-control">
  1480. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1481. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1482. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1483. </div>
  1484. </div>
  1485. </div>
  1486. </div> */}
  1487. </div>
  1488. :
  1489. elementType === 'shelfnew' ? <div className="widget">
  1490. {/* {imgTextButtonShow ? <>
  1491. <div className="caption section goBack" onClick={() => { setImgTextButtonShow(false) }}>
  1492. <SwapLeftOutlined />
  1493. <span>返回</span>
  1494. </div>
  1495. {shelfnewBtData.widgetTypeV2 === 'gh' || shelfnewBtData.widgetTypeV2 === 'link' || shelfnewBtData.widgetTypeV2 === 'enterprise_wx_auto' ? <>
  1496. {shelfnewBtData.widgetTypeV2 === 'link' ? <div className="form section">
  1497. <div className="form-caption">链接设置</div>
  1498. <Input placeholder="以 http:// 或 https:// 开头" value={shelfnewBtData?.origBtnJumpUrl} onChange={(e) => { onSetShelfnewButtonField('origBtnJumpUrl', e.target.value) }} />
  1499. </div> : shelfnewBtData.widgetTypeV2 === 'gh' ? <div className="form section">
  1500. <Space>
  1501. <Switch size="small" checked={shelfnewBtData?.subType === '17' ? true : false} onChange={(e) => { onSetShelfnewButtonField('subType', e ? '17' : '1') }} />
  1502. 一键关注
  1503. <Tooltip placement="top" title={'唤起公众号简介的半屏面板,点击其中按钮直接关注公众号'}>
  1504. <QuestionCircleOutlined />
  1505. </Tooltip>
  1506. </Space>
  1507. </div> : <div className="form section">
  1508. <div className="form-caption">客服设置</div>
  1509. <div className="adui-form-item">
  1510. <div className="adui-form-label">客服分配</div>
  1511. <div className="adui-form-control">
  1512. <div className="fl-sb">
  1513. <Button size="small" onClick={clickCustorGroup}>{shelfnewBtData?.custorData?.length > 0 ? '修改客服组' : '选择客服组'}</Button>
  1514. </div>
  1515. </div>
  1516. </div>
  1517. {shelfnewBtData?.custorData?.length > 0 && <div className='adui-form-item custorGroup'>
  1518. {shelfnewBtData?.custorData?.map((item: { label: string, custorData: any[], id: number }) => <div key={item.id}>
  1519. <strong>{item.label}:</strong><span>{item.custorData[0]?.name}</span>
  1520. </div>)}
  1521. </div>}
  1522. </div>}
  1523. <div className="form section">
  1524. <div className="form-caption">按钮外观</div>
  1525. <div className="adui-form-item">
  1526. <div className="adui-form-label">按钮文案</div>
  1527. <div className="adui-form-control">
  1528. <div className="fl-sb">
  1529. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1530. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', border: '1px solid #d9d9d9', borderRadius: 2, paddingRight: 8 }}>
  1531. <Input maxLength={5} style={{ width: 90 }} bordered={false} value={shelfnewBtData?.btnTitle} onChange={(e) => { onSetShelfnewButtonField('btnTitle', e.target.value) }} /> <span>{shelfnewBtData?.btnTitle?.length}/5</span>
  1532. </div>
  1533. </div>
  1534. <Radio.Group onChange={(e) => { onSetShelfnewButtonField('btnFontType', e.target.value) }} value={shelfnewBtData?.btnFontType}>
  1535. <Radio.Button value="0">常规</Radio.Button>
  1536. <Radio.Button value="1">加粗</Radio.Button>
  1537. </Radio.Group>
  1538. </div>
  1539. </div>
  1540. </div>
  1541. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1542. <div className="adui-form-label">字体色</div>
  1543. <div className="adui-form-control">
  1544. <Space><ColorPicker onColor={(color: string) => { onSetShelfnewButtonField('fontColor', color) }} color={shelfnewBtData?.fontColor}></ColorPicker><div className="colorShow">{shelfnewBtData?.fontColor}</div></Space>
  1545. </div>
  1546. </div>
  1547. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1548. <div className="adui-form-label">边框色</div>
  1549. <div className="adui-form-control">
  1550. <Space><ColorPicker onColor={(color: string) => { onSetShelfnewButtonField('btnBorderColorTheme', color) }} color={shelfnewBtData?.btnBorderColorTheme}></ColorPicker><div className="colorShow">{shelfnewBtData?.btnBorderColorTheme}</div></Space>
  1551. </div>
  1552. </div>
  1553. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1554. <div className="adui-form-label">背景色</div>
  1555. <div className="adui-form-control">
  1556. <Space><ColorPicker onColor={(color: string) => { onSetShelfnewButtonField('btnBgColorTheme', color) }} color={shelfnewBtData?.btnBgColorTheme}></ColorPicker><div className="colorShow">{shelfnewBtData?.btnBgColorTheme}</div></Space>
  1557. </div>
  1558. </div>
  1559. </div>
  1560. </> : <></>}
  1561. </> : <>
  1562. <div className="caption section">
  1563. <div className="caption-title">图文复合组件</div>
  1564. </div>
  1565. <div className="form section">
  1566. <div className="adui-form-item">
  1567. <div className="adui-form-label">类型</div>
  1568. <div className="adui-form-control">
  1569. <>
  1570. <Radio.Group onChange={(e) => { setShelfnewType(e.target.value) }} value={type}>
  1571. <Radio value='104'>一行1个</Radio>
  1572. <Radio value='103'>一行2个</Radio>
  1573. </Radio.Group>
  1574. {type === '103' && <Radio.Group onChange={(e) => { setGoodsCount(e.target.value) }} value={goodsCount} size='small' style={{ marginTop: 10 }}>
  1575. <Radio.Button value={0}>商品1</Radio.Button>
  1576. <Radio.Button value={1}>商品2</Radio.Button>
  1577. </Radio.Group>}
  1578. </>
  1579. </div>
  1580. </div>
  1581. </div>
  1582. <div className="form section">
  1583. <div className="adui-form-item">
  1584. <div className="adui-form-label">配图</div>
  1585. <div className="adui-form-control">
  1586. <div>
  1587. <Button onClick={() => { setCcType(4); setSelectImgVisible(true); setNum(1) }}>上传图片</Button>
  1588. <div style={{ marginTop: 4, fontSize: 12, color: '#636363' }}>{type === '103' ? '尺寸:480像素*480像素' : '尺寸:360像素*360像素'}</div>
  1589. <div style={{ marginTop: 4, fontSize: 12, color: '#636363' }}>格式:不超过300k</div>
  1590. </div>
  1591. </div>
  1592. </div>
  1593. <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1594. <div className="adui-form-label" style={{ marginTop: 6 }}>标题</div>
  1595. <div className="adui-form-control">
  1596. <Input.TextArea placeholder="请输入标题" onChange={(e) => { onShelfnewTxtCon(e.target.value?.replace(/\r|\n/ig, ""), 0, 'content') }} value={shelfnewTitleData?.content} showCount maxLength={type === '104' ? 12 : 8} autoSize />
  1597. </div>
  1598. </div>
  1599. <div className="adui-form-item">
  1600. <div className="adui-form-label">描述</div>
  1601. <div className="adui-form-control">
  1602. <Space direction="vertical" style={{ width: '100%' }}>
  1603. <Radio.Group onChange={onSetShelfnewDescType} value={descType}>
  1604. <Radio value="text">文字</Radio>
  1605. <Radio value="price">价格</Radio>
  1606. </Radio.Group>
  1607. {descType === 'text' ?
  1608. <Input.TextArea placeholder="请输入描述" onChange={(e) => { onShelfnewTxtCon(e.target.value?.replace(/\r|\n/ig, ""), 1, 'content') }} value={shelfnewDescData?.content} showCount maxLength={type === '104' ? 15 : 10} autoSize={{ minRows: 2, maxRows: 2 }} /> :
  1609. <div>
  1610. <Input placeholder="请输入" suffix="元" onChange={(e) => { onShelfnewTxtCon(e.target.value, 1, 'content') }} style={{ width: 150 }} value={shelfnewDescData?.content?.split('¥')[1]} />
  1611. <div style={{ fontSize: 12, color: '#636363', marginTop: 5 }}>价格范围0.01~999,999,999.99元</div>
  1612. </div>
  1613. }
  1614. </Space>
  1615. </div>
  1616. </div>
  1617. {type === '103' && <div className="adui-form-item">
  1618. <div className="adui-form-label">对齐</div>
  1619. <div className="adui-form-control">
  1620. <Radio.Group onChange={(e) => { setAilgin103(e.target.value) }} value={wxad_align}>
  1621. <Radio value={0}>左对齐</Radio>
  1622. <Radio value={1}>居中对齐</Radio>
  1623. </Radio.Group>
  1624. </div>
  1625. </div>}
  1626. <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1627. <div className="adui-form-label" style={{ marginTop: 14 }}>字体颜色</div>
  1628. <div className="adui-form-control">
  1629. <Space style={{ width: '100%' }} size="large" className="shelfnewColor">
  1630. <div>
  1631. <Space><ColorPicker onColor={(color: string) => { onShelfnewTxtCon(color, 0, 'fontColor') }} color={shelfnewTitleData?.fontColor}></ColorPicker> <div className="colorShow">{shelfnewTitleData?.fontColor}</div></Space>
  1632. <div className="colorName">标题</div>
  1633. </div>
  1634. <div>
  1635. <Space><ColorPicker onColor={(color: string) => { onShelfnewTxtCon(color, 1, 'fontColor') }} color={shelfnewDescData?.fontColor}></ColorPicker> <div className="colorShow">{shelfnewDescData?.fontColor}</div></Space>
  1636. <div className="colorName">{shelfnewDescData?.name}</div>
  1637. </div>
  1638. </Space>
  1639. </div>
  1640. </div>
  1641. <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1642. <div className="adui-form-label" style={{ marginTop: 14 }}>其它颜色</div>
  1643. <div className="adui-form-control">
  1644. <Space style={{ width: '100%' }} size="large" className="shelfnewColor">
  1645. <div>
  1646. <Space><ColorPicker onColor={(color: string) => { setCon('borderColor', color) }} color={borderColor}></ColorPicker> <div className="colorShow">{borderColor}</div></Space>
  1647. <div className="colorName">边框</div>
  1648. </div>
  1649. <div>
  1650. <Space><ColorPicker onColor={(color: string) => { setCon('bgColor', color) }} color={bgColor}></ColorPicker> <div className="colorShow">{bgColor}</div></Space>
  1651. <div className="colorName">背景</div>
  1652. </div>
  1653. </Space>
  1654. </div>
  1655. </div>
  1656. </div>
  1657. <div className="form section">
  1658. <div className="form-caption">边距</div>
  1659. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1660. <div className="adui-form-label">上边距</div>
  1661. <div className="adui-form-control">
  1662. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1663. <div style={{ flexGrow: 1 }}><Slider value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} /></div>
  1664. <InputNumber min={0} max={100} step={1} value={paddingTop} onChange={(value: number) => { setCon('paddingTop', value) }} style={{ width: 80, marginLeft: 20 }} />
  1665. </div>
  1666. </div>
  1667. </div>
  1668. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1669. <div className="adui-form-label">下边距</div>
  1670. <div className="adui-form-control">
  1671. <div style={{ display: 'flex', justifyContent: 'space-between' }}>
  1672. <div style={{ flexGrow: 1 }}><Slider value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} /></div>
  1673. <InputNumber min={0} max={100} step={1} value={paddingBottom} onChange={(value: number) => { setCon('paddingBottom', value) }} style={{ width: 80, marginLeft: 20 }} />
  1674. </div>
  1675. </div>
  1676. </div>
  1677. </div>
  1678. <div className="form section">
  1679. <div className="form-caption">按钮</div>
  1680. <div className="adui-form-item">
  1681. <div className="adui-form-label">跳转方式</div>
  1682. <div className="adui-form-control">
  1683. <Radio.Group onChange={onSetShelfnewJumpMode} value={jumpMode}>
  1684. <Radio value="btn_jump">按钮跳转</Radio>
  1685. <Radio value="total_jump">全局跳转</Radio>
  1686. </Radio.Group>
  1687. </div>
  1688. </div>
  1689. <div className="adui-form-item">
  1690. <div className="adui-form-label">按钮类型</div>
  1691. <div className="adui-form-control">
  1692. <Space>
  1693. <Select style={{ width: 120 }} value={shelfnewBtData.widgetTypeV2} onChange={(e) => { onSetShelfnewButton(e) }}>
  1694. <Option value="link">跳转链接</Option>
  1695. <Option value="gh">关注公众号</Option>
  1696. <Option value="enterprise_wx_auto">添加商家微信</Option>
  1697. </Select>
  1698. <Button type="link" size="small" onClick={() => { setImgTextButtonShow(true) }}>配置</Button>
  1699. </Space>
  1700. </div>
  1701. </div>
  1702. </div>
  1703. </>} */}
  1704. </div>
  1705. :
  1706. elementType === 'FLOAT_BUTTON' ? <div style={{ height: '100%' }}>
  1707. <div className={`widget ${imgTextButtonShow ? 'widget_back' : ''}`}>
  1708. <div className="caption section">
  1709. <div className="caption-title">悬浮按钮</div>
  1710. </div>
  1711. <div className="form section">
  1712. <div className="form-caption">卡片设置</div>
  1713. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1714. <div className="adui-form-label">转化按钮</div>
  1715. <div className="adui-form-control">
  1716. <div className='form-result-text'><span>{componentItem?.name}</span> <Button type="link" size='small' style={{ color: '#6b6b6b', fontSize: 12 }} onClick={() => { setImgTextButtonShow(true) }}>设置</Button> </div>
  1717. </div>
  1718. </div>
  1719. <div className="adui-form-item">
  1720. <div className="adui-form-label">卡片样式</div>
  1721. <div className="adui-form-control">
  1722. <Radio.Group onChange={(e) => { setGlobalComponentItem('styleType', e.target.value) }} className="floatType" value={styleType}>
  1723. <Radio.Button value={0}>
  1724. <div className='floatTypeInner'>
  1725. <i className="floatTypeAvatar"></i>
  1726. <i className="floatTypeText_two"></i>
  1727. <i className="floatTypeButton"></i>
  1728. </div>
  1729. </Radio.Button>
  1730. <Radio.Button value={1}>
  1731. <div className='floatTypeInner'>
  1732. <i style={{ display: 'inline-block', height: 12 }}></i>
  1733. <i className="floatTypeText_two"></i>
  1734. <i className="floatTypeButton"></i>
  1735. </div>
  1736. </Radio.Button>
  1737. <Radio.Button value={2}>
  1738. <div className='floatTypeInner'>
  1739. <i style={{ display: 'inline-block', height: 12 }}></i>
  1740. <i className="floatTypeText_one"></i>
  1741. <i className="floatTypeButton"></i>
  1742. </div>
  1743. </Radio.Button>
  1744. </Radio.Group>
  1745. </div>
  1746. </div>
  1747. </div>
  1748. <div className="form section">
  1749. <div className="form-caption">内容设置</div>
  1750. {styleType === 0 && <div className="adui-form-item" style={{ alignItems: 'flex-start' }}>
  1751. <div className="adui-form-label">图片</div>
  1752. <div className="adui-form-control">
  1753. <div className={`upload-img-item ${imageUrl ? 'upload-img-item_uploaded' : ''}`}>
  1754. {
  1755. imageUrl ? <div className="upload-img-item-inner" style={{ backgroundImage: `url(${imageUrl ? imageUrl : ""})` }}>
  1756. <div className='upload-img-item-action' onClick={() => { setCcType(5); setSelectImgVisible(true); }}>
  1757. <RetweetOutlined />
  1758. </div>
  1759. </div>
  1760. :
  1761. <div className="upload-img-item-inner" onClick={() => { setCcType(5); setSelectImgVisible(true); }}>
  1762. <PlusOutlined />
  1763. </div>
  1764. }
  1765. </div>
  1766. <div style={{ marginTop: 4, fontSize: 12, color: '#A3A3A3' }}>尺寸:96像素*96像素</div>
  1767. <div style={{ marginTop: 4, fontSize: 12, color: '#A3A3A3' }}>格式:不超过300k</div>
  1768. </div>
  1769. </div>}
  1770. <div className="adui-form-item" style={{ alignItems: 'flex-start', marginBottom: 10 }}>
  1771. <div className="adui-form-label" style={{ marginTop: 6 }}>标题</div>
  1772. <div className="adui-form-control">
  1773. <Input.TextArea placeholder="请输入标题" onChange={(e) => { setGlobalComponentItem('title', e.target.value?.replace(/\r|\n/ig, "")) }} value={title} showCount maxLength={10} autoSize />
  1774. </div>
  1775. </div>
  1776. {(styleType === 1 || styleType === 0) && <div className="adui-form-item" style={{ alignItems: 'flex-start', marginBottom: 10 }}>
  1777. <div className="adui-form-label" style={{ marginTop: 6 }}>描述</div>
  1778. <div className="adui-form-control">
  1779. <Input.TextArea placeholder="请输入描述" onChange={(e) => { setGlobalComponentItem('desc', e.target.value?.replace(/\r|\n/ig, "")) }} value={desc} showCount maxLength={14} autoSize />
  1780. </div>
  1781. </div>}
  1782. <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
  1783. <div className="adui-form-label" style={{ marginTop: 6 }}>标题字色</div>
  1784. <div className="adui-form-control">
  1785. <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('titleColor', color) }} color={titleColor}></ColorPicker> <div className="colorShow">{titleColor}</div></Space>
  1786. </div>
  1787. </div>
  1788. {(styleType === 1 || styleType === 0) && <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
  1789. <div className="adui-form-label" style={{ marginTop: 6 }}>描述字色</div>
  1790. <div className="adui-form-control">
  1791. <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('descColor', color) }} color={descColor}></ColorPicker> <div className="colorShow">{descColor}</div></Space>
  1792. </div>
  1793. </div>}
  1794. </div>
  1795. <div className="form section">
  1796. <div className="form-caption">更多设置</div>
  1797. <div className='adui-form-tip adui-form-tip_normal'>如果落地页只有一页,悬浮组件的更多设置必须为“进入页面时出现”、且“不消失”</div>
  1798. <div className="adui-form-item">
  1799. <div className="adui-form-label">出现方式</div>
  1800. <div className="adui-form-control">
  1801. <Radio.Group onChange={(e) => { setGlobalComponentItem('appearType', e.target.value) }} value={appearType}>
  1802. <Radio value={0}>进入页面时出现</Radio>
  1803. <Radio value={1}>滑动页面时出现</Radio>
  1804. </Radio.Group>
  1805. </div>
  1806. </div>
  1807. <div className="adui-form-item">
  1808. <div className="adui-form-label">消失方式</div>
  1809. <div className="adui-form-control">
  1810. <Radio.Group onChange={(e) => { setGlobalComponentItem('disappearType', e.target.value) }} value={disappearType}>
  1811. <Radio value={0}>不消失</Radio>
  1812. <Radio value={1}>滑至页面底部时消失</Radio>
  1813. </Radio.Group>
  1814. </div>
  1815. </div>
  1816. </div>
  1817. </div>
  1818. {/* 设置转化按钮 imgTextButtonShow */}
  1819. <div className='aside' style={{ transform: imgTextButtonShow ? 'translate3d(0px, 0px, 0px)' : 'translate3d(100%, 0px, 0px)', transition: 'all 0.3s cubic-bezier(0, 0, 0.2, 1) 0s' }}>
  1820. <div className='aside-nav'>
  1821. <Button type='link' icon={<SwapLeftOutlined />} onClick={() => { setImgTextButtonShow(false) }}>返回</Button>
  1822. </div>
  1823. <div className="form section">
  1824. <div className="form-caption">按钮类型</div>
  1825. <div className="adui-form-item" style={{ alignItems: 'center' }}>
  1826. <Select style={{ width: 180 }} className="aside-select" dropdownClassName="aside-select" onChange={(e) => { setGlobalComponentItem('componentItem', e) }} value={componentItem?.elementType} size="small">
  1827. <Option value="GH"><FollowAcc />关注公众号</Option>
  1828. <Option value="ENTERPRISE_WX"><WxAutoSvg />添加商家微信</Option>
  1829. </Select>
  1830. </div>
  1831. </div>
  1832. {componentItem?.elementType === 'GH' ? <>
  1833. <div className="form section">
  1834. <Space>
  1835. <Switch size="small" checked={componentItem?.fastFollow} onChange={(e) => { setGlobalComponentItem('componentItem', { ...componentItem, fastFollow: e ? 1 : 0 }) }} />
  1836. 一键关注
  1837. <Tooltip placement="top" title={'唤起公众号简介的半屏面板,点击其中按钮直接关注公众号'}>
  1838. <QuestionCircleOutlined />
  1839. </Tooltip>
  1840. </Space>
  1841. </div>
  1842. </> : null}
  1843. <div className="form section">
  1844. <div className="form-caption">按钮外观</div>
  1845. <div className="adui-form-item" style={{ marginBottom: 10 }}>
  1846. <div className="adui-form-label">按钮文案</div>
  1847. <div className="adui-form-control">
  1848. <div className="fl-sb">
  1849. <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
  1850. <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', border: '1px solid #d9d9d9', borderRadius: 2, paddingRight: 8 }}>
  1851. <Input maxLength={5} style={{ width: 90 }} bordered={false} value={componentItem?.btnTitle} onChange={(e) => { setGlobalComponentItem('componentItem', { ...componentItem, btnTitle: e.target.value }) }} /> <span>{componentItem?.btnTitle?.length}/5</span>
  1852. </div>
  1853. </div>
  1854. <Radio.Group onChange={(e) => { setGlobalComponentItem('componentItem', { ...componentItem, btnFontType: e.target.value }) }} value={componentItem?.btnFontType}>
  1855. <Radio.Button value={0}>常规</Radio.Button>
  1856. <Radio.Button value={1}>加粗</Radio.Button>
  1857. </Radio.Group>
  1858. </div>
  1859. </div>
  1860. </div>
  1861. <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
  1862. <div className="adui-form-label">字体色</div>
  1863. <div className="adui-form-control">
  1864. <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('componentItem', { ...componentItem, fontColor: color }) }} color={componentItem?.fontColor}></ColorPicker><div className="colorShow">{componentItem?.fontColor}</div></Space>
  1865. </div>
  1866. </div>
  1867. <div className="adui-form-item" style={{ alignItems: 'center', marginBottom: 10 }}>
  1868. <div className="adui-form-label">填充色</div>
  1869. <div className="adui-form-control">
  1870. <Space><ColorPicker onColor={(color: string) => { setGlobalComponentItem('componentItem', { ...componentItem, btnBgColorTheme: color }) }} color={componentItem?.btnBgColorTheme}></ColorPicker><div className="colorShow">{componentItem?.btnBgColorTheme}</div></Space>
  1871. </div>
  1872. </div>
  1873. </div>
  1874. </div>
  1875. </div> :
  1876. null
  1877. }
  1878. </>
  1879. } else {
  1880. return null
  1881. }
  1882. }
  1883. /** 选择单张图片 */
  1884. const clickUpdateImg = useCallback((num: number) => {
  1885. setSliderImgContent([])
  1886. setCcType(1)
  1887. setSelectImgVisible(true)
  1888. }, [imgSize, scType, content, sliderImgContent])
  1889. /** 选择视频 */
  1890. const clickUpdateVideo = useCallback(() => {
  1891. setCcType(2)
  1892. setSelectImgVisible(true)
  1893. }, [imgSize, scType])
  1894. /** 弹窗返回设置图片 */
  1895. const setImg = useCallback((value: any[]) => {
  1896. setSelectImgVisible(false)
  1897. let newContent = JSON.parse(JSON.stringify(content))
  1898. let selectIndex = newContent?.findIndex((item: Content) => item.comptActive)
  1899. let oldContent = newContent
  1900. if (scType === 1) { // 图片
  1901. if (selectIndex !== -1) {
  1902. let selectCon = oldContent[selectIndex]
  1903. selectCon['imageUrl'] = value[0]?.url
  1904. selectCon['width'] = Number(value[0]?.width)
  1905. selectCon['height'] = Number(value[0]?.height)
  1906. oldContent[selectIndex] = { ...selectCon }
  1907. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  1908. }
  1909. } else if (scType === 2) { // 视频要判断是否是长视频 还是短视频
  1910. if (selectIndex !== -1) {
  1911. let selectCon = oldContent[selectIndex]
  1912. selectCon['width'] = value[0]?.width
  1913. selectCon['height'] = value[0]?.height
  1914. selectCon['videoUrl'] = value[0]?.url
  1915. oldContent[selectIndex] = { ...selectCon }
  1916. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  1917. }
  1918. } else if (scType === 3) { // 轮播
  1919. if (selectIndex !== -1) {
  1920. let urlList = value?.map(item => item?.url)
  1921. let selectCon = oldContent[selectIndex]
  1922. selectCon.imageUrlList = selectCon.imageUrlList?.reduce((prev: any[], cur: any, index: number) => {
  1923. prev.push(urlList[index] || "")
  1924. return prev
  1925. }, [])
  1926. oldContent[selectIndex] = { ...selectCon }
  1927. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  1928. }
  1929. } else if (scType === 4) { // 设置图文复合组件图片
  1930. if (selectIndex !== -1) {
  1931. let selectCon = oldContent[selectIndex]
  1932. if (selectCon?.type === '104') {
  1933. let componentItem = selectCon?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  1934. componentItem[0] = {
  1935. ...componentItem[0],
  1936. pureImageUrl: value[0]?.content
  1937. }
  1938. oldContent[selectIndex] = { ...selectCon }
  1939. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  1940. } else if (selectCon?.type === '103') {
  1941. let componentItem = selectCon?.layoutItems.componentItem[goodsCount]
  1942. let shelfnewItem = componentItem?.layoutItems?.componentItem[0]?.layoutItems?.componentItem
  1943. shelfnewItem[0].pureImageUrl = value[0]?.content
  1944. oldContent[selectIndex] = { ...selectCon }
  1945. dispatch({ type: 'setCon', params: { content: [...oldContent] } })
  1946. }
  1947. }
  1948. } else if (scType === 5) { // 设置悬浮组件
  1949. let newConItem = JSON.parse(JSON.stringify(componentItem))
  1950. let selectIndex = newConItem?.findIndex((item: Content) => item.comptActive)
  1951. let oldContent = newConItem
  1952. if (selectIndex !== -1) {
  1953. let selectCon = oldContent[selectIndex]
  1954. selectCon['imageUrl'] = value[0]?.url
  1955. dispatchGlobal({ type: 'setConItem', params: { componentItem: JSON.parse(JSON.stringify(oldContent)) } })
  1956. }
  1957. }
  1958. }, [content, scType, goodsCount])
  1959. /** 回填数据 */
  1960. const editSelectImg = useCallback((url: any[]) => {
  1961. setSelectImgVisible(true)
  1962. }, [selectImgVisible])
  1963. /** 下一步 */
  1964. const nextHandle = useCallback(() => {
  1965. if (content.length === 1) {
  1966. message.error('请完善内容')
  1967. return
  1968. }
  1969. if (((content[0]?.elementType === "TOP_IMAGE") && !content[0].imageUrl) || content[0]?.elementType === "empty") {
  1970. message.error('请完善顶部组件内容')
  1971. return
  1972. }
  1973. if (content[0]?.elementType === "TOP_SLIDER" && !content[0].imageUrlList?.every((item: string) => item)) {
  1974. message.error('请完善轮播图组件内容~~')
  1975. return
  1976. }
  1977. if (content[0]?.elementType === "TOP_VIDEO" && !content[0].videoUrl) {
  1978. message.error('请完善顶部视频组件内容~~')
  1979. return
  1980. }
  1981. let reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?/;
  1982. let a = content?.every((item: any) => {
  1983. if (item?.elementType === "GH") {
  1984. if (item?.btnTitle) {
  1985. return true
  1986. } else {
  1987. message.error('关注公众号按钮按钮文案未填写')
  1988. return false
  1989. }
  1990. } else if (item?.elementType === "link") {
  1991. if (!reg.test(item?.origBtnJumpUrl)) {
  1992. message.error('跳转链接按钮请输入正确链接')
  1993. return false
  1994. }
  1995. if (item?.btnTitle) {
  1996. return true
  1997. } else {
  1998. message.error('关注公众号按钮按钮文案未填写')
  1999. return false
  2000. }
  2001. } else if (item?.elementType === "IMAGE") {
  2002. if (item.imageUrl) {
  2003. return true
  2004. } else {
  2005. message.error('请选择图片')
  2006. return false
  2007. }
  2008. } else if (item?.elementType === "TEXT") {
  2009. if (item.text) {
  2010. return true
  2011. } else {
  2012. message.error('请完善文本内容')
  2013. return false
  2014. }
  2015. } else if (item?.elementType === "ENTERPRISE_WX") {
  2016. if (item?.btnTitle) {
  2017. return true
  2018. } else {
  2019. message.error('客服组按钮按钮文案未填写')
  2020. return false
  2021. }
  2022. } else if (item?.elementType === "shelfnew") {
  2023. return true
  2024. } else {
  2025. return true
  2026. }
  2027. })
  2028. if (componentItem?.length > 0) {
  2029. let b = componentItem?.every((item: any) => {
  2030. if (item?.elementType === "FLOAT_BUTTON") {
  2031. if (item?.styleType === 0) {
  2032. if (!item?.imageUrl) {
  2033. message.error('悬浮组件请上传图片')
  2034. return false
  2035. }
  2036. if (!item?.title) {
  2037. message.error('悬浮组件请输入标题')
  2038. return false
  2039. }
  2040. if (!item?.desc) {
  2041. message.error('悬浮组件请输入描述')
  2042. return false
  2043. }
  2044. } else if (item?.wxad_styleType === 1) {
  2045. if (!item?.title) {
  2046. message.error('悬浮组件请输入标题')
  2047. return false
  2048. }
  2049. if (!item?.desc) {
  2050. message.error('悬浮组件请输入描述')
  2051. return false
  2052. }
  2053. } else if (item?.wxad_styleType === 2) {
  2054. if (!item?.title) {
  2055. message.error('悬浮组件请输入标题')
  2056. return false
  2057. }
  2058. }
  2059. }
  2060. return true
  2061. })
  2062. if (b) {
  2063. } else {
  2064. return
  2065. }
  2066. }
  2067. if (a) {
  2068. setLastVisible(true)
  2069. }
  2070. }, [lastVisible, state, componentItem])
  2071. /** 保存 */
  2072. const saveHandle = useCallback(() => {
  2073. let { content, pageBackColor } = state
  2074. if (!shareTittle || !shareDesc) {
  2075. message.error('请填写分享标题或者描述')
  2076. return
  2077. }
  2078. let layoutName: string = pageName
  2079. if (!pageName) {
  2080. layoutName = `${id ? '复制' : ''}原生推广页` + moment().format("YYYYMMDDHHmmss") + '_' + currentUser?.userId
  2081. }
  2082. let pageContextList: Array<ImgProps | TopImg | TopVideo | TopSlider | Text | GhButton> = content?.map((item: { elementType: string, comptActive: boolean, activeIndex: boolean }) => {
  2083. let { elementType, comptActive, activeIndex, ...data } = item
  2084. let typeKey = getTypeKey(elementType)
  2085. let newItem = { elementType }
  2086. newItem[typeKey] = data
  2087. return newItem
  2088. })
  2089. let globalSpec: any = {}
  2090. if (componentItem?.length > 0) {
  2091. let globalElementsSpecList = componentItem?.map((item: { elementType: string, comptActive: boolean, componentItem: { elementType: string } }) => {
  2092. let { elementType, comptActive, componentItem, ...data } = item
  2093. let typeKey = getTypeKey(elementType);
  2094. let newItem = { elementType };
  2095. (data as any).elementType = componentItem.elementType
  2096. if (componentItem?.elementType) {
  2097. let { elementType, ...data1 } = componentItem
  2098. let type1Key = getTypeKey(elementType);
  2099. data[type1Key] = data1
  2100. }
  2101. newItem[typeKey] = data
  2102. return newItem
  2103. })
  2104. globalSpec.globalElementsSpecList = globalElementsSpecList
  2105. } else {
  2106. globalSpec = null
  2107. }
  2108. let pageSpecs = {
  2109. bgColor: pageBackColor,
  2110. pageElementsSpecList: pageContextList
  2111. }
  2112. let params = {
  2113. mediaType: 'PAGE',
  2114. folder: false,
  2115. parentId,
  2116. title: layoutName,
  2117. pageName: layoutName,
  2118. belongUser: belongUser === '0' ? false : true,
  2119. sort,
  2120. pageSpecsList: [pageSpecs],
  2121. globalSpec,
  2122. shareContentSpec: {
  2123. shareTitle: shareTittle,
  2124. shareDescription: shareDesc
  2125. }
  2126. }
  2127. add.run(params).then(res => {
  2128. if (res) {
  2129. ajax.refresh()
  2130. hideModal && hideModal()
  2131. }
  2132. })
  2133. }, [state, shareTittle, pageName, parentId, sort, shareDesc, belongUser, currentUser, ajax, id, componentItem])
  2134. return <Drawer
  2135. title={
  2136. <div className={style.drawerTitle}>
  2137. <div>
  2138. <Space>
  2139. <span>{id ? '复制' : '创建'}推广页</span>
  2140. </Space>
  2141. </div>
  2142. <Button type='primary' size='small' className={style.next} onClick={() => { nextHandle() }}>下一步 <SwapRightOutlined /></Button>
  2143. </div>
  2144. }
  2145. placement="right"
  2146. onClose={() => {
  2147. modal.confirm(config);
  2148. }}
  2149. visible={visible}
  2150. width='90%'
  2151. className={`addDraw ${style.drawer}`}
  2152. >
  2153. {/* 选择素材 */}
  2154. {selectImgVisible && <SelectCloud visible={selectImgVisible} sliderImgContent={sliderImgContent} onClose={() => setSelectImgVisible(false)} onChange={setImg} />}
  2155. <Modal
  2156. title={<>
  2157. <div style={{ marginBottom: 2, color: '#1f1f1f' }}>分享设置</div>
  2158. <div style={{ color: '#a3a3a3', fontSize: 12 }}>设置推广页的分享样式</div>
  2159. </>}
  2160. visible={lastVisible}
  2161. confirmLoading={add.loading}
  2162. onOk={saveHandle}
  2163. onCancel={() => { setLastVisible(false) }}
  2164. >
  2165. <Form labelCol={{ span: 4 }}>
  2166. <Form.Item label="落地页名称">
  2167. <Space><Input placeholder='落地页名称(不填写,创建时间+创建者ID)' value={pageName} onChange={(e) => { setPageName(e.target.value) }} style={txtLength(pageName) > 60 ? { width: 300, borderColor: 'red' } : { width: 300 }} /><span style={txtLength(pageName) > 60 ? { color: 'red' } : {}}>{txtLength(pageName)}/60</span></Space>
  2168. </Form.Item>
  2169. <Form.Item label="分享标题">
  2170. <Space><Input placeholder='建议与详情页面主题相符' value={shareTittle} onChange={(e) => { setShareTittle(e.target.value) }} style={txtLength(shareTittle) > 20 ? { width: 300, borderColor: 'red' } : { width: 300 }} /><span style={txtLength(shareTittle) > 20 ? { color: 'red' } : {}}>{txtLength(shareTittle)}/20</span></Space>
  2171. </Form.Item>
  2172. <Form.Item label="分享描述">
  2173. <Space><Input placeholder='对标题的简要解读' style={txtLength(shareDesc) > 30 ? { width: 300, borderColor: 'red' } : { width: 300 }} value={shareDesc} onChange={(e) => { setShareDesc(e.target.value) }} /><span style={txtLength(shareTittle) > 30 ? { color: 'red' } : {}}>{txtLength(shareDesc)}/30</span></Space>
  2174. </Form.Item>
  2175. <Form.Item label="排序" tooltip="值越大越靠前">
  2176. <InputNumber placeholder='输入排序' min={0} value={sort} onChange={(e) => { setSort(e) }} />
  2177. </Form.Item>
  2178. </Form>
  2179. </Modal>
  2180. <Spin spinning={get.loading}>
  2181. <div className={style.boxCont}>
  2182. <Row className={style.row}>
  2183. <Col flex="320px" className={style.right}>
  2184. <div className={style.title}>顶部组件</div>
  2185. <div className={style.assembly}>
  2186. {
  2187. content[0].elementType === 'empty' ? <>
  2188. <div {...getDragProps(`TOP_IMAGE`)}> <Topimg /> <span>图片</span> </div>
  2189. <div {...getDragProps(`TOP_SLIDER`)}> <Topslider /> <span>轮播图</span> </div>
  2190. <div {...getDragProps(`TOP_VIDEO`)}> <Topvideo /> <span>视频</span></div>
  2191. </>
  2192. :
  2193. <>
  2194. <div className={style.disabled}> <Topimg /> <span>图片</span> </div>
  2195. <div className={style.disabled}> <Topslider /> <span>轮播图</span> </div>
  2196. <div className={style.disabled}> <Topvideo /> <span>视频</span></div>
  2197. </>
  2198. }
  2199. </div>
  2200. <div className={style.title}>基础组件</div>
  2201. <div className={style.assembly}>
  2202. <div {...getDragPropsCon(`IMAGE`)}> <Img /> <span className="my">图片</span> </div>
  2203. <div {...getDragPropsCon(`TEXT`)}> <MyText /> <span>文字</span> </div>
  2204. </div>
  2205. <div className={style.title}>转化按钮</div>
  2206. <div className={style.assembly}>
  2207. <div {...getDragPropsCon(`GH`)}> <FollowAcc /> <span className="my">关注公众号</span> </div>
  2208. {/* <div {...getDragPropsCon(`JumpLink`)}> <JumpLink /> <span className="my">跳转链接</span> </div> */}
  2209. <div {...getDragPropsCon(`ENTERPRISE_WX`)}> <WxAutoSvg /> <span className="my">添加商家微信</span> </div>
  2210. </div>
  2211. <div className={style.title}>营销组件</div>
  2212. <div className={style.assembly}>
  2213. {/* <div {...getDragPropsCon(`shelfnew`)}> <ImgText /> <span className="my">图文复合组件</span> </div> */}
  2214. {componentItem?.some((item: { elementType: string }) => item.elementType === 'FLOAT_BUTTON') ?
  2215. <div className={style.disabled}> <FloatbuttonSvg /> <span>悬浮组件</span></div> : <div {...getDragPropsCon(`FLOAT_BUTTON`)}> <FloatbuttonSvg /> <span className="my">悬浮组件</span></div>
  2216. }
  2217. </div>
  2218. </Col>
  2219. <Col flex="auto" className={style.center} onClick={installActiveNull}>
  2220. <div className={style.page} style={{ backgroundColor: pageBackColor || '#FFFFFF' }}>
  2221. {/* 头部 */}
  2222. <div>{topCon}</div>
  2223. {/* 内容*/}
  2224. <div className={`comptPlaceholder lastChild`} id="comptCon">
  2225. {comptCon()}
  2226. </div>
  2227. <div className={style.sidebar}>
  2228. <div>
  2229. <ColorPicker onColor={(color: string) => { dispatch({ type: 'setPageBackColor', params: { pageBackColor: color } }) }} color={pageBackColor}></ColorPicker>
  2230. <div style={{ marginTop: 4 }}>背景</div>
  2231. </div>
  2232. </div>
  2233. </div>
  2234. </Col>
  2235. <Col flex="380px" className={style.left}>{rightCon()}</Col>
  2236. </Row>
  2237. </div>
  2238. </Spin>
  2239. </Drawer>
  2240. }
  2241. export default React.memo(AddLandingPage)