wjx 5 months ago
parent
commit
9791d579f3

+ 2 - 1
src/pages/launchSystemV3/components/DynamicTooltip/index.tsx

@@ -19,7 +19,7 @@ const DynamicTooltip: React.FC<Props> = ({ data: dynamicData }) => {
 
     /************************************/
     const { deliveryMode, creativeTemplateId, dynamicCreativeName, creativeComponents, configuredStatus } = dynamicData
-    const { textLink, actionButton, showData, brand, mainJumpInfo, creativeLabelDTOS, creativeBarrageDTOS, floatingZoneComponent } = creativeComponents || {}
+    const { textLink, actionButton, showData, brand, mainJumpInfo, creativeLabelDTOS, creativeBarrageDTOS, creativeFirstReplyDTO, floatingZoneComponent } = creativeComponents || {}
 
     const [profileData, setprofileData] = useState<any>()
     const getProfiles = useAjax((params) => getProfilesApi(params))
@@ -94,6 +94,7 @@ const DynamicTooltip: React.FC<Props> = ({ data: dynamicData }) => {
                 {floatingZoneComponent?.floatingZoneDesc && <p>文案:{floatingZoneComponent.floatingZoneDesc}</p>}
                 {floatingZoneComponent?.floatingZoneButtonText && <p>按钮文案:{floatingZoneComponent.floatingZoneButtonText}</p>}
             </>}
+            {creativeFirstReplyDTO?.text && <p>首评:{creativeFirstReplyDTO?.text}</p>}
         </>}
     </div>
 }

+ 19 - 0
src/pages/launchSystemV3/components/TextAideInput/index.less

@@ -60,4 +60,23 @@
         vertical-align: middle;
         image-rendering: -webkit-optimize-contrast;
     }
+}
+
+.InputGroup {
+    display: flex;
+    border: 1px solid #d9d9d9;
+    border-radius: 8px;
+
+    .emojiBtn {
+        height: 32px;
+        padding: 0 10px;
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        border-left: 1px solid #d9d9d9;
+
+        &:hover {
+            color: #1890ff;
+        }
+    }
 }

+ 9 - 7
src/pages/launchSystemV3/components/TextAideInput/index.tsx

@@ -1,6 +1,6 @@
 import { useAjax } from "@/Hook/useAjax"
 import { txtLength } from "@/utils/utils";
-import { Button, Input, InputRef, List, Popover } from "antd";
+import { Input, InputRef, List, Popover } from "antd";
 import React, { useEffect, useRef } from "react"
 import { useState } from "react";
 import './index.less'
@@ -17,6 +17,7 @@ interface Props {
     maxTextLength?: number;
     isShowAjax?: boolean
     isSelectEmoji?: boolean
+    disabled?: boolean
     putInType?: 'NOVEL' | 'GAME'
 }
 
@@ -28,7 +29,7 @@ interface Props {
 const TextAideInput: React.FC<Props> = (props) => {
 
     /************************/
-    const { value, onChange, style, placeholder, maxTextLength = 10, isShowAjax = true, isSelectEmoji = true, putInType } = props
+    const { value, onChange, style, placeholder, maxTextLength = 10, isShowAjax = true, isSelectEmoji = true, disabled, putInType } = props
     const [text, setText] = useState<any>(value)
     const [descriptionShow, setDescriptionshow] = useState(false)
     const [cursorPosition, setCursorPosition] = useState<number | null>(null);
@@ -87,13 +88,14 @@ const TextAideInput: React.FC<Props> = (props) => {
                 }}><span >{item.text}{item.tag && <span className="crt">{'CTR 高'}</span>}</span></List.Item>}
             />}
         >
-
-            <Input.Group compact>
+            <div className="InputGroup">
                 <Input
                     ref={inputRef}
                     placeholder={placeholder}
                     style={style}
                     value={text}
