wjx il y a 6 mois
Parent
commit
3b1b3acb10
23 fichiers modifiés avec 779 ajouts et 70 suppressions
  1. 6 0
      config/routerConfig.ts
  2. 12 5
      src/pages/launchSystemV3/components/ConversionSelect/index.tsx
  3. 34 14
      src/pages/launchSystemV3/components/TargetingTooltip/index.tsx
  4. 2 2
      src/pages/launchSystemV3/tencenTasset/corpWechat/index.tsx
  5. 268 0
      src/pages/launchSystemV3/tencenTasset/game/index.tsx
  6. 75 0
      src/pages/launchSystemV3/tencenTasset/game/modify.tsx
  7. 106 0
      src/pages/launchSystemV3/tencenTasset/game/tableConfig.tsx
  8. 17 2
      src/pages/launchSystemV3/tencenTasset/targeting/index.tsx
  9. 13 2
      src/pages/launchSystemV3/tencenTasset/targeting/tableConfig.tsx
  10. 35 3
      src/pages/launchSystemV3/tencentAdPutIn/const.ts
  11. 13 5
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx
  12. 22 10
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx
  13. 6 5
      src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx
  14. 4 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/index.tsx
  15. 7 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx
  16. 80 8
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx
  17. 3 1
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/dataItem.tsx
  18. 5 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/index.tsx
  19. 7 4
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx
  20. 3 2
      src/pages/launchSystemV3/tencentAdPutIn/create/Target/tableConfig.tsx
  21. 1 0
      src/pages/launchSystemV3/tencentAdPutIn/create/index.tsx
  22. 1 0
      src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts
  23. 59 1
      src/services/adqV3/global.ts

+ 6 - 0
config/routerConfig.ts

@@ -180,6 +180,12 @@ const launchSystemV3 = {
                     path: '/launchSystemV3/tencenTasset/corpWechat',
                     access: 'corpWechat',
                     component: './launchSystemV3/tencenTasset/corpWechat',
+                },
+                {
+                    name: '游戏库',
+                    path: '/launchSystemV3/tencenTasset/game',
+                    access: 'game',
+                    component: './launchSystemV3/tencenTasset/game',
                 }
             ],
         },

+ 12 - 5
src/pages/launchSystemV3/components/ConversionSelect/index.tsx