+                    bordered={false}
+                    disabled={disabled}
                     onFocus={() => {
                         if (isShowAjax) {
                             setDescriptionshow(true)
@@ -116,7 +118,7 @@ const TextAideInput: React.FC<Props> = (props) => {
                     }}
                     allowClear
                 />
-                {isSelectEmoji && <Popover
+                {isSelectEmoji && !disabled && <Popover
                     placement="bottomRight"
                     overlayClassName="emoji"
                     content={<div className="emoji-list-scroll">
@@ -127,9 +129,9 @@ const TextAideInput: React.FC<Props> = (props) => {
                         setEmojiOpen(e)
                     }}
                 >
-                    <Button><SmileOutlined /></Button>
+                    <div className="emojiBtn"><SmileOutlined /></div>
                 </Popover>}
-            </Input.Group>
+            </div>
         </Popover>
         <span>{`${txtLength(text)}/${maxTextLength}`}</span>
     </div>

+ 2 - 2
src/pages/launchSystemV3/tencenTasset/copyWriting/modifyCopyWriting.tsx

@@ -30,7 +30,7 @@ const ModifyCopyWriting: React.FC<Props> = ({ visible, initialValues, onClose, o
             console.log(valid)
             let params = JSON.parse(JSON.stringify(valid))
             if (params?.contentList) {
-                params.contentList = params?.contentList?.split(/[,,\n\s]+/ig).filter((item: any) => item)
+                params.contentList = params?.contentList?.split(/[\n\s]+/ig).filter((item: any) => item)
             }
             if (initialValues?.id) {
                 params.id = initialValues.id
@@ -69,7 +69,7 @@ const ModifyCopyWriting: React.FC<Props> = ({ visible, initialValues, onClose, o
                 <Input allowClear placeholder="请输入文案" />
             </Form.Item> : <Form.Item label={<strong>文案</strong>} name="contentList" rules={[{ required: true, message: '请输入文案!' }]}>
                 <Input.TextArea
-                    placeholder="请输入文案(多个,,空格换行)"
+                    placeholder="请输入文案(多个空格或者换行)"
                     allowClear
                     rows={6}
                 />

+ 40 - 5
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeConversionAssistant.tsx

@@ -5,7 +5,7 @@ import style from '../index.less'
 import New1Radio from "@/pages/launchSystemV3/components/New1Radio";
 import { useUpdateEffect } from "ahooks";
 import { QuestionCircleFilled } from "@ant-design/icons";
-import { txtLength } from "@/utils/utils";
+import { extractAndFilterBracketsContent, txtLength } from "@/utils/utils";
 import TextAideInput from "@/pages/launchSystemV3/components/TextAideInput";
 import styles from '../Material/index.less'
 import SelectLabel from "./SelectLable"
@@ -19,7 +19,8 @@ import SelectBarrage from "./SelectBarrage";
 const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean, putInType?: 'NOVEL' | 'GAME' }> = ({ automaticSiteEnabled, putInType }) => {
 
     /**************************************/
-    const { creativeComponents, form, isUpdate, setIsUpdate } = useContext(DispatchDynamic)!;
+    const { creativeComponents, form, isUpdate, setIsUpdate, adgroups } = useContext(DispatchDynamic)!;
+    const { siteSet } = adgroups
     const textLinkShow = Form.useWatch('textLinkShow', form)
     const actionButtonShow = Form.useWatch('actionButtonShow', form)
     const showDataShow = Form.useWatch('showDataShow', form)
@@ -31,6 +32,7 @@ const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean, pu
     const floatingZoneSwitch = Form.useWatch(['floatingZone', 'value', 'floatingZoneSwitch'], form)
     const floatingZoneType = Form.useWatch(['floatingZone', 'value', 'floatingZoneType'], form)
     const image = Form.useWatch(['floatingZone', 'value', 'image'], form)
+    const pageType = Form.useWatch(['jumpInfo', 'pageType'], form)
     const creativeTemplateId = Form.useWatch('creativeTemplateId', form)
     const cardType: string[] = Form.useWatch('cardType', form)
     const [cardData, setCardData] = useState<{ label: string, value: string, disabled?: boolean }[]>([])
@@ -287,9 +289,9 @@ const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean, pu
     const barrageContent = useMemo(() => {
         let barrage = creativeComponents?.barrage;
         if (barrage) {
-            return <Form.Item 
-                name={'creativeBarrageDTOS'} 
-                style={{ marginTop: 16, marginBottom: 0 }} 
+            return <Form.Item
+                name={'creativeBarrageDTOS'}
+                style={{ marginTop: 16, marginBottom: 0 }}
                 label={<strong>&nbsp;&nbsp;&nbsp;弹幕{barrage.required ? '' : '(选填)'}</strong>}
                 rules={[
                     {
@@ -569,6 +571,38 @@ const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean, pu
         return null
     }, [creativeComponents?.floating_zone, floatingZoneSwitch, floatingZoneType, image])
 
+
+    /** 微信朋友首评论 */
+    const socialSkillContent = useMemo(() => {
+        if ((automaticSiteEnabled || siteSet.includes('SITE_SET_MOMENTS')) && ![717, 727].includes(creativeTemplateId)) {
+            const disabled = !["PAGE_TYPE_WECHAT_CHANNELS_PROFILE", "PAGE_TYPE_WECHAT_OFFICIAL_ACCOUNT_DETAIL"].includes(pageType)
+            return <Form.Item
+                name={['creativeFirstReplyDTO', 'text']}
+                label={<strong>&nbsp;&nbsp;&nbsp;首评(选填)</strong>}
+                rules={[{
+                    required: false, validator: (rule, value) => {
+                        if (value) {
+                            if (!value.match(RegExp("^[^\\<\\>\\&'\\\"\\x08\\x09\\x0A\\x0D\\\\]+$"))) {
+                                return Promise.reject('请输入正确的首评')
+                            } else if (txtLength(value) > 30) {
+                                return Promise.reject('请输入正确的首评')
+                            }
+                            const result = extractAndFilterBracketsContent(value);
+                            if (result.extracted.length > 1) {
+                                return Promise.reject('表情数量不得超出: 1 个')
+                            }
+                        }
+                        return Promise.resolve()
+                    }
+                }]}
+                help={disabled ? <span style={{ color: 'red' }}>只有【品牌形象】是公众号和视频号支持</span> : null}
+            >
+                <TextAideInput placeholder={'请输入首评'} disabled={disabled} style={{ width: 750 }} isShowAjax={false} maxTextLength={30} putInType={putInType} />
+            </Form.Item>
+        }
+        return null
+    }, [automaticSiteEnabled, siteSet, creativeTemplateId, pageType])
+
     useEffect(() => {
         let data = [
             { label: '不使用', value: 'not', disabled: false },
@@ -645,6 +679,7 @@ const CreativeConversionAssistant: React.FC<{ automaticSiteEnabled?: boolean, pu
             {barrageContent}
             {showDataContent}
             {floatingZoneContent}
+            {socialSkillContent}
 
             {/* 选择视频素材 */}
             {(selectVideoVisible && selectCloudData) && <SelectCloudNew

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/creativeTemplateContent.tsx

@@ -53,7 +53,7 @@ const CreativeTemplateContent: React.FC<{ automaticSiteEnabled: boolean, putInTy
         return <>
             {brand && <Form.Item style={{ marginBottom: 0 }}>
                 <Form.Item name={['jumpInfo', 'pageType']} label={<strong>品牌形象跳转</strong>} rules={[{ required: true, message: '请选择品牌形象跳转!' }]} tooltip="品牌形象将在各流量版位下广告外层创意展示。此外,朋友圈广告在此基础上支持跳转,点击品牌形象可跳转到品牌简介页或搜一搜品牌主页">
-                    <New1Radio data={enumeration} onChange={() => form.setFieldsValue({ brand: undefined })} />
+                    <New1Radio data={enumeration} onChange={() => form.setFieldsValue({ brand: undefined, creativeFirstReplyDTO: undefined })} />
                 </Form.Item>
                 {['PAGE_TYPE_H5_PROFILE'].includes(pageType) ? <div style={{ margin: '0 0 10px', backgroundColor: '#fafafb', padding: '8px 16px 8px', borderRadius: 8 }}>
                     <Form.Item name='brand' style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择一个头像及昵称跳转页,与广告创意一起展示' }]}>

+ 2 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx

@@ -18,7 +18,7 @@ const Dynamic: React.FC<{ creativeTemplateAppellation?: string, creativeTemplate
     const { addelivery, setAddelivery, clearData, setAccountCreateLogs, accountCreateLogs, putInType } = useContext(DispatchAddelivery)!;
     const { adgroups, dynamic: dynamicData } = addelivery;
     const { deliveryMode, creativeTemplateId, dynamicCreativeName, creativeComponents, configuredStatus } = dynamicData
-    const { textLink, actionButton, showData, brand, mainJumpInfo, floatingZoneComponent, creativeLabelDTOS, creativeBarrageDTOS } = creativeComponents || {}
+    const { textLink, actionButton, showData, brand, mainJumpInfo, floatingZoneComponent, creativeLabelDTOS, creativeBarrageDTOS, creativeFirstReplyDTO } = creativeComponents || {}
     const [newVisible, setNewVisible] = useState<boolean>(false);
     const [profileData, setprofileData] = useState<any>()
 
@@ -97,6 +97,7 @@ const Dynamic: React.FC<{ creativeTemplateAppellation?: string, creativeTemplate
                         {floatingZoneComponent?.floatingZoneDesc && <p>文案:{floatingZoneComponent.floatingZoneDesc}</p>}
                         {floatingZoneComponent?.floatingZoneButtonText && <p>按钮文案:{floatingZoneComponent.floatingZoneButtonText}</p>}
                     </>}
+                    {creativeFirstReplyDTO?.text && <p>首评:{creativeFirstReplyDTO?.text}</p>}
                 </>}
             </div>
             <div className={style.detail_footer}>

+ 12 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx

@@ -126,7 +126,7 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
                 if (creativeTemplateStyle.includes('视频')) {
                     goalTypeData.push({ label: '视频', value: 'video' })
                 }
-                if (creativeTemplateStyle.includes('图片')) {
+                if (creativeTemplateStyle.includes('图片') || creativeTemplateStyle.includes('其他')) {
                     goalTypeData.push({ label: '图片', value: 'image' })
                 }
                 setMarketingGoalTypeList(goalTypeData)
@@ -334,6 +334,7 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
             floatingZone,
             creativeLabelDTOS,
             creativeBarrageDTOS,
+            creativeFirstReplyDTO,
             ...surplusValues
         } = values
 
@@ -451,6 +452,11 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
             creativeComponents.creativeBarrageDTOS = creativeBarrageDTOS
         }
 
+        // 首评
+        if (creativeFirstReplyDTO?.text) {
+            creativeComponents.creativeFirstReplyDTO = creativeFirstReplyDTO
+        }
+
         // 数据外显
         if (showDataShow) {
             creativeComponents.showData = [showData]
@@ -495,14 +501,16 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
                     mainJumpInfo,
                     floatingZoneComponent,
                     creativeLabelDTOS,
-                    creativeBarrageDTOS
+                    creativeBarrageDTOS,
+                    creativeFirstReplyDTO
                 },
                 ...surplusValues
             } = JSON.parse(JSON.stringify(value))
             let dynamicValues: any = {
                 ...surplusValues,
                 creativeLabelDTOS,
-                creativeBarrageDTOS
+                creativeBarrageDTOS,
+                creativeFirstReplyDTO
             }
             // if (value.deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
             //     getTemplate(value.creativeTemplateId)
@@ -660,7 +668,7 @@ const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onCl
                                 </Form.Item>
                                 <Form.Item name="creativeTemplateId" label={<strong>创意形式</strong>} rules={[{ required: true, message: '请选择营销目的!' }]}>
                                     <New2Radio
-                                        data={adcreativeTemplateList.filter(item => creativeTemplateStyle === 'video' ? item.creativeTemplateStyle === '视频' : item.creativeTemplateStyle === '图片')}
+                                        data={adcreativeTemplateList.filter(item => creativeTemplateStyle === 'video' ? item.creativeTemplateStyle === '视频' : (item.creativeTemplateStyle === '图片' || item.creativeTemplateStyle === '其他'))}
                                         onChange={(id) => { getTemplate(id, true); }}
                                     />
                                 </Form.Item>

+ 3 - 3
src/pages/launchSystemV3/tencentAdPutIn/create/Material/addMaterial.tsx

@@ -172,7 +172,6 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
         })
         return `${imageCount}张图片,${videoCount}个视频,${arrayImgCount}个组图`
     }
-    console.log('dynamicGroup---->', dynamicGroup)
 
     return <Modal
         title={<Space>
@@ -385,6 +384,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                                     <Dropdown
                                         menu={{
                                             items: [
+                                                { label: '1:1 九图', key: '1', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 9) } },
                                                 { label: '1:1 六图', key: '1', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 6) } },
                                                 { label: '1:1 三图', key: '2', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 3) } },
                                                 { label: '1:1 四图', key: '3', disabled: dynamicGroup?.[num]?.['list']?.length >= 15, onClick: () => { selectGroupImg(num, 4) } },
@@ -530,7 +530,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                                                     }, 100)
                                                 }}>
                                                     {Array(item.arrayProperty.maxNumber).fill('').map((arr, index1) => {
-                                                        return <p key={index1} style={item.arrayProperty.maxNumber >= 3 ? { width: 130, height: 130 } : { justifyContent: 'center' }}>
+                                                        return <p key={index1} style={item.arrayProperty.maxNumber === 9 ? { width: 92, height: 92 } : item.arrayProperty.maxNumber >= 3 ? { width: 130, height: 130 } : { justifyContent: 'center' }}>
                                                             {dynamicGroup?.length > 0 && dynamicGroup[num] && Object.keys(dynamicGroup[num])?.includes(name) && dynamicGroup[num][name][index1] ? <img src={dynamicGroup[num][name][index1]['url']} /> : <>
                                                                 <span>{`推荐尺寸(${imageData.restriction.imageRestriction.width} x ${imageData.restriction.imageRestriction.height})`}</span>
                                                                 <span>{`${imageData.restriction.imageRestriction.fileFormat?.map((str: any) => str?.replace('IMAGE_TYPE_', ''))};小于 ${imageData.restriction.imageRestriction.fileSize}KB`}</span>
@@ -571,7 +571,7 @@ const AddMaterial: React.FC<Props> = ({ creativeTemplateId, materialData, delive
                                                     return <div className={styles.boxList_body_item} key={index}>
                                                         <div className={styles.tag}>{length}图</div>
                                                         <div className={styles.content}>
-                                                            {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length === 6 ? 33.3 : 49.9 }} />)}
+                                                            {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length >= 6 ? 33.3 : 49.9 }} />)}
                                                         </div>
                                                         <div className={styles.clear} onClick={() => { clearTem(num, index) }}><CloseCircleOutlined /></div>
                                                     </div>

+ 2 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Material/index.tsx

@@ -94,7 +94,7 @@ const Material: React.FC<{ adData?: any[] }> = ({ adData }) => {
                         <div className={style.detail_body_m}>
                             {dynamicMaterialDTos.dynamicGroup.map((item: any, index: number) => {
                                 if (deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
-                                    return <div key={index} style={{ width: deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? [641, 642, 643].includes(creativeTemplateId) ? '100%' : [720, 721, 722, 1529, 618].includes(creativeTemplateId) ? '50%' : '25%' : '100%' }}>
+                                    return <div key={index} style={{ width: deliveryMode === 'DELIVERY_MODE_CUSTOMIZE' ? [641, 642, 643, 2277].includes(creativeTemplateId) ? '100%' : [720, 721, 722, 1529, 618].includes(creativeTemplateId) ? '50%' : '25%' : '100%' }}>
                                         <Title level={5} style={{ fontSize: 12 }}>创意组{index + 1}</Title>
                                         {mType ? ['short_video', 'video'].includes(mType) ? <div className={style.video}>
                                             <VideoNews src={item?.video_id?.url || item?.short_video1?.url} keyFrameImageUrl={item?.video_id?.keyFrameImageUrl || item?.short_video1?.keyFrameImageUrl}/>
@@ -123,7 +123,7 @@ const Material: React.FC<{ adData?: any[] }> = ({ adData }) => {
                                                     return <div className={styles.boxList_body_item} key={index} style={{ width: 60, height: 60 }}>
                                                         <div className={styles.tag}>{length}图</div>
                                                         <div className={styles.content} style={{ width: 60, height: 60 }}>
-                                                            {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length === 6 ? 19.9 : 29.9 }} />)}
+                                                            {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length >= 6 ? 19.9 : 29.9 }} />)}
                                                         </div>
                                                     </div>
                                                 } else if (item?.url?.includes('mp4') || item?.keyFrameImageUrl) {

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/tableConfig.tsx

@@ -154,7 +154,7 @@ const columns = (): TableProps<any>['columns'] => {
                                             let length = item.length
                                             return <div className={styles.boxList_body_item} key={index} style={{ width: 30, height: 30 }}>
                                                 <div className={styles.content} style={{ width: 30, height: 30 }}>
-                                                    {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length === 6 ? 9.999 : 14.999 }} />)}
+                                                    {item.map((l, i) => <img src={l?.url} key={i} style={{ width: length >= 6 ? 9.999 : 14.999 }} />)}
                                                 </div>
                                             </div>
                                         } else if (item?.url?.includes('mp4') || item?.keyFrameImageUrl) {