@@ -13,6 +13,7 @@ import { useUpdateEffect } from "ahooks"
  */
 interface Props {
     adgroups: any
+    putInType?: 'NOVEL' | 'GAME'
     visible?: boolean,
     onClose?: () => void,
     onChange?: (data: PULLIN.AccountCreateLogsProps[]) => void,
@@ -21,7 +22,7 @@ interface Props {
 const ConversionSelect: React.FC<Props> = (props) => {
 
     /************************/
-    const { visible, onClose, data: data1, onChange, adgroups } = props
+    const { putInType, visible, onClose, data: data1, onChange, adgroups } = props
     const [tableData, setTableData] = useState<any[]>([])//table数据
     const [selectAdz, setSelectAdz] = useState<number>(1)   // 选择广告主
     const [data, setData] = useState<PULLIN.AccountCreateLogsProps[]>(data1)
@@ -42,12 +43,18 @@ const ConversionSelect: React.FC<Props> = (props) => {
         } else {
             setTableData([])
         }
-    }, [accountId, adgroups, conversionName])
+    }, [accountId, adgroups, conversionName, putInType])
 
     // 获取公众号列表
     const getList = (accountId: number) => {
-        let { optimizationGoal, deepConversionSpec, siteSet } = adgroups
-        getConversionInfo.run({ accountId, pageNum: 1, pageSize: 100, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet }).then(res => {
+        let { optimizationGoal, deepConversionSpec, siteSet, marketingSubGoal, marketingGoal } = adgroups
+        let params: { [x: string]: any } = {}
+        if (putInType === 'NOVEL') {
+            params = { accountId, pageNum: 1, pageSize: 100, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+        } else {
+            params = { accountId, pageNum: 1, pageSize: 100, marketingGoal, marketingSubGoal, conversionName, createSourceType: 'SELF_CREATED', optimizationGoal, deepWorthOptimizationGoal: deepConversionSpec?.deepConversionWorthSpec?.goal, siteSet, taskType: putInType }
+        }
+        getConversionInfo.run(params).then(res => {
             setTableData(res?.records || [])
         })
     }
@@ -159,7 +166,7 @@ const ConversionSelect: React.FC<Props> = (props) => {
             </div>
             <div className={style.right}>
                 <Space style={{ marginBottom: 10 }} align="end" size={0}>
-                    <Input.Search enterButton allowClear onSearch={(value) => setConversionName(value)} placeholder="搜索转化名称"/>
+                    <Input.Search enterButton allowClear onSearch={(value) => setConversionName(value)} placeholder="搜索转化名称" />
                     <Button icon={<SyncOutlined />} type='link' loading={getConversionInfo?.loading} onClick={() => { getList(data[selectAdz - 1].accountId) }}>刷新</Button>
                     {/* {data?.length > 1 && <Button disabled={!data[selectAdz - 1]['newConversionList']?.length} onClick={() => setOnekey()} type="link" loading={getConversionInfo.loading}>
                         <Space>

+ 34 - 14
src/pages/launchSystemV3/components/TargetingTooltip/index.tsx

@@ -1,8 +1,8 @@
 import React, { useEffect, useState } from "react"
 import './index.less'
-import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM } from "../../tencentAdPutIn/const"
+import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, GAME_CONSUMPTION_LEVEL_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM, WECHAT_AD_NEHAVIOR_GAME_ENUM } from "../../tencentAdPutIn/const"
 
-const targetingData = [
+let targetingData = [
     { key: 'geoLocation', name: '地域' },
     { key: 'age', name: '年龄' },
     { key: 'gender', name: '性别' },
@@ -22,6 +22,7 @@ interface Props {
     geoLocationList: any // 所有地域
     modelList: any  // 所有品牌手机
     targetingName?: string
+    taskType?: 'NOVEL' | 'GAME'
 }
 interface ContentProps {
     unlimited?: string,         // 不限
@@ -43,6 +44,7 @@ interface ContentProps {
     devicePrice?: string[]      // 手机价格
     userOs?: string[]           // 手机系统
     excludedOs?: string[]           // 手机系统
+    gameConsumptionLevel?: string[] // 游戏消费能力
     excludedConvertedAudience?: {
         conversionBehaviorList: string[],
         excludedDimension: string
@@ -55,9 +57,14 @@ interface ContentProps {
 const TargetingTooltip: React.FC<Props> = (props) => {
 
     /**********************/
-    const { data, geoLocationList, modelList, targetingName } = props
+    const { data, geoLocationList, modelList, targetingName, taskType } = props
     const [content, setContent] = useState<ContentProps>({})
     /**********************/
+
+    if (taskType == 'GAME') {
+        targetingData = [...targetingData, { key: 'gameConsumptionLevel', name: '游戏消费能力' }]
+    }
+
     useEffect(() => {
         if (data && geoLocationList) {
             let newConten: ContentProps = {}
@@ -114,6 +121,9 @@ const TargetingTooltip: React.FC<Props> = (props) => {
                     case 'devicePrice':
                         newConten.devicePrice = data[item]
                         break
+                    case 'gameConsumptionLevel':
+                        newConten.gameConsumptionLevel = data[item]
+                        break
                     case 'userOs':
                         newConten.userOs = data[item]
                         break
@@ -136,7 +146,7 @@ const TargetingTooltip: React.FC<Props> = (props) => {
     return <div className='targetingTooltip'>
         {targetingName && <div style={{ fontWeight: 'bold', marginBottom: 4 }}>{targetingName}</div>}
         {content?.geoLocation && <div>
-            <strong>地域:</strong><span>{(content?.location && content?.location?.length > 0) && `(${content?.location?.map((key: string) => LOCATION_TYPES_ENUM[key]).toString()})`}{content?.geoLocation?.toString()}</span>
+            <strong>地域:</strong><span>{(content?.location && content?.location?.length > 0) && `(${content?.location?.map((key: string) => LOCATION_TYPES_ENUM[key as keyof typeof LOCATION_TYPES_ENUM]).toString()})`}{content?.geoLocation?.toString()}</span>
         </div>}
         {content?.age && <div>
             <strong>年龄:</strong><span>{content?.age}</span>
@@ -145,22 +155,25 @@ const TargetingTooltip: React.FC<Props> = (props) => {
             <strong> 性别:</strong><span>{content?.gender === 'MALE' ? '男' : '女'}</span>
         </div>}
         {(content?.education && content?.education?.length > 0) && <div>
-            <strong>学历:</strong><span>{content?.education?.map((key: string) => EDUCATION_ENUM[key]).toString()}</span>
+            <strong>学历:</strong><span>{content?.education?.map((key: string) => EDUCATION_ENUM[key as keyof typeof EDUCATION_ENUM]).toString()}</span>
         </div>}
         {(content?.networkType && content?.networkType?.length > 0) && <div>
-            <strong>联网方式:</strong><span>{content?.networkType?.map((key: string) => NETWORK_ENUM[key]).toString()}</span>
+            <strong>联网方式:</strong><span>{content?.networkType?.map((key: string) => NETWORK_ENUM[key as keyof typeof NETWORK_ENUM]).toString()}</span>
         </div>}
         {(content?.devicePrice && content?.devicePrice?.length > 0) && <div>
-            <strong> 手机价格:</strong><span>{content?.devicePrice?.map((key: string) => DEVICE_PRICE_ENUM[key]).toString()}</span>
+            <strong>手机价格:</strong><span>{content?.devicePrice?.map((key: string) => DEVICE_PRICE_ENUM[key as keyof typeof DEVICE_PRICE_ENUM]).toString()}</span>
+        </div>}
+        {(content?.gameConsumptionLevel && content?.gameConsumptionLevel?.length > 0) && <div>
+            <strong>游戏消费能力:</strong><span>{content?.gameConsumptionLevel?.map((key: string) => GAME_CONSUMPTION_LEVEL_ENUM[key as keyof typeof GAME_CONSUMPTION_LEVEL_ENUM]).toString()}</span>
         </div>}
         {(content?.userOs && content?.userOs?.length > 0) && <div>
-            <strong>操作系统:</strong><span>{content?.userOs?.map((key: string) => USER_OS_ENUM[key]).toString()}</span>
+            <strong>操作系统:</strong><span>{content?.userOs?.map((key: string) => USER_OS_ENUM[key as keyof typeof USER_OS_ENUM]).toString()}</span>
         </div>}
         {(content?.excludedOs && content?.excludedOs?.length > 0) && <div>
-            <strong>排除操作系统:</strong><span>{content?.excludedOs?.map((key: string) => USER_OS_ENUM[key]).toString()}</span>
+            <strong>排除操作系统:</strong><span>{content?.excludedOs?.map((key: string) => USER_OS_ENUM[key as keyof typeof USER_OS_ENUM]).toString()}</span>
         </div>}
         {(content?.maritalStatus && content?.maritalStatus?.length > 0) && <div>
-            <strong>婚恋:</strong><span>{content?.maritalStatus?.map((key: string) => MARITAL_STATUS_ENUM[key]).toString()}</span>
+            <strong>婚恋:</strong><span>{content?.maritalStatus?.map((key: string) => MARITAL_STATUS_ENUM[key as keyof typeof MARITAL_STATUS_ENUM]).toString()}</span>
         </div>}
         {content?.deviceBrandModel && <>
             {(content?.deviceBrandModel?.includedList && content?.deviceBrandModel?.includedList?.length > 0) && <div>
@@ -170,16 +183,23 @@ const TargetingTooltip: React.FC<Props> = (props) => {
                 <strong>排除品牌型号:</strong><span>{content?.deviceBrandModel?.excludedList?.toString()}</span>
             </div>}
         </>}
-        {content?.wechatAdBehavior && <>
+        {content?.wechatAdBehavior && taskType === 'GAME' ? <>
+            {(content?.wechatAdBehavior?.actions && content?.wechatAdBehavior?.actions?.length > 0) && <div>
+                <strong>再营销:</strong><span>{content?.wechatAdBehavior?.actions?.map((key: string) => WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM]).toString()}</span>
+            </div>}
+            {(content?.wechatAdBehavior?.excludedActions && content?.wechatAdBehavior?.excludedActions?.length > 0) && <div>
+                <strong>排除营销:</strong><span>{content?.wechatAdBehavior?.excludedActions?.map((key: string) => WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM]).toString()}</span>
+            </div>}
+        </> : <>
             {(content?.wechatAdBehavior?.actions && content?.wechatAdBehavior?.actions?.length > 0) && <div>
-                <strong> 再营销:</strong><span>{content?.wechatAdBehavior?.actions?.map((key: string) => WECHAT_AD_NEHAVIOR_ENUM[key]).toString()}</span>
+                <strong>再营销:</strong><span>{content?.wechatAdBehavior?.actions?.map((key: string) => WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM]).toString()}</span>
             </div>}
             {(content?.wechatAdBehavior?.excludedActions && content?.wechatAdBehavior?.excludedActions?.length > 0) && <div>
-                <strong>排除营销:</strong><span>{content?.wechatAdBehavior?.excludedActions?.map((key: string) => WECHAT_AD_NEHAVIOR_ENUM[key]).toString()}</span>
+                <strong>排除营销:</strong><span>{content?.wechatAdBehavior?.excludedActions?.map((key: string) => WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM]).toString()}</span>
             </div>}
         </>}
         {content?.excludedConvertedAudience && <div>
-            <strong>排除已转化用户:</strong><span>{EXCLUDED_DIMENSION_ENUM[content?.excludedConvertedAudience?.excludedDimension]}{`(自定义转化行为:${content?.excludedConvertedAudience?.conversionBehaviorList?.map(item => OPTIMIZATIONGOAL_ENUM[item])?.toString()})`}</span>
+            <strong>排除已转化用户:</strong><span>{EXCLUDED_DIMENSION_ENUM[content?.excludedConvertedAudience?.excludedDimension as keyof typeof EXCLUDED_DIMENSION_ENUM]}{`(自定义转化行为:${content?.excludedConvertedAudience?.conversionBehaviorList?.map(item => OPTIMIZATIONGOAL_ENUM[item as keyof typeof OPTIMIZATIONGOAL_ENUM])?.toString()})`}</span>
         </div>}
         {content?.unlimited && <div>
             <strong>不限:</strong><span>{!content?.geoLocation && '地域,'}{content?.unlimited}</span>

+ 2 - 2
src/pages/launchSystemV3/tencenTasset/corpWechat/index.tsx

@@ -1,12 +1,12 @@
 import { useAjax } from "@/Hook/useAjax";
-import { delCorpWechatApi, getCorpWechatAllApi, getCorpWechatApi, getCorpWechatDetailApi, getWechatAppletAllApi, getWechatAppletDetailApi } from "@/services/adqV3/global";
+import { delCorpWechatApi, getCorpWechatAllApi, getCorpWechatApi, getCorpWechatDetailApi } from "@/services/adqV3/global";
 import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
 import { Button, Card, Divider, Input, message, Select, Table, Typography } from "antd";
 import React, { useEffect, useState } from "react"
 import '../../tencentAdPutIn/index.less'
 import Modify from "./modify";
 import columns from "./tableConfig";
-const { Text, Link, Paragraph } = Typography;
+const { Text, Paragraph } = Typography;
 
 /**
  * 企业微信

+ 268 - 0
src/pages/launchSystemV3/tencenTasset/game/index.tsx

@@ -0,0 +1,268 @@
+import { useAjax } from "@/Hook/useAjax";
+import { delGameApi, getGameLibraryApi, getGameLibraryDetailApi, getGameLibraryListApi } from "@/services/adqV3/global";
+import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
+import { Button, Card, Divider, Input, message, Select, Spin, Table, Typography } from "antd";
+import React, { useEffect, useState } from "react"
+import '../../tencentAdPutIn/index.less'
+import Modify from "./modify";
+import columns from "./tableConfig";
+const { Text, Paragraph } = Typography;
+
+/**
+ * 游戏库
+ * @returns 
+ */
+const Game: React.FC = () => {
+
+    /**********************************/
+    const [queryForm, setQueryForm] = useState<{ pageNum: number, pageSize: number, gameName?: string, idList?: number[], gameType?: string }>({ pageNum: 1, pageSize: 20 })
+    const [queryFormNew, setQueryFormNew] = useState<{ pageNum: number, pageSize: number, gameName?: string, idList?: number[], gameType?: string }>({ pageNum: 1, pageSize: 20 })
+    const [visible, setVisible] = useState<boolean>(false)
+
+    const getGameLibraryList = useAjax((params) => getGameLibraryListApi(params))
+    const delGame = useAjax((params) => delGameApi(params))
+    /**********************************/
+
+    useEffect(() => {
+        getGameLibraryList.run(queryFormNew)
+    }, [queryFormNew])
+
+    const del = (id: number) => {
+        delGame.run(id).then(res => {
+            if (res) {
+                message.success('删除成功')
+                getGameLibraryList.refresh()
+            }
+        })
+    }
+
+    return <Card
+        className="cardResetCss"
+        title={<div className="flexStart" style={{ gap: 8 }}>
+            <Input style={{ width: 200 }} placeholder="请输入游戏名称" value={queryForm?.gameName} allowClear onChange={(e) => setQueryForm({ ...queryForm, gameName: e.target.value, pageNum: 1 })} />
+            <Select
+                showSearch
+                placeholder="请选择游戏类型"
+                onChange={(e) => setQueryForm({ ...queryForm, gameType: e, pageNum: 1 })}
+                filterOption={(input, option) =>
+                    (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
+                }
+                allowClear
+                style={{ width: 150 }}
+                options={[
+                    {
+                        value: 'WXGAME',
+                        label: '微信小游戏',
+                    }
+                ]}
+            />
+            <Input.TextArea
+                style={{ width: 300 }}
+                placeholder="请输入游戏ID(多个逗号隔开)"
+                allowClear
+                rows={1}
+                onChange={(e) => {
+                    let value = e.target.value
+                    let arr: any[] = []
+                    if (value) {
+                        value = value.replace(/[,,\s]/g, ',')
+                        arr = value.split(',').filter((a: any) => a)
+                    }
+                    setQueryForm({ ...queryForm, idList: arr, pageNum: 1 })
+                }}
+            />
+            <Button type="primary" icon={<SearchOutlined />} onClick={() => setQueryFormNew({ ...queryForm })}>搜索</Button>
+            <Button type="primary" icon={<PlusOutlined />} onClick={() => { setVisible(true) }}>新增游戏</Button>
+        </div>}
+    >
+
+        <Table
+            columns={columns(del)}
+            dataSource={getGameLibraryList.data?.records}
+            size="small"
+            loading={getGameLibraryList?.loading}
+            scroll={{ y: 600 }}
+            bordered
+            rowKey={'id'}
+            pagination={{
+                defaultPageSize: 20,
+                current: getGameLibraryList.data?.current || 1,
+                pageSize: getGameLibraryList.data?.size || 10,
+                total: getGameLibraryList.data?.total || 0
+            }}
+            onChange={(pagination) => {
+                const { current, pageSize } = pagination
+                setQueryForm({ ...queryForm, pageNum: current || 1, pageSize: pageSize || 10 })
+                setQueryFormNew({ ...queryForm, pageNum: current || 1, pageSize: pageSize || 10 })
+            }}
+        />
+
+        {/* 新增修改 */}
+        {visible && <Modify
+            visible={visible}
+            onClose={() => {
+                setVisible(false)
+            }}
+            onChange={() => {
+                setVisible(false)
+                getGameLibraryList.refresh()
+            }}
+        />}
+    </Card>
+}
+
+
+/**
+ * 选择游戏
+ * @param param0 
+ * @returns 
+ */
+export const SelectGame: React.FC<{ gameType: 'WXGAME', value?: string, onChange?: (value?: string) => void }> = ({ gameType, value, onChange }) => {
+
+    /*******************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const getGameLibrary = useAjax((params) => getGameLibraryApi(params))
+    /*******************************/
+
+    // 获取列表
+    useEffect(() => {
+        getGameLibrary.run({ gameType })
+    }, [gameType])
+
+    return <>
+        <Select
+            showSearch
+            allowClear
+            placeholder="请选择企微"
+            filterOption={(input: any, option: any) => {
+                return option!.name?.toString().toLowerCase().includes(input.toLowerCase())
+            }}
+            style={{ width: 480 }}
+            dropdownRender={menu => <>
+                {menu}
+                <Divider style={{ margin: '8px 0' }} />
+                <div>
+                    <Button type="link" onClick={() => {
+                        window.location.href = '/#/launchSystemV3/tencenTasset/game'
+                    }}>前往管理</Button>
+                    <Button type="link" style={{ paddingLeft: 0, paddingRight: 0 }} onClick={() => {
+                        setVisible(true)
+                    }}>新增</Button>
+                    {/* <Link href="/#/launchSystemV3/tencenTasset/miniProgramWechat" target="_blank">
+                    前往管理
+                </Link> */}
+                </div>
+            </>}
+            value={value}
+            onChange={(e) => onChange?.(e)}
+        >
+            {getGameLibrary?.data?.map((item: { id: number, appId: string, gameName: string }) => {
+                return <Select.Option value={item.id} key={item.id} name={item.gameName + `(${item.appId})`}><Text strong>{item.gameName}</Text><Text type="secondary">{`(${item.appId})`}</Text></Select.Option>
+            })}
+        </Select>
+        {/* 新增修改 */}
+        {visible && <Modify
+            visible={visible}
+            onClose={() => {
+                setVisible(false)
+            }}
+            onChange={() => {
+                setVisible(false)
+                getGameLibrary.refresh()
+            }}
+        />}
+    </>
+}
+
+/**
+ * 选择游戏
+ * @param param0 
+ * @returns 
+ */
+export const SelectGameAppId: React.FC<{ gameType: 'WXGAME', value?: string[], onChange?: (value?: string[]) => void }> = ({ gameType, value, onChange }) => {
+
+    /*******************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const getGameLibrary = useAjax((params) => getGameLibraryApi(params))
+    /*******************************/
+
+    // 获取列表
+    useEffect(() => {
+        getGameLibrary.run({ gameType })
+    }, [gameType])
+
+    return <>
+        <Select
+            showSearch
+            allowClear
+            placeholder="请选择游戏"
+            filterOption={(input: any, option: any) => {
+                return option!.name?.toString().toLowerCase().includes(input.toLowerCase())
+            }}
+            mode="multiple"
+            style={{ width: 480 }}
+            dropdownRender={menu => <>
+                {menu}
+                <Divider style={{ margin: '8px 0' }} />
+                <div>
+                    <Button type="link" onClick={() => {
+                        window.location.href = '/#/launchSystemV3/tencenTasset/game'
+                    }}>前往管理</Button>
+                    <Button type="link" style={{ paddingLeft: 0, paddingRight: 0 }} onClick={() => {
+                        setVisible(true)
+                    }}>新增</Button>
+                    {/* <Link href="/#/launchSystemV3/tencenTasset/miniProgramWechat" target="_blank">
+                    前往管理
+                </Link> */}
+                </div>
+            </>}
+            value={value}
+            onChange={(e) => onChange?.(e)}
+        >
+            {getGameLibrary?.data?.map((item: { id: number, appId: string, gameName: string }) => {
+                return <Select.Option value={item.appId} disabled={value && value?.length > 0 && !value.includes(item.appId)} key={item.id} name={item.gameName + `(${item.appId})`}><Text strong>{item.gameName}</Text><Text type="secondary">{`(${item.appId})`}</Text></Select.Option>
+            })}
+        </Select>
+        {/* 新增修改 */}
+        {visible && <Modify
+            visible={visible}
+            onClose={() => {
+                setVisible(false)
+            }}
+            onChange={() => {
+                setVisible(false)
+                getGameLibrary.refresh()
+            }}
+        />}
+    </>
+}
+
+
+/**
+ * 展示游戏
+ * @param param0 
+ * @returns 
+ */
+export const ShowGameDetail: React.FC<{ id: number }> = ({ id }) => {
+
+    /*******************************/
+    const getGameLibraryDetail = useAjax((params) => getGameLibraryDetailApi(params))
+    /*******************************/
+
+    // 获取列表
+    useEffect(() => {
+        if (id) {
+            getGameLibraryDetail.run(id)
+        }
+    }, [id])
+
+    return <Spin spinning={getGameLibraryDetail.loading}>
+        <Paragraph style={{ fontSize: 12, wordBreak: 'break-all', marginBottom: 0 }} ellipsis={{ rows: 2 }}>
+            {getGameLibraryDetail.data ? <>
+                <Text strong>游戏:{getGameLibraryDetail.data?.gameName}</Text><Text type="secondary">{`(${getGameLibraryDetail.data?.appId})`}</Text>
+            </> : id}
+        </Paragraph>
+    </Spin>
+}
+
+export default Game

+ 75 - 0
src/pages/launchSystemV3/tencenTasset/game/modify.tsx

@@ -0,0 +1,75 @@
+import { useAjax } from "@/Hook/useAjax"
+import { addGameApi } from "@/services/adqV3/global"
+import { Form, Input, message, Modal, Radio } from "antd"
+import React from "react"
+import '../../tencentAdPutIn/index.less'
+
+
+interface Props {
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+
+/**
+ * 新增游戏
+ * @returns 
+ */
+const Modify: React.FC<Props> = ({ visible, onChange, onClose }) => {
+
+    /********************************/
+    const [form] = Form.useForm()
+    const addGame = useAjax((params) => addGameApi(params))
+    /********************************/
+
+    const handleOk = () => {
+        form.validateFields().then(valid => {
+            console.log(valid)
+            addGame.run(valid).then(res => {
+                if (res) {
+                    message.success('新增成功')
+                    onChange?.()
+                }
+            })
+        })
+    }
+
+    return <Modal
+        title={<strong>{`新增游戏`}</strong>}
+        open={visible}
+        onCancel={onClose}
+        onOk={handleOk}
+        className="modalResetCss"
+        confirmLoading={addGame.loading}
+    >
+        <Form
+            name="basicMiniProgramWechat"
+            form={form}
+            layout='vertical'
+            autoComplete="off"
+            initialValues={{
+                gameType: 'WXGAME'
+            }}
+        >
+            <Form.Item label={<strong>游戏类型</strong>} name="gameType" rules={[{ required: true, message: '请选择游戏类型!' }]}>
+                <Radio.Group buttonStyle="solid">
+                    <Radio.Button value="WXGAME">微信小游戏</Radio.Button>
+                </Radio.Group>
+            </Form.Item>
+            <Form.Item label={<strong>游戏名称</strong>} name="gameName" rules={[{ required: true, message: '请输入游戏名称!' }]}>
+                <Input placeholder="请输入游戏名称" allowClear />
+            </Form.Item>
+            <Form.Item
+                label={<strong>appId</strong>}
+                name="appId"
+                rules={[
+                    { required: true, message: '请输入appId!' }
+                ]}
+            >
+                <Input placeholder="请输入appId" allowClear />
+            </Form.Item>
+        </Form>
+    </Modal>
+}
+
+export default React.memo(Modify)

+ 106 - 0
src/pages/launchSystemV3/tencenTasset/game/tableConfig.tsx

@@ -0,0 +1,106 @@
+import { copy } from "@/utils/utils"
+import { Space, Popconfirm, TableProps, Tag } from "antd"
+import React from "react"
+
+
+const columns = (del: (id: number) => void): TableProps<any>['columns'] => {
+
+
+    const data: TableProps<any>['columns'] = [
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            align: 'center',
+            width: 70,
+            render: (_, b) => {
+                return <Space>
+                    <Popconfirm
+                        title="确定删除?"
+                        onConfirm={() => del(b.id)}
+                        okText="是"
+                        cancelText="否"
+                    >
+                        <a style={{ color: 'red', fontSize: 12 }}>删除</a>
+                    </Popconfirm>
+                </Space>
+            }
+        },
+        {
+            title: 'ID',
+            dataIndex: 'id',
+            key: 'id',
+            width: 50,
+            align: 'center',
+            render: (a) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        },
+        {
+            title: '游戏名称',
+            dataIndex: 'gameName',
+            key: 'gameName',
+            ellipsis: true,
+            width: 180,
+            render: (a) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        },
+        {
+            title: '游戏类型',
+            dataIndex: 'gameType',
+            key: 'gameType',
+            width: 100,
+            align: 'center',
+            render: (a) => {
+                return a === 'WXGAME' ? <Tag color="#f50">微信小游戏</Tag> : '--'
+            }
+        },
+        {
+            title: 'appId',
+            dataIndex: 'appId',
+            key: 'appId',
+            ellipsis: true,
+            render: (a) => {
+                return <a style={{ fontSize: "12px" }} onClick={() => copy(a)}>{a}</a>
+            }
+        },
+        {
+            title: '创建人',
+            dataIndex: 'createByName',
+            key: 'createByName',
+            align: 'center',
+            width: 75,
+            ellipsis: true,
+            render: (a) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '更新人',
+            dataIndex: 'createByName',
+            key: 'createByName',
+            align: 'center',
+            width: 75,
+            ellipsis: true,
+            render: (a) => {
+                return <span style={{ fontSize: "12px" }}>{a || '--'}</span>
+            }
+        },
+        {
+            title: '创建时间',
+            dataIndex: 'createTime',
+            key: 'createTime',
+            align: 'center',
+            width: 140,
+            ellipsis: true,
+            render: (a) => {
+                return <span style={{ fontSize: "12px" }}>{a}</span>
+            }
+        }
+    ]
+
+    return data
+}
+
+export default columns

+ 17 - 2
src/pages/launchSystemV3/tencenTasset/targeting/index.tsx

@@ -42,12 +42,13 @@ const Targeting: React.FC = () => {
 
     /** 编辑 复制 */
     const editHandle = (data: any, isCopy?: boolean) => {
-        const { targetingName, targeting, description, id, accountId } = data
+        const { targetingName, targeting, description, id, accountId, taskType } = data
         let newModifyDta = {
             ...targeting,
             targetingName,
             description,
-            accountId: accountId || undefined
+            accountId: accountId || undefined,
+            taskType
         }
         if (!isCopy) {
             newModifyDta.id = id
@@ -73,6 +74,20 @@ const Targeting: React.FC = () => {
         className="cardResetCss"
         title={<div className="flexStart" style={{ gap: 8 }}>
             <Input style={{ width: 180 }} placeholder="请输入关键字查找" value={queryParams?.targetingName} allowClear onChange={(e) => setQueryParams({ ...queryParams, targetingName: e.target.value, pageNum: 1 })} />
+            <Select
+                style={{ width: 180 }}
+                showSearch
+                filterOption={(input, option) =>
+                    (option!.children as unknown as string)?.toLowerCase()?.includes(input?.toLowerCase())
+                }
+                allowClear
+                value={queryParams?.taskType}
+                onChange={(e) => setQueryParams({ ...queryParams, taskType: e })}
+                placeholder='请选择模板投放类型'
+            >
+                <Select.Option value={"GAME"}>游戏</Select.Option>
+                <Select.Option value={"NOVEL"}>小说</Select.Option>
+            </Select>
             <Select
                 style={{ width: 250 }}
                 showSearch

+ 13 - 2
src/pages/launchSystemV3/tencenTasset/targeting/tableConfig.tsx

@@ -1,4 +1,4 @@
-import { Button, Popconfirm, Popover, Space, Typography } from "antd";
+import { Button, Popconfirm, Popover, Space, Tag, Typography } from "antd";
 import { ColumnsType } from "antd/es/table";
 import React from "react";
 import TargetingTooltip from "../../components/TargetingTooltip";
@@ -24,6 +24,7 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
                             data={records?.targeting}
                             geoLocationList={geoLocationList}
                             modelList={modelList}
+                            taskType={records?.taskType}
                         />}
                     >
                         <QuestionCircleFilled />
@@ -31,6 +32,16 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
                 </div>
             }
         },
+        {
+            title: '类型',
+            dataIndex: 'taskType',
+            key: 'taskType',
+            align: 'center',
+            width: 70,
+            render(value) {
+                return value === 'GAME' ? <Tag color="#f50" style={{ fontSize: 12 }}>游戏</Tag> : value === 'NOVEL' ? <Tag color="#2db7f5" style={{ fontSize: 12 }}>小说</Tag> : <span style={{ fontSize: 12 }}>--</span>
+            },
+        },
         {
             title: '关联账户',
             dataIndex: 'accountId',
@@ -91,7 +102,7 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
             key: 'cz',
             align: 'center',
             fixed: 'right',
-            width: 100,
+            width: 120,
             render: (a: any, b: any) => {
                 return <Space wrap>
                     <Button type="link" style={{ padding: 0, fontSize: 12 }} onClick={() => { editHandle(b) }} >编辑</Button>

+ 35 - 3
src/pages/launchSystemV3/tencentAdPutIn/const.ts

@@ -22,6 +22,23 @@ export enum MARKETING_GOAL_ENUM {
 	MARKETING_GOAL_INCREASE_FANS_INTERACTION = '加粉互动'
 }
 
+/** 二级营销目的 */
+export enum MARKETING_SUB_GOAL_ENUM {
+	MARKETING_SUB_GOAL_NEW_GAME_RESERVE = '新游预约',
+	MARKETING_SUB_GOAL_NEW_GAME_TEST = '新游测试',
+	MARKETING_SUB_GOAL_NEW_GAME_LAUNCH = '新游首发',
+	MARKETING_SUB_GOAL_PLATEAU_PHASE_LAUNCH = '平推期投放',
+	MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH = '新客增长',
+	MARKETING_SUB_GOAL_MINI_GAME_RETURN_CUSTOMER_ENGAGEMENT = '回流触达',
+	MARKETING_SUB_GOAL_APP_ACQUISITION = '应用拉新',
+	MARKETING_SUB_GOAL_APP_ACTIVATION = '应用拉活',
+	MARKETING_SUB_GOAL_NOT_INSTALL_USER = '未安装用户',
+	MARKETING_SUB_GOAL_PRE_INSTALL_USER = '预安装用户',
+	MARKETING_SUB_GOAL_UNLOADED_USER = '已卸载用户',
+	MARKETING_SUB_GOAL_SHORT_INACTIVE_USER = '短期未活跃用户',
+	MARKETING_SUB_GOAL_LONG_INACTIVE_USER = '长期未活跃用户',
+}
+
 /** 营销目的 */
 export const marketingGoalList = [
 	{
@@ -482,9 +499,10 @@ export enum USER_OS_ENUM {
 	ANDROID_VERSION_12 = "Android12.x",
 	ANDROID_VERSION_13 = "Android13.x",
 	ANDROID_VERSION_14 = "Android14.x",
-	HARMONY = 'Harmony'
-	// WINDOWS = "Windows 系统", 
-	// SYMBIAN = "塞班系统", 
+	HARMONY = 'Harmony',
+	WINDOWS = "Windows系统", 
+	MAC = "Mac系统",
+	SYMBIAN = "塞班系统", 
 	// JAVA = "JAVA 系统"
 }
 
@@ -497,6 +515,11 @@ export enum DEVICE_PRICE_ENUM {
 	PRICE_4500_MORE = '¥4500以上',
 }
 
+/** 游戏消费能力 */
+export enum GAME_CONSUMPTION_LEVEL_ENUM {
+	HIGH = '高',
+	NORMAL = '普通'
+}
 
 /** 微信再营销 */
 export enum WECHAT_AD_NEHAVIOR_ENUM {
@@ -508,6 +531,15 @@ export enum WECHAT_AD_NEHAVIOR_ENUM {
 	// WECHAT_WORK_CONTACTS_ADDED = '已经添加过企业微信',
 }
 
+/** 游戏再营销 */
+export enum WECHAT_AD_NEHAVIOR_GAME_ENUM {
+	WECHAT_OFFICIAL_ACCOUNT_AD_LIKE = '曾对你的公众号广告感兴趣',
+	WECHAT_MOMENTS_AD_LIKE = '曾对你的朋友圈广告感兴趣',
+	MINI_GAME_WECHAT_REGISTERED = '曾经注册过你的小游戏',
+	GDT_WECHAT_OFFICIAL_ACCOUNT_FOLLOWED = '已关注过你的公众号',
+	WE_COM_CORP_ID_ADDED = '已经添加过企业微信',
+}
+
 /** 投放模式 */
 export enum DELIVERY_MODE_ENUM {
 	DELIVERY_MODE_COMPONENT = '组件化创意',

+ 13 - 5
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/adgroupsMarketingContent.tsx

@@ -11,6 +11,7 @@ import { adRules } from "../../rules"
 import { QuestionCircleFilled } from "@ant-design/icons"
 import { SelectMiniProgramWechat } from "@/pages/launchSystemV3/tencenTasset/miniProgramWechat"
 import { SelectCorpWechat } from "@/pages/launchSystemV3/tencenTasset/corpWechat"
+import { SelectGame } from "@/pages/launchSystemV3/tencenTasset/game"
 
 
 /**
@@ -61,7 +62,7 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
             if (bidMode === 'BID_MODE_OCPC' || bidMode === 'BID_MODE_OCPM') {
                 obj.bidMode = bidMode
             }
-            queryOptimizationGoalPermissions.run(obj)
+            queryOptimizationGoalPermissions.run({ ...obj, taskType: putInType })
         }
     }
 
@@ -69,7 +70,7 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
         if (OGPParams.marketingCarrierType && OGPParams.marketingTargetType) {
             getOptimizationGoalPermissions()
         }
-    }, [OGPParams])
+    }, [OGPParams, putInType])
 
     // 处理深度转化优化
     useEffect(() => {
@@ -141,13 +142,18 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
         }
     }, [marketingCarrierType, marketingCarrierTypeList, OGPParams, value, marketingTargetType])
 
+    // 切换 其他 优化目标更新
     useEffect(() => {
         let optimizationGoalPermissionList: string[] = queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList
         if (isUpdateOptimizationGoal && optimizationGoalPermissionList?.length > 0 && !optimizationGoalPermissionList?.includes(optimizationGoal)) {
-            form.setFieldsValue({ optimizationGoal: optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_ECOMMERCE_ORDER') ? 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER' : optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_PAGE_SCAN_CODE') ? 'OPTIMIZATIONGOAL_PAGE_SCAN_CODE' : undefined })
+            if (putInType === 'NOVEL') {
+                form.setFieldsValue({ optimizationGoal: optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_ECOMMERCE_ORDER') ? 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER' : optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_PAGE_SCAN_CODE') ? 'OPTIMIZATIONGOAL_PAGE_SCAN_CODE' : undefined })
+            } else if (putInType === 'GAME') {
+                form.setFieldsValue({ optimizationGoal: (optimizationGoalPermissionList?.includes('OPTIMIZATIONGOAL_ECOMMERCE_ORDER') ? 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER' : optimizationGoalPermissionList?.[0]) || undefined })
+            }
             setIsUpdateOptimizationGoal(false)
         }
-    }, [queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList, marketingGoal, marketingTargetType, marketingCarrierType, optimizationGoal, value, isUpdateOptimizationGoal])
+    }, [queryOptimizationGoalPermissions?.data?.optimizationGoalPermissionList, marketingGoal, marketingTargetType, marketingCarrierType, optimizationGoal, value, isUpdateOptimizationGoal, putInType])
 
     const setIsUpdate = () => {
         if (bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') {
@@ -194,12 +200,14 @@ const AdgroupsMarketingContent: React.FC<{ value?: any }> = ({ value }) => {
             <SelectMiniProgramWechat />
         </Form.Item> : marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_WORK' ? <Form.Item label={<strong>企业微信</strong>} name='sysCorpWechatId' rules={[{ required: true, message: '请选择企业微信' }]}>
             <SelectCorpWechat />
+        </Form.Item> : marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ? <Form.Item label={<strong>微信小游戏</strong>} name='sysWxGameId' rules={[{ required: true, message: '请选择微信小游戏' }]}>
+            <SelectGame gameType="WXGAME" />
         </Form.Item> : null}
         {marketingCarrierTypeList?.length > 0 && <Form.Item name="marketingCarrierType" label={<strong>营销载体类型</strong>} rules={[{ required: true, message: '请选择营销载体类型!' }]}>
             <New1Radio data={marketingCarrierTypeList} onChange={(e) => { setOGPparams({ ...OGPParams, marketingCarrierType: e }); setIsUpdate() }} />
         </Form.Item>}
         {(bidMode === 'BID_MODE_OCPM' || bidMode === 'BID_MODE_OCPC') && <>
-            {['MARKETING_CARRIER_TYPE_JUMP_PAGE', 'MARKETING_CARRIER_TYPE_APP_IOS', 'MARKETING_CARRIER_TYPE_APP_QUICK_APP'].includes(marketingCarrierType) && <Form.Item
+            {['MARKETING_CARRIER_TYPE_JUMP_PAGE', 'MARKETING_CARRIER_TYPE_APP_IOS', 'MARKETING_CARRIER_TYPE_APP_QUICK_APP', 'MARKETING_CARRIER_TYPE_WECHAT_MINI_GAME'].includes(marketingCarrierType) && <Form.Item
                 label={<Space>
                     <strong>转化归因新链路</strong>
                     <Tooltip title={<>

+ 22 - 10
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/index.tsx

@@ -4,11 +4,12 @@ import NewCreateAd from "./newCreateAd"
 import { DispatchAddelivery } from "..";
 import { Button, Modal, Typography } from "antd";
 import { EditOutlined } from "@ant-design/icons";
-import { AD_STATUS_ENUM, BID_MODE_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM, SITE_SET_ENUM, SMART_BID_TYPE_ENUM } from "../../const";
+import { AD_STATUS_ENUM, BID_MODE_ENUM, DEEP_CONVERSION_ENUM, GOAL_ROAS_ENUM, MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, OPTIMIZATIONGOAL_ENUM, SITE_SET_ENUM, SMART_BID_TYPE_ENUM } from "../../const";
 import TimeSeriesLook from "@/pages/launchSystemNew/adq/ad/timeSeriesLook";
 import { arraysHaveSameValues } from "@/utils/utils";
 import '../../index.less'
 import { ShowMiniProgramWechatDetail } from "@/pages/launchSystemV3/tencenTasset/miniProgramWechat";
+import { ShowGameDetail } from "@/pages/launchSystemV3/tencenTasset/game";
 
 /**
  * 广告信息
@@ -20,8 +21,8 @@ const Ad: React.FC = () => {
     const { addelivery, setAddelivery, accountCreateLogs, clearData, setAccountCreateLogs, putInType } = useContext(DispatchAddelivery)!;
     const { adgroups } = addelivery
     const {
-        marketingGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, siteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidAmount, optimizationGoal, isConversion, depthConversionEnabled,
-        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, sceneSpec, autoDerivedCreativeEnabled, sysWechatAppId
+        marketingGoal, marketingSubGoal, marketingAssetOuterSpec, marketingCarrierType, automaticSiteEnabled, siteSet, searchExpandTargetingSwitch, bidMode, smartBidType, bidAmount, optimizationGoal, isConversion, depthConversionEnabled,
+        deepConversionSpec, autoAcquisitionEnabled, autoAcquisitionBudget, dailyBudget, endDate, beginDate, timeSeries, firstDayBeginTime, configuredStatus, adgroupName, sceneSpec, autoDerivedCreativeEnabled, sysWechatAppId, sysWxGameId
     } = adgroups
     const [newVisible, setNewVisible] = useState<boolean>(false)
     /*****************************/
@@ -35,9 +36,19 @@ const Ad: React.FC = () => {
                 <div className={style.detail_body}>
                     {(adgroups && Object.keys(adgroups).length > 0) ? <>
                         <p style={{ fontWeight: 'bold', color: configuredStatus === 'AD_STATUS_NORMAL' ? '#52c41a' : '#FF4D4F' }}>广告状态:{AD_STATUS_ENUM[configuredStatus as keyof typeof AD_STATUS_ENUM]}</p>
-                        <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
-                        <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
-                        {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' && <ShowMiniProgramWechatDetail id={sysWechatAppId} />}
+                        {putInType === 'NOVEL' ? <>
+                            <p>营销目的:{MARKETING_GOAL_ENUM[marketingGoal as keyof typeof MARKETING_GOAL_ENUM]}</p>
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]}</p>
+                        </> : <>
+                            <p>营销目的:{MARKETING_SUB_GOAL_ENUM[marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM]}</p>
+                            <p style={{ fontWeight: 'bold', color: '#000' }}>推广产品类型:{MARKETING_TARGET_TYPE_GAME_ENUM[marketingAssetOuterSpec?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM]}</p>
+                        </>}
+                        {marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_MINI_PROGRAM_WECHAT' ?
+                            <ShowMiniProgramWechatDetail id={sysWechatAppId} /> :
+                            marketingAssetOuterSpec?.marketingTargetType === 'MARKETING_TARGET_TYPE_WECHAT_MINI_GAME' ?
+                                <ShowGameDetail id={sysWxGameId}/> :
+                                null
+                        }
                         <p>营销载体类型:{MARKETING_CARRIER_TYPE_ENUM[marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]}</p>
                         <p>版位选择:{automaticSiteEnabled ? '自动版位' : '选择特定版位'}</p>
                         {!automaticSiteEnabled && <Typography.Paragraph className={style.tpP} style={{ marginBottom: 0 }} ellipsis={{ tooltip: true, rows: 2 }}>广告版位:{siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}</Typography.Paragraph>}
@@ -106,8 +117,9 @@ const Ad: React.FC = () => {
                             return item
                         }))
                     }
-                    setAddelivery({ ...addelivery, adgroups })
                     setNewVisible(false)
+                    setAddelivery({ ...addelivery, adgroups })
+
                     clearData()
                 } else {
                     setAccountCreateLogs(accountCreateLogs.map(item => ({ accountId: item.accountId })))
@@ -126,20 +138,20 @@ const Ad: React.FC = () => {
                             cancelText: '不清空',
                             keyboard: false,
                             onOk() { // 清空
-                                setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
                                 setNewVisible(false)
+                                setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
                                 clearData()
                             },
                             onCancel() { // 不清空
-                                setAddelivery({ ...addelivery, adgroups })
                                 setNewVisible(false)
+                                setAddelivery({ ...addelivery, adgroups })
                                 clearData()
                             },
                             className: 'modalResetCss'
                         })
                     } else {
-                        setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
                         setNewVisible(false)
+                        setAddelivery({ adgroups, targeting: [], dynamic: {}, dynamicMaterialDTos: {}, dynamicCreativesTextDTOS: {}, mediaType: 0 })
                         clearData()
                     }
                 }

+ 6 - 5
src/pages/launchSystemV3/tencentAdPutIn/create/Ad/newCreateAd.tsx

@@ -29,7 +29,7 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose, putIn
     /***********************************/
     const [form] = Form.useForm();
     // 深度优化副作用参数
-    const [OGPParams, setOGPparams] = useState<PULLIN.OGPParamsProps>({ bidMode: 'BID_MODE_OCPM', siteSet: defaultSiteSet, automaticSiteEnabled: false, marketingGoal: putInType === 'NOVEL' ? defaultMarketingGoal :  defaultGameMarketingGoal, marketingSubGoal: putInType === 'GAME' ? 'MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH' : undefined })
+    const [OGPParams, setOGPparams] = useState<PULLIN.OGPParamsProps>({ bidMode: 'BID_MODE_OCPM', siteSet: defaultSiteSet, automaticSiteEnabled: false, marketingGoal: putInType === 'NOVEL' ? defaultMarketingGoal : defaultGameMarketingGoal, marketingSubGoal: putInType === 'GAME' ? 'MARKETING_SUB_GOAL_MINI_GAME_NEW_CUSTOMER_GROWTH' : undefined })
     /***********************************/
 
     const handleOk = (values: any) => {
@@ -51,7 +51,6 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose, putIn
             ...surplusValues
         } = values
         console.log(values)
-        return
         let adgroupsValues: any = {
             ...surplusValues,
             beginDate: moment(date?.[0]).format('YYYY-MM-DD'),
@@ -81,7 +80,7 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose, putIn
 
     // 数据回填
     useEffect(() => {
-        if (value && Object.keys(value).length > 0) {
+        if (value && Object.keys(value).length > 0 && visible) {
             const {
                 firstDayBeginTime,
                 timeSeries,
@@ -148,17 +147,19 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose, putIn
             } else {
                 adgroupsValues.displaySceneType = '0'
             }
+            console.log('------------------------------------>', adgroupsValues)
             setOGPparams({
                 bidMode: adgroupsValues.bidMode,
                 siteSet: adgroupsValues.siteSet,
                 automaticSiteEnabled: adgroupsValues.automaticSiteEnabled,
                 marketingGoal: adgroupsValues.marketingGoal,
+                marketingSubGoal: adgroupsValues.marketingSubGoal,
                 marketingCarrierType: adgroupsValues?.marketingCarrierType,
                 marketingTargetType: adgroupsValues?.marketingTargetType
             })
             form.setFieldsValue({ ...adgroupsValues })
         }
-    }, [value])
+    }, [value, visible])
 
     return <Modal
         title={<strong style={{ fontSize: 20 }}>广告的基本信息</strong>}
@@ -193,7 +194,7 @@ const NewCreateAd: React.FC<Props> = ({ value, visible, onChange, onClose, putIn
                 searchExpandTargetingSwitch: 'SEARCH_EXPAND_TARGETING_SWITCH_OPEN',
                 bidMode: 'BID_MODE_OCPM',
                 smartBidType: 'SMART_BID_TYPE_CUSTOM',
-                optimizationGoal: 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER',
+                optimizationGoal: putInType === 'NOVEL' ? 'OPTIMIZATIONGOAL_ECOMMERCE_ORDER' : 'OPTIMIZATIONGOAL_MOBILE_APP_AD_INCOME',
                 depthConversionEnabled: true,
                 deepConversionSpec: {
                     deepConversionType: 'DEEP_CONVERSION_WORTH'

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

@@ -15,7 +15,7 @@ import { useAjax } from "@/Hook/useAjax"
 const Dynamic: React.FC<{ creativeTemplateAppellation?: string, creativeTemplateStyle?: string }> = ({ creativeTemplateAppellation, creativeTemplateStyle }) => {
 
     /***************************************/
-    const { addelivery, setAddelivery, clearData, setAccountCreateLogs, accountCreateLogs } = useContext(DispatchAddelivery)!;
+    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 } = creativeComponents || {}
@@ -99,9 +99,11 @@ const Dynamic: React.FC<{ creativeTemplateAppellation?: string, creativeTemplate
                 <Button disabled={!(adgroups && Object.keys(adgroups)?.length > 0)} type="link" icon={<EditOutlined />} style={{ padding: 0, fontSize: 12 }} onClick={() => setNewVisible(true)}>编辑</Button>
             </div>
         </div>
-
+        
+        {/* 添加创意 */}
         {newVisible && <NewDynamic
             visible={newVisible}
+            putInType={putInType}
             creativeTemplateStyle={creativeTemplateStyle}
             value={dynamicData}
             onClose={() => {

+ 7 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Dynamic/newDynamic.tsx

@@ -17,6 +17,7 @@ import CreativeTemplateSetup from "./creativeTemplateSetup";
 export const DispatchDynamic = React.createContext<PULLIN.DynamicReactContent | null>(null);
 
 interface Props {
+    putInType?: 'NOVEL' | 'GAME'
     value?: any,
     visible?: boolean
     creativeTemplateStyle?: string,
@@ -29,7 +30,7 @@ interface Props {
  * @param param0 
  * @returns 
  */
-const NewDynamic: React.FC<Props> = ({ value: newValue, visible, onClose, onChange, creativeTemplateStyle: oldCreativeTemplateStyle }) => {
+const NewDynamic: React.FC<Props> = ({ putInType, value: newValue, visible, onClose, onChange, creativeTemplateStyle: oldCreativeTemplateStyle }) => {
 
     /**********************************/
     const { addelivery, setMaterialData, setTextData } = useContext(DispatchAddelivery)!;
@@ -42,7 +43,7 @@ const NewDynamic: React.FC<Props> = ({ value: newValue, visible, onClose, onChan
     const [adcreativeTemplateList, setAdcreativeTemplateList] = useState<PULLIN.AdcreativeTemplateList[]>([])
     const [creativeComponents, setCreativeComponents] = useState<any>({})
     const [isUpdate, setIsUpdate] = useState<boolean>(false)
-    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec, automaticSiteEnabled } = adgroups
+    const { marketingGoal, marketingAssetOuterSpec, marketingCarrierType, siteSet, sceneSpec, automaticSiteEnabled, marketingSubGoal } = adgroups
 
     const [newMaterialData, setNewMaterialData] = useState<any>({}) // 素材数据
     const [newTextData, setNewTextData] = useState<any>({})
@@ -172,6 +173,10 @@ const NewDynamic: React.FC<Props> = ({ value: newValue, visible, onClose, onChan
             } else {
                 params.siteSet = siteSet
             }
+            params.taskType = putInType
+            if (putInType === 'GAME') {
+                params.marketingSubGoal = marketingSubGoal
+            }
             getCreativeDetails.run(params).then(res => {
                 if (res?.adcreativeTemplateStructAdpermits?.length > 0) {
                     let adcreativeTemplateStructAdpermits = res?.adcreativeTemplateStructAdpermits[0]

+ 80 - 8
src/pages/launchSystemV3/tencentAdPutIn/create/Target/addTarget.tsx

@@ -1,7 +1,7 @@
 import { Button, Card, Checkbox, Form, Input, Modal, Radio, Select, Space, Spin, Tooltip, TreeSelect, Typography, message } from "antd"
 import React, { useEffect, useState } from "react"
 import style from '../index.less'
-import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM } from "../../const"
+import { DEVICE_PRICE_ENUM, EDUCATION_ENUM, EXCLUDED_DIMENSION_ENUM, GAME_CONSUMPTION_LEVEL_ENUM, GENDER_ENUM, LOCATION_TYPES_ENUM, MARITAL_STATUS_ENUM, NETWORK_ENUM, OPTIMIZATIONGOAL_ENUM, USER_OS_ENUM, WECHAT_AD_NEHAVIOR_ENUM, WECHAT_AD_NEHAVIOR_GAME_ENUM } from "../../const"
 import { QuestionCircleFilled } from "@ant-design/icons"
 import { getTargetingGagsApi } from "@/services/adqV3/global"
 import { useAjax } from "@/Hook/useAjax"
@@ -16,13 +16,14 @@ const { Title, Paragraph } = Typography;
 
 interface Props {
     isBackVal?: boolean
+    putInType?: 'NOVEL' | 'GAME'
     value?: any,
     visible?: boolean
     onClose?: () => void
     onChange?: (targeting?: any) => void
 }
 
-const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClose }) => {
+const AddTarget: React.FC<Props> = ({ isBackVal, putInType, value, visible, onChange, onClose }) => {
 
     /******************************/
     const [form] = Form.useForm();
@@ -37,10 +38,12 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
     const education = Form.useWatch('education', form);
     const networkType = Form.useWatch('networkType', form);
     const devicePrice = Form.useWatch('devicePrice', form);
+    const gameConsumptionLevel = Form.useWatch('gameConsumptionLevel', form);
     const excludedDimension = Form.useWatch(['excludedConvertedAudience', 'excludedDimension'], form);
     const conversionBehaviorList = Form.useWatch(['excludedConvertedAudience', 'conversionBehaviorList'], form);
     const actions = Form.useWatch(['wechatAdBehavior', 'actions'], form);
     const excludedActions = Form.useWatch(['wechatAdBehavior', 'excludedActions'], form);
+    const taskType: 'NOVEL' | 'GAME' = Form.useWatch('taskType', form) || putInType
 
     const [regionsList, setRegionsList] = useState<any[]>([])
     const [modelList, setModelList] = useState([])
@@ -158,8 +161,13 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                 }
             }
         })
-        setOsList([{ label: 'iOS系统', value: 'IOS', children: iosChildren }, { label: 'Android系统', value: 'ANDROID', children: androidChildren }, { label: 'Harmony', value: 'HARMONY', children: harmonyChildren }])
-    }, [USER_OS_ENUM])
+        let newOsList = [{ label: 'iOS系统', value: 'IOS', children: iosChildren }, { label: 'Android系统', value: 'ANDROID', children: androidChildren }, { label: 'Harmony', value: 'HARMONY', children: harmonyChildren }]
+        if (taskType === 'GAME') {
+            newOsList.push({ label: 'Windows系统', value: 'WINDOWS', children: [] })
+            newOsList.push({ label: 'Mac系统', value: 'MAC', children: [] })
+        }
+        setOsList(newOsList)
+    }, [USER_OS_ENUM, taskType])
 
     const handleOk = async (values: any) => {
         console.log(values)
@@ -183,7 +191,9 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             os,
             isExcludedOs,
             devicePrice,
+            gameConsumptionLevel,
             wechatAdBehaviorType,
+            taskType,
             ...surplusValues
         } = values
 
@@ -243,7 +253,12 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
         if (!devicePrice?.includes('0')) {
             targetValues.devicePrice = devicePrice
         }
+        // 游戏消费能力
+        if (!gameConsumptionLevel?.includes('0')) {
+            targetValues.gameConsumptionLevel = gameConsumptionLevel
+        }
         let targetingDTO = {
+            taskType: taskType || putInType,
             targetingName,
             description,
             accountId,
@@ -258,7 +273,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
 
         let checkData = await checkTargeting.run(value?.id ? { ...targetingDTO, id: value?.id } : targetingDTO)
         if (checkData?.[0]?.isSame) {
-            message.error('存在相同模板名称,请修改')
+            message.error('存在相同模板名称或内容,请修改')
             return
         }
         if (value?.id) {
@@ -296,6 +311,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                 excludedOs,
                 userOs,
                 devicePrice,
+                gameConsumptionLevel,
                 wechatAdBehavior,
                 ...surplusValues
             } = JSON.parse(JSON.stringify(value))
@@ -307,6 +323,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                 networkType: networkType || '0',
                 excludedConvertedAudience: excludedConvertedAudience || { excludedDimension: '0' },
                 devicePrice: devicePrice || '0',
+                gameConsumptionLevel: gameConsumptionLevel || '0',
                 wechatAdBehavior,
                 maritalStatus
             }
@@ -400,6 +417,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
             }}
             onFinish={handleOk}
             initialValues={{
+                taskType: 'NOVEL',
                 geoLocationType: '0',
                 maritalStatusType: '0',
                 deviceBrandModelType: '0',
@@ -414,6 +432,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                 education: ['0'],
                 networkType: ['0'],
                 devicePrice: ['0'],
+                gameConsumptionLevel: ['0'],
                 excludedConvertedAudience: {
                     excludedDimension: '0'
                 },
@@ -423,6 +442,29 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                 targetingName: (isBackVal ? '定向' : '定向模板') + '_' + localStorage.getItem('userId') + '_' + moment().format('MM_DD_HH:mm:ss')
             }}
         >
+            {!putInType && <Card
+                title={<strong style={{ fontSize: 18 }}>定向类型</strong>}
+                className="cardResetCss newCss"
+                bodyStyle={{ padding: '4px 6px' }}
+                style={{ marginBottom: 8 }}
+            >
+                <div className={style.newSpace}>
+                    <Form.Item name="taskType" label={<strong>投放类型</strong>} style={{ marginBottom: 0 }} rules={[{ required: true, message: '请选择定向类型' }]}>
+                        <Radio.Group onChange={(e) => {
+                            form.setFieldsValue({
+                                excludedConvertedAudience: {
+                                    excludedDimension: '0'
+                                },
+                                userOsType: '0',
+                                wechatAdBehaviorType: ['0']
+                            })
+                        }}>
+                            <Radio value="NOVEL">小说</Radio>
+                            <Radio value="GAME">游戏</Radio>
+                        </Radio.Group>
+                    </Form.Item>
+                </div>
+            </Card>}
             <Card
                 title={<strong style={{ fontSize: 18 }}>定向选择</strong>}
                 className="cardResetCss newCss"
@@ -622,7 +664,7 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                     >
                         <Radio.Group>
                             <Radio value="0">不限</Radio>
-                            {Object.keys(EXCLUDED_DIMENSION_ENUM).map(key => {
+                            {Object.keys(EXCLUDED_DIMENSION_ENUM).filter(key => taskType === 'GAME' ? ['EXCLUDED_DIMENSION_UID', 'EXCLUDED_DIMENSION_BUSINESS_MANAGER', 'EXCLUDED_DIMENSION_COMPANY_ACCOUNT', 'EXCLUDED_DIMENSION_APP'].includes(key) : true).map(key => {
                                 return <Radio value={key} key={key}>{EXCLUDED_DIMENSION_ENUM[key as keyof typeof EXCLUDED_DIMENSION_ENUM]}</Radio>
                             })}
                         </Radio.Group>
@@ -686,6 +728,28 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                     </div>}
                 </div>
 
+                {taskType === 'GAME' && <div className={style.newSpace}>
+                    <Form.Item
+                        name="gameConsumptionLevel"
+                        label={<strong>游戏消费能力</strong>}
+                        style={{ marginBottom: 0 }}
+                        getValueFromEvent={(e: string[]) => {
+                            if (e.length > 1 && !gameConsumptionLevel.includes('0') && e.includes('0')) {
+                                return ['0'];
+                            }
+                            return e.length > 0 ? (e.length > 1 && e.includes('0') ? e.filter(item => item !== '0') : e) : ['0'];
+                        }}
+                    >
+                        <Checkbox.Group
+                            options={[
+                                { label: '不限', value: '0' },
+                                ...Object.keys(GAME_CONSUMPTION_LEVEL_ENUM)?.map(key => ({ label: GAME_CONSUMPTION_LEVEL_ENUM[key as keyof typeof GAME_CONSUMPTION_LEVEL_ENUM], value: key }))
+                            ]}
+                        />
+                    </Form.Item>
+                </div>}
+
+
                 <div className={style.newSpace}>
                     <Form.Item name="userOsType" label={<strong>操作系统版本</strong>} style={{ marginBottom: 0 }}>
                         <Radio.Group>
@@ -771,13 +835,21 @@ const AddTarget: React.FC<Props> = ({ isBackVal, value, visible, onChange, onClo
                         {wechatAdBehaviorType.includes('actions') && <>
                             <Title level={5} style={{ fontSize: 14 }}>再营销</Title>
                             <Form.Item style={{ marginBottom: 10 }} name={['wechatAdBehavior', 'actions']}>
-                                <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                                {taskType === 'GAME' ?
+                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                                    :
+                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).filter(item => !['WE_COM_CORP_ID_ADDED', 'WECHAT_WORK_CONTACTS_ADDED'].includes(item)).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: excludedActions?.some((k: string) => k === key) }))} />
+                                }
                             </Form.Item>
                         </>}
                         {wechatAdBehaviorType.includes('excludedActions') && <>
                             <Title level={5} style={{ fontSize: 14 }}>排除营销</Title>
                             <Form.Item name={['wechatAdBehavior', 'excludedActions']}>
-                                <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                                {taskType === 'GAME' ?
+                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_GAME_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_GAME_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_GAME_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                                    :
+                                    <Checkbox.Group options={Object.keys(WECHAT_AD_NEHAVIOR_ENUM).map(key => ({ label: WECHAT_AD_NEHAVIOR_ENUM[key as keyof typeof WECHAT_AD_NEHAVIOR_ENUM], value: key, disabled: actions?.some((k: string) => k === key) }))} />
+                                }
                             </Form.Item>
                         </>}
                         {excludedActions?.includes('WE_COM_CORP_ID_ADDED') && <>

+ 3 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Target/dataItem.tsx

@@ -6,13 +6,14 @@ import { CloseOutlined, CopyOutlined, FormOutlined } from "@ant-design/icons"
 
 interface Props {
     targeting: any
+    taksType: 'NOVEL' | 'GAME',
     geoLocationList?: any,
     modelList?: any
     onModify?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void
     onClear?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void
     onCopy?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void
 }
-const DataItem: React.FC<Props> = ({ targeting, onModify, onClear, onCopy, geoLocationList, modelList }) => {
+const DataItem: React.FC<Props> = ({ targeting, taksType, onModify, onClear, onCopy, geoLocationList, modelList }) => {
 
 
     return <Popover
@@ -24,6 +25,7 @@ const DataItem: React.FC<Props> = ({ targeting, onModify, onClear, onCopy, geoLo
             data={targeting}
             geoLocationList={geoLocationList}
             modelList={modelList}
+            taskType={taksType}
         />}
     >
         <div className={style.dataItem}>

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

@@ -18,7 +18,7 @@ const Target: React.FC = () => {
 
     /***************************************/
     const { geoLocationList, modelList } = useModel('useLaunchV3.useTargeting')
-    const { addelivery, setAddelivery, clearData } = useContext(DispatchAddelivery)!;
+    const { addelivery, setAddelivery, clearData, putInType } = useContext(DispatchAddelivery)!;
     const { targeting, adgroups } = addelivery
     const [addVisible, setAddVisible] = useState<boolean>(false)
     const [addTemVisible, setAddTemVisible] = useState<boolean>(false)
@@ -39,11 +39,12 @@ const Target: React.FC = () => {
                 <div className={style.detail_body}>
                     {targeting?.length > 0 && <>
                         <Title level={5} style={{ fontSize: 12 }}>全部相同</Title>
-                        {targeting?.map((item: { targetingName: any; targeting: any, id?: number }, index: number) => <div key={index}>
+                        {targeting?.map((item: { targetingName: any; targeting: any, taskType: 'NOVEL' | 'GAME', id?: number }, index: number) => <div key={index}>
                             <DataItem
                                 geoLocationList={geoLocationList}
                                 modelList={modelList}
                                 key={index}
+                                taksType={item.taskType}
                                 targeting={{ targetingName: item.targetingName, ...item.targeting }}
                                 onClear={() => {
                                     let newTargeting: any[] = JSON.parse(JSON.stringify(targeting))
@@ -86,6 +87,7 @@ const Target: React.FC = () => {
         {addVisible && <SelectTarget
             value={targeting?.filter(item => item?.id)}
             visible={addVisible}
+            putInType={putInType}
             onClose={() => {
                 setAddVisible(false)
             }}
@@ -101,6 +103,7 @@ const Target: React.FC = () => {
         {addTemVisible && <AddTarget
             value={modifyDta}
             isBackVal={true}
+            putInType={putInType}
             visible={addTemVisible}
             onClose={() => {
                 setAddTemVisible(false)

+ 7 - 4
src/pages/launchSystemV3/tencentAdPutIn/create/Target/selectTarget.tsx

@@ -15,6 +15,7 @@ const { Title, Text } = Typography;
 
 interface Props {
     value?: any,
+    putInType?: 'NOVEL' | 'GAME'
     visible?: boolean
     onClose?: () => void
     onChange?: (value: any) => void
@@ -25,7 +26,7 @@ interface Props {
  * @param param0 
  * @returns 
  */
-const SelectTarget: React.FC<Props> = ({ value = [], visible, onChange, onClose }) => {
+const SelectTarget: React.FC<Props> = ({ value = [], putInType, visible, onChange, onClose }) => {
 
     /*****************************/
     const [distributionRule, setDistributionRule] = useState<'1' | '2'>('1')
@@ -66,17 +67,18 @@ const SelectTarget: React.FC<Props> = ({ value = [], visible, onChange, onClose
     }, [])
 
     useEffect(() => {
-        getTargetingList.run(queryParamsNew)
+        getTargetingList.run({...queryParamsNew, taskType: putInType})
     }, [queryParamsNew])
 
     /** 编辑 复制 */
     const editHandle = (data: any, isCopy?: boolean) => {
-        const { targetingName, targeting, description, id, accountId } = data
+        const { targetingName, targeting, description, id, accountId, taskType } = data
         let newModifyDta = {
             ...targeting,
             targetingName,
             description,
-            accountId: accountId || undefined
+            accountId: accountId || undefined,
+            taskType
         }
         if (!isCopy) {
             newModifyDta.id = id
@@ -186,6 +188,7 @@ const SelectTarget: React.FC<Props> = ({ value = [], visible, onChange, onClose
         {addTemVisible && <AddTarget
             value={modifyDta}
             visible={addTemVisible}
+            putInType={putInType}
             onClose={() => {
                 setAddTemVisible(false)
                 setModifyDta(undefined)

+ 3 - 2
src/pages/launchSystemV3/tencentAdPutIn/create/Target/tableConfig.tsx

@@ -23,6 +23,7 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
                             data={records?.targeting}
                             geoLocationList={geoLocationList}
                             modelList={modelList}
+                            taskType={records?.taskType}
                         />}
                     >
                         <QuestionCircleFilled />
@@ -79,8 +80,8 @@ export function TableConfig(geoLocationList: any, modelList: any, editHandle: (d
             width: 120,
             render: (a: any, b: any) => {
                 return <Space wrap>
-                    <Button type="link" style={{ padding: 0 }} onClick={() => { editHandle(b) }} >编辑</Button>
-                    <Button type="link" style={{ padding: 0 }} onClick={() => { editHandle(b, true) }} >复制</Button>
+                    <Button type="link" style={{ padding: 0, fontSize: 12 }} onClick={() => { editHandle(b) }} >编辑</Button>
+                    <Button type="link" style={{ padding: 0, fontSize: 12 }} onClick={() => { editHandle(b, true) }} >复制</Button>
                 </Space>
             }
         },

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

@@ -1033,6 +1033,7 @@ const Create: React.FC = () => {
                 {/* 转化归因 */}
                 {conversionVisible && <ConversionSelect
                     adgroups={addelivery.adgroups}
+                    putInType={putInType}
                     visible={conversionVisible}
                     data={accountCreateLogs}
                     onClose={() => setConversionVisible(false)}

+ 1 - 0
src/pages/launchSystemV3/tencentAdPutIn/typings.d.ts

@@ -63,6 +63,7 @@ declare namespace PULLIN {
         pageSize: number,
         accountId?: number,
         targetingName?: string,
+        taskType?: 'NOVEL' | 'GAME',
         min?: string,
         max?: string,
     }

+ 59 - 1
src/services/adqV3/global.ts

@@ -601,4 +601,62 @@ export async function getAdLabelApi(data: { accountId?: number }) {
         method: 'POST',
         data
     })
-}
+}
+
+/**
+ * 获取游戏列表
+ * @param data 
+ * @returns 
+ */
+export async function getGameLibraryListApi(data: { pageNum: number, pageSize: number, gameName?: string, idList?: number[], gameType?: string }) {
+    return request(api + `/adq/v3/gameLibrary/pageList`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 所有游戏列表
+ * @param data 
+ * @returns 
+ */
+export async function getGameLibraryApi(data: { gameName?: string, idList?: number[], gameType?: string }) {
+    return request(api + `/adq/v3/gameLibrary/listAll`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 新增游戏
+ * @param data 
+ * @returns 
+ */
+export async function addGameApi(data: { appId: string, gameName: string, gameType: string, id?: number }) {
+    return request(api + `/adq/v3/gameLibrary/add`, {
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 删除游戏
+ * @param id 
+ * @returns 
+ */
+export async function delGameApi(id: number) {
+    return request(api + `/adq/v3/gameLibrary/delById/${id}`, {
+        method: 'DELETE'
+    })
+}
+
+/**
+ * 获取游戏详情
+ * @param id 
+ * @returns 
+ */
+export async function getGameLibraryDetailApi(id: number) {
+    return request(api + `/adq/v3/gameLibrary/getById/${id}`, {
+        method: 'GET'
+    })
+}