wjx 7 months ago
parent
commit
25e3efdd0f
29 changed files with 2062 additions and 39 deletions
  1. 7 0
      src/components/InputName/index.less
  2. 53 0
      src/components/InputName/index.tsx
  3. 55 0
      src/components/New1Radio/index.less
  4. 34 0
      src/components/New1Radio/index.tsx
  5. 2 2
      src/components/Settings/index.tsx
  6. 6 2
      src/components/TablePro/index.tsx
  7. 1 3
      src/components/TablePro/typings.d.ts
  8. 27 0
      src/components/timeInSelect/Header.tsx
  9. 215 0
      src/components/timeInSelect/Thead.tsx
  10. 68 0
      src/components/timeInSelect/const.ts
  11. 62 0
      src/components/timeInSelect/header.less
  12. 97 0
      src/components/timeInSelect/index.less
  13. 16 0
      src/components/timeInSelect/index.tsx
  14. 80 0
      src/components/timeInSelect/thead.less
  15. 174 0
      src/pages/iaaData/components/UpdateAd3/global.less
  16. 26 0
      src/pages/iaaData/components/UpdateAd3/index.less
  17. 371 0
      src/pages/iaaData/components/UpdateAd3/index.tsx
  18. 112 1
      src/pages/iaaData/const.tsx
  19. 90 2
      src/pages/iaaData/game/tencent/adList/index.tsx
  20. 197 0
      src/pages/iaaData/novel/tencent/adList/autoAcquisitionSet.tsx
  21. 12 0
      src/pages/iaaData/novel/tencent/adList/const.tsx
  22. 48 0
      src/pages/iaaData/novel/tencent/adList/index.less
  23. 111 7
      src/pages/iaaData/novel/tencent/adList/index.tsx
  24. 44 22
      src/pages/iaaData/novel/tencent/adList/tableConfig.tsx
  25. 8 0
      src/pages/iaaData/novel/tencent/adList/tableConfigDay.tsx
  26. 8 0
      src/pages/iaaData/novel/tencent/dynamic/tableConfig.tsx
  27. 8 0
      src/pages/iaaData/novel/tencent/dynamic/tableConfigDay.tsx
  28. 62 0
      src/services/gameData/index.ts
  29. 68 0
      src/services/gameData/typings.d.ts

+ 7 - 0
src/components/InputName/index.less

@@ -0,0 +1,7 @@
+.matching {
+    font-size: 12px;
+    &>span {
+        color: #999;
+        
+    }
+}

+ 53 - 0
src/components/InputName/index.tsx

@@ -0,0 +1,53 @@
+import { txtLength } from "@/utils/utils"
+import { Button, Input, Space } from "antd"
+import { TextAreaProps } from "antd/lib/input/TextArea"
+import React, { useEffect, useState } from "react"
+import './index.less'
+
+interface Props extends TextAreaProps {
+    length?: number
+    isCurrent?: Array<'素材名称' | '落地页名' | '文案'>
+}
+/**
+ * 广告名称 设置 组件
+ * @returns 
+ */
+const InputName: React.FC<Props> = ({ isCurrent, value, onChange, length, ...props }) => {
+
+    /******************************/
+    const [status, setStatus] = useState<{ status?: string }>({})
+    /******************************/
+
+    useEffect(() => {
+        if (length && txtLength(value as any) > length) {
+            setStatus({ status: 'error' })
+        } else {
+            setStatus({})
+        }
+    }, [value])
+
+    /** 插入通配符 */
+    const insertMatching = (matching: string) => {
+        onChange?.(value + `-${matching}` as any)
+    }
+
+    return <Space direction="vertical" size={0}>
+        <Space align="end">
+            <Input.TextArea value={value} {...props} onChange={(e) => {
+                onChange?.(e)
+            }} />
+            {length && <span style={Object.keys(status).length > 0 ? { color: 'red' } : {}}>{txtLength(value as any)}/{length}</span>}
+        </Space>
+        {isCurrent && isCurrent?.length > 0 && <div className="matching">
+            <span>通配符:</span>
+            <Space>
+                {isCurrent.includes('素材名称') && <Button type="link" onClick={() => insertMatching('<素材名称>')} style={{ padding: 0 }} disabled={value?.toString()?.includes('<素材名称>')}>+素材名称</Button>}
+                {isCurrent.includes('落地页名') && <Button type="link" onClick={() => insertMatching('<落地页名>')} style={{ padding: 0 }} disabled={value?.toString()?.includes('<落地页名>')}>+落地页名</Button>}
+                {isCurrent.includes('文案') && <Button type="link" onClick={() => insertMatching('<文案>')} style={{ padding: 0 }} disabled={value?.toString()?.includes('<文案>')}>+文案(前5个文字)</Button>}
+            </Space>
+        </div>}
+        
+    </Space>
+}
+
+export default React.memo(InputName)

+ 55 - 0
src/components/New1Radio/index.less

@@ -0,0 +1,55 @@
+.new1Radio {
+    border: 1px solid #E2E5EA;
+    border-radius: 999px;
+    padding: 3px;
+    display: inline-flex;
+    gap: 4px;
+
+    >div {
+        height: 28px;
+        padding: 0 16px;
+        box-sizing: border-box;
+        border-radius: 999px;
+        align-items: center;
+        position: relative;
+        line-height: 28px;
+        color: rgba(0, 0, 0, 0.95);
+        font-weight: 500;
+        cursor: pointer;
+        user-select: none;
+
+        >span {
+            display: block;
+            transition-property: opacity, transform, right, left;
+            transition-duration: .2s;
+        }
+
+        >div {
+            position: absolute;
+            left: 6px;
+            content: '';
+            width: 16px;
+            height: 16px;
+            color: #1890ff;
+            opacity: 0;
+        }
+
+        &.newRadioActive {
+            background: #f2f4fa;
+
+            >div {
+                opacity: 1;
+            }
+
+            >span {
+                transform: translateX(9px);
+                font-weight: 600;
+            }
+        }
+
+        &.disabled {
+            color: rgb(196, 199, 204);
+            cursor: not-allowed;
+        }
+    }
+}

+ 34 - 0
src/components/New1Radio/index.tsx

@@ -0,0 +1,34 @@
+import React from "react"
+import style from './index.less'
+import { CheckCircleFilled } from "@ant-design/icons"
+
+type DataType = { label: string | number, value: any, disabled?: boolean }
+interface FormItemDataNewProps {
+    data: DataType[]
+    id?: any,
+    value?: any,
+    onChange?: (value?: any) => void
+}
+
+/**
+ * 新的Radio样式
+ * @param param0 
+ * @returns 
+ */
+const New1Radio: React.FC<FormItemDataNewProps> = ({ data = [], value, onChange, id }) => {
+
+    return <div className={style.new1Radio} id={id}>
+        {data.map((item, index) => <div
+            onClick={() => {
+                if (!item?.disabled) onChange?.(item?.value)
+            }}
+            key={item?.value || index}
+            className={`${value === item.value ? style.newRadioActive : ''} ${item?.disabled ? style.disabled : ''}`}
+        >
+            <div><CheckCircleFilled /></div>
+            <span>{item?.label || item?.value || index}</span>
+        </div>)}
+    </div>
+}
+
+export default React.memo(New1Radio)

+ 2 - 2
src/components/Settings/index.tsx

@@ -7,10 +7,10 @@ import { DispatchHeader } from "../TablePro";
  * 头部
  * 头部
  * @returns 
  * @returns 
  */
  */
-const Settings: React.FC = () => {
+const Settings: React.FC<{ leftChild?: JSX.Element; czChild?: JSX.Element; ajax?: any; }> = ({ leftChild, czChild, ajax }) => {
 
 
     /******************************/
     /******************************/
-    const { isFullscreen, setIsFullscreen, isFull, toggleFull, setVisible, czChild, leftChild, ajax } = useContext(DispatchHeader)!;
+    const { isFullscreen, setIsFullscreen, isFull, toggleFull, setVisible } = useContext(DispatchHeader)!;
     /******************************/
     /******************************/
 
 
     return <Col span={24}>
     return <Col span={24}>

+ 6 - 2
src/components/TablePro/index.tsx

@@ -203,8 +203,12 @@ const TablePro: React.FC<PROAPI.TableProProps> = ({
                         <Space><span>{title}</span>{tips && <Tooltip title={tips}><span><QuestionCircleOutlined /></span></Tooltip>}</Space>
                         <Space><span>{title}</span>{tips && <Tooltip title={tips}><span><QuestionCircleOutlined /></span></Tooltip>}</Space>
                     </div>}
                     </div>}
                     <Row gutter={[0, 16]}>
                     <Row gutter={[0, 16]}>
-                        <DispatchHeader.Provider value={{ setIsFullscreen, isFullscreen, isFull, toggleFull, setVisible, ajax, czChild, leftChild }}>
-                            <Settings />
+                        <DispatchHeader.Provider value={{ setIsFullscreen, isFullscreen, isFull, toggleFull, setVisible }}>
+                            <Settings
+                                leftChild={leftChild}
+                                czChild={czChild}
+                                ajax={ajax}
+                            />
                         </DispatchHeader.Provider>
                         </DispatchHeader.Provider>
                         <DispatchContext.Provider value={{ total, page, pageSize, handelResize }}>
                         <DispatchContext.Provider value={{ total, page, pageSize, handelResize }}>
                             <Col span={24}>
                             <Col span={24}>

+ 1 - 3
src/components/TablePro/typings.d.ts

@@ -39,9 +39,7 @@ declare namespace PROAPI {
         isFull: boolean;
         isFull: boolean;
         toggleFull: () => void;
         toggleFull: () => void;
         setVisible: React.Dispatch<React.SetStateAction<boolean>>;
         setVisible: React.Dispatch<React.SetStateAction<boolean>>;
-        czChild?: JSX.Element;
-        leftChild?: JSX.Element;
-        ajax?: any; //接口刷新
+        
     };
     };
     type TableContentProps = {
     type TableContentProps = {
         total?: number;
         total?: number;

+ 27 - 0
src/components/timeInSelect/Header.tsx

@@ -0,0 +1,27 @@
+import React from 'react';
+import { Typography } from 'antd';
+import { HOUR_LIST } from './const';
+
+import './header.less';
+
+const Header: React.FC = () => {
+    return (
+        <div className="table_header_wrapper">
+            <div className="left">
+                <Typography.Text>星期 \ 时间</Typography.Text>
+            </div>
+            <div className="right">
+                <div className="top">
+                    <div className="before">00:00 - 12:00</div>
+                    <div className="after">12:00 - 24:00</div>
+                </div>
+                <div className="foot">
+                    {HOUR_LIST.map((item, index) => (
+                        <Typography key={index}>{item}</Typography>
+                    ))}
+                </div>
+            </div>
+        </div>
+    );
+}
+export default React.memo(Header)

+ 215 - 0
src/components/timeInSelect/Thead.tsx

@@ -0,0 +1,215 @@
+import React, { useState, useRef } from 'react';
+import classnames from 'classnames';
+import { Space, Tag, Button, Tooltip, Typography } from 'antd';
+import {
+    WEEK_SERIRES,
+    initTimerPicker,
+    formatData,
+    getInitalFormatList,
+    Props,
+} from './const';
+
+import './index.less';
+
+const INIT_START_POINT = { rowNum: -1, colNum: -1, deselect: false };
+const INIT_END_POINT = { rowNum: -1, colNum: -1 };
+function getRealStartEndPoint(startPoint: { colNum: number, rowNum: number }, endPoint: { colNum: number, rowNum: number }) {
+    let startRowNum = startPoint.rowNum,
+        startColNum = startPoint.colNum,
+        endRowNum = endPoint.rowNum,
+        endColNum = endPoint.colNum;
+    if (startPoint.colNum > endPoint.colNum) {
+        startColNum = endPoint.colNum;
+        endColNum = startPoint.colNum;
+    }
+    if (startPoint.rowNum > endPoint.rowNum) {
+        startRowNum = endPoint.rowNum;
+        endRowNum = startPoint.rowNum;
+    }
+    return {
+        startRowNum,
+        startColNum,
+        endRowNum,
+        endColNum,
+    };
+}
+const getActiveStatus = (data: { each: any, startPoint: any, endPoint: any }) => {
+    const { each, startPoint, endPoint } = data;
+    if (startPoint.rowNum === -1 || endPoint.rowNum === -1) {
+        return each.selected;
+    }
+    const { startRowNum, startColNum, endRowNum, endColNum } = getRealStartEndPoint(startPoint, endPoint);
+    if (each.rowNum >= startRowNum && each.colNum >= startColNum && each.rowNum <= endRowNum && each.colNum <= endColNum) {
+        return !startPoint.deselect;
+    }
+    return each.selected;
+};
+
+const Thead: React.FC<Props> = ({ value = [], onChange }) => {
+    const [timerPickered, setTimerPickered] = useState(initTimerPicker(value));
+    const [startPoint, setStartPoint] = useState({ ...INIT_START_POINT });
+    const [endPoint, setEndPoint] = useState({ ...INIT_END_POINT });
+    const endPointRef = useRef(endPoint);
+
+    const updateEndPoint = (point: any) => {
+        endPointRef.current = { ...point };
+        setEndPoint(endPointRef.current);
+    };
+
+    const handleClear = () => {
+        const initData = getInitalFormatList();
+        setTimerPickered(initTimerPicker(initData));
+        setStartPoint({ ...INIT_START_POINT });
+        setEndPoint({ ...INIT_END_POINT });
+        onChange?.(initData);
+    };
+
+    const updateDataList = ({ startPoint, endPoint }: any) => {
+        const dataList = getInitalFormatList();
+        timerPickered.forEach((rows) => {
+            rows.forEach((each: any) => {
+                each.selected = getActiveStatus({
+                    each,
+                    startPoint,
+                    endPoint,
+                });
+                formatData(dataList, each);
+            });
+        });
+        setTimerPickered([...timerPickered]);
+        setStartPoint({ ...INIT_START_POINT });
+        updateEndPoint({ ...INIT_END_POINT });
+        return dataList;
+    };
+
+    const triggerChange = (changedValue: any) => {
+        const data = updateDataList({ startPoint, endPoint });
+        // onChange?.([...data, ...(value ?? []), ...changedValue]);
+        onChange?.(data);
+    };
+
+    const onMouseDown = ({ target: { dataset } }: any) => {
+        const { type, rowNum, colNum, selected } = dataset;
+        if ('time-boxzone' !== type) return;
+        setStartPoint({
+            rowNum: +rowNum,
+            colNum: +colNum,
+            deselect: selected === '1',
+        });
+        updateEndPoint({ rowNum: +rowNum, colNum: +colNum });
+    };
+
+    const onMouseUp = ({ target: { dataset } }: any) => {
+        const { type, rowNum, colNum } = dataset;
+        if (type !== 'time-boxzone') return;
+        if (+rowNum !== endPointRef.current.rowNum || +colNum !== endPointRef.current.colNum) {
+            updateEndPoint({ rowNum: +rowNum, colNum: +colNum });
+        }
+        requestAnimationFrame(() => {
+            const list = updateDataList({
+                startPoint,
+                endPoint: endPointRef.current,
+            });
+            triggerChange(list);
+        });
+    };
+
+    const onMouseOver = ({ target: { dataset } }: any) => {
+        const { type, rowNum, colNum } = dataset;
+        if ('time-boxzone' !== type) return;
+        if (startPoint.colNum === -1) return;
+        endPointRef.current = { rowNum: +rowNum, colNum: +colNum };
+        requestAnimationFrame(() => {
+            updateEndPoint(endPointRef.current);
+        });
+    };
+
+    const onMouseLeave = () => {
+        if (startPoint.rowNum === -1) return;
+        setTimeout(() => {
+            if (endPointRef.current.colNum === -1) {
+                updateEndPoint({
+                    colNum: startPoint.colNum,
+                    rowNum: startPoint.rowNum,
+                });
+            }
+            requestAnimationFrame(() => {
+                const list = updateDataList({
+                    startPoint,
+                    endPoint: endPointRef.current,
+                });
+                triggerChange(list);
+            });
+        });
+    };
+    const Footer = (
+        <div className="footer_wrapper">
+            <Space>
+                <Tag color="#1890ff">已选</Tag>
+                <Tag>未选</Tag>
+                <Typography.Text type="secondary">可拖动鼠标选择时间段</Typography.Text>
+            </Space>
+            <Button type="link" onClick={handleClear} style={{ paddingLeft: 0, paddingRight: 0 }}>
+                清空
+            </Button>
+        </div>
+    );
+
+    return (
+        <div className="thead_wrapper">
+            <div className="thead_wrapper_content">
+                <div className="week_series">
+                    {WEEK_SERIRES.map((item, index) => (
+                        <div className="week_series__item" key={index}>
+                            {item?.name}
+                        </div>
+                    ))}
+                </div>
+                <div
+                    className="time_series"
+                    data-type="right-boxzones"
+                    onMouseDown={onMouseDown}
+                    onMouseUp={onMouseUp}
+                    onMouseOver={onMouseOver}
+                    onMouseLeave={onMouseLeave}
+                >
+                    {timerPickered.map((row, index) => (
+                        <div className="time_series__row" key={index}>
+                            {row.map((each: any, i: number) => (
+                                <Tooltip
+                                    destroyTooltipOnHide
+                                    mouseEnterDelay={1}
+                                    key={`${index}_${i}`}
+                                    title={each?.name}
+                                    placement="bottom"
+                                >
+                                    <div
+                                        key={each?.key}
+                                        draggable={false}
+                                        data-row-num={each?.rowNum}
+                                        data-col-num={each?.colNum}
+                                        data-selected={each?.selected ? '1' : '0'}
+                                        data-type="time-boxzone"
+                                        className={classnames(
+                                            {
+                                                isActive: getActiveStatus({
+                                                    each,
+                                                    startPoint,
+                                                    endPoint: endPointRef.current,
+                                                }),
+                                            },
+                                            'row_item',
+                                        )}
+                                    />
+                                </Tooltip>
+                            ))}
+                        </div>
+                    ))}
+                </div>
+            </div>
+            {Footer}
+        </div>
+    );
+}
+
+export default React.memo(Thead)

+ 68 - 0
src/components/timeInSelect/const.ts

@@ -0,0 +1,68 @@
+import moment from 'moment';
+
+/**
+ * @param value string[]
+ * @param onChange (data: string[]) => void
+ */
+export interface Props {
+    id?: any,
+    value?: string[],
+    onChange?: (data: string[]) => void
+}
+
+const [_, ...rest] = moment.weekdays();
+export const WEEK_SERIRES = [...rest, _].map((item, index) => ({
+    name: item,
+    key: index,
+    value: index + 1,
+}));
+
+export const HOUR_LIST = Array.from({ length: 24 }, (v, i) => i);
+
+// export const TIME_PICKER = Array(24)
+//   .fill(0)
+//   .map((k, v) => `${v}:30`);
+
+const totalHour = 48;
+
+export const initTimerPicker = function (value: any[] = []) {
+    const result: any[] = [];
+    let index = 0;
+    WEEK_SERIRES.forEach((week, rowNum) => {
+        const weekList = [];
+        let hourSpan = 0;
+        while (hourSpan < totalHour) {
+            const hour = Math.floor(hourSpan / 2);
+            const curHour = ('00' + hour).slice(-2);
+            const nextHour = ('00' + (hour + 1)).slice(-2);
+            const timer = index % 2 === 0 ? `${curHour}:00-${curHour}:30` : `${curHour}:30-${nextHour}:00`;
+            const selected = value[index] === '1';
+            const timerBox = {
+                key: `${week.value}_${timer}`,
+                name: `${week.name} ${timer}`,
+                value: index,
+                rowNum: rowNum + 1,
+                colNum: (index % totalHour) + 1,
+                selected,
+            };
+            weekList.push(timerBox);
+            if (!selected) {
+                value[index] = '0';
+            }
+            index++;
+            hourSpan++;
+        }
+        result.push(weekList);
+    });
+    value.length = 7 * 24 * 2;
+    return result;
+};
+
+export function formatData(data: any, timeBox: any) {
+    data[timeBox.value] = timeBox.selected ? '1' : '0';
+    return data;
+}
+
+export function getInitalFormatList() {
+    return new Array(7 * 24 * 2).fill('0');
+}

+ 62 - 0
src/components/timeInSelect/header.less

@@ -0,0 +1,62 @@
+.flexBase {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: #f9f9f9;
+}
+
+.table_header_wrapper {
+    width: 100%;
+    height: 60px;
+    display: flex;
+    border-top: 1px solid rgba(217, 218, 219, .8);
+
+    .left:extend(.flexBase) {
+        width: 73px;
+        height: 100%;
+        background: white;
+        box-shadow: 0px 0px 0px 1px rgba(217, 218, 219, .8);
+    }
+
+    .right {
+        width: calc(100% - 73px);
+        height: 100%;
+
+        .top {
+            display: flex;
+            width: 100%;
+            height: 40px;
+
+            .before:extend(.flexBase) {
+                width: 50%;
+                height: 100%;
+                border-right: 1px solid rgba(217, 218, 219, .8);
+                border-left: 1px solid rgba(217, 218, 219, .8);
+            }
+
+            .after :extend(.flexBase) {
+                width: 50%;
+                height: 100%;
+                border-right: 1px solid rgba(217, 218, 219, .8);
+            }
+        }
+
+        .foot {
+            width: 100%;
+            height: calc(100% - 40px);
+            display: grid;
+            grid-template-columns: repeat(24, 1fr);
+
+            .ant-typography {
+                &:extend(.flexBase);
+                &:first-child {
+                    border-left: 1px solid rgba(217, 218, 219, .8);
+                }
+                height: 19px;
+                border-bottom: 1px solid rgba(217, 218, 219, .8);
+                border-top: 1px solid rgba(217, 218, 219, .8);
+                border-right: 1px solid rgba(217, 218, 219, .8);
+            }
+        }
+    }
+}

+ 97 - 0
src/components/timeInSelect/index.less

@@ -0,0 +1,97 @@
+.flexBase {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: #f9f9f9;
+    box-shadow: 0px 0px 0px 1px rgba(217, 218, 219, .8);
+}
+
+.selectNone {
+    user-select: none;
+    -webkit-user-select: none;
+    /* Chrome, Safari and Opera */
+    -moz-user-select: none;
+    /* Firefox */
+    -ms-user-select: none;
+    /* IE 10+ */
+}
+
+.thead_wrapper {
+    .thead_wrapper_content {
+        display: flex;
+
+        .week_series {
+            width: 73px;
+            height: 100%;
+
+            &__item:extend(.flexBase) {
+                width: 100%;
+                height: 40px;
+                background: white !important;
+            }
+        }
+
+        .time_series:extend(.selectNone) {
+            width: calc(100% - 73px);
+            border-right: 1px solid rgba(217, 218, 219, .8);
+            border-bottom: 1px solid rgba(217, 218, 219, .8);
+
+            &__row:extend(.selectNone) {
+                display: flex;
+                height: 39px;
+                width: 100%;
+                margin-top: 1px;
+
+                .row_item:extend(.selectNone) {
+                    width: 100%;
+                    height: 100%;
+                    margin-right: 1px;
+                    background: lightblue;
+                    box-sizing: border-box;
+                    // cursor: pointer;
+
+                    &__content:extend(.selectNone) {
+                        display: none;
+                    }
+
+                    &:first-child {
+                        margin-left: 1px;
+                    }
+
+                    &:nth-child(odd) {
+                        background: rgb(249, 249, 249);
+                    }
+
+                    &:nth-child(even) {
+                        background: rgb(240, 240, 240);
+                    }
+
+                    &:hover {
+                        background: rgba(@primary-color, 0.4);
+                        transition: all 0.5s;
+
+                        .row_item__content {
+                            display: block;
+                            transition: all 0.4s;
+                            color: white;
+                        }
+                    }
+
+                    &:last-child {
+                        margin-right: 0;
+                    }
+                }
+
+                .isActive {
+                    background: @primary-color !important;
+                    transition: all 0.5s;
+                }
+            }
+        }
+    }
+
+    .footer_wrapper {
+        display: flex;
+        justify-content: space-between;
+    }
+}

+ 16 - 0
src/components/timeInSelect/index.tsx

@@ -0,0 +1,16 @@
+import React from "react"
+import { Props } from "./const";
+import Header from './Header';
+import Thead from './Thead';
+
+
+const TimeInSelect: React.FC<Props> = ({ id, ...props }) => {
+
+    return <div id={id}>
+        <Header />
+        <Thead {...props} />
+    </div>
+}
+
+
+export default React.memo(TimeInSelect)

+ 80 - 0
src/components/timeInSelect/thead.less

@@ -0,0 +1,80 @@
+.flexBase {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    background: #f9f9f9;
+    box-shadow: 0px 0px 0px 1px #efefef;
+}
+
+.thead_wrapper {
+    .thead_wrapper_content {
+        display: flex;
+
+        .week_series {
+            width: 73px;
+            height: 100%;
+
+            &__item:extend(.flexBase) {
+                width: 100%;
+                height: 40px;
+                background: white !important;
+            }
+        }
+
+        .time_series {
+            width: calc(100% - 73px);
+
+            &__row {
+                display: flex;
+                height: 39px;
+                width: 100%;
+                margin-top: 1px;
+
+                .row_item {
+                    width: 100%;
+                    height: 100%;
+                    margin-right: 1px;
+                    background: lightblue;
+                    cursor: pointer;
+
+                    &__content {
+                        display: none;
+                    }
+
+                    &:first-child {
+                        margin-left: 1px;
+                    }
+
+                    &:nth-child(odd) {
+                        background: rgb(249, 249, 249);
+                    }
+
+                    &:nth-child(even) {
+                        background: rgb(240, 240, 240);
+                    }
+
+                    &:hover {
+                        background: rgba(@primary-color, 0.4);
+                        transition: all 0.5s;
+
+                        .row_item__content {
+                            display: block;
+                            transition: all 0.4s;
+                            color: white;
+                        }
+                    }
+                }
+
+                .isActive {
+                    background: @primary-color !important;
+                    transition: all 0.5s;
+                }
+            }
+        }
+    }
+
+    .footer_wrapper {
+        display: flex;
+        justify-content: space-between;
+    }
+}

+ 174 - 0
src/pages/iaaData/components/UpdateAd3/global.less

@@ -0,0 +1,174 @@
+.modalResetCss {
+    // font-family: PingFang SC,Microsoft YaHei UI,Microsoft YaHei,Helvetica Neue,Helvetica,Hiragino Sans GB,Arial,sans-serif;
+    --boder: 8px;
+
+    .ant-modal-content {
+        border-radius: var(--boder) !important;
+    }
+
+    .ant-modal-header {
+        border-radius: var(--boder) var(--boder) 0 0;
+        padding: 8px 16px;
+    }
+
+    .ant-modal-body {
+        padding: 16px;
+    }
+
+    .ant-modal-footer {
+        border-radius: 0 0 var(--boder) var(--boder);
+        padding: 4px 8px;
+
+    }
+
+    .ant-modal-close-x {
+        width: 39px;
+        height: 39px;
+        line-height: 39px;
+    }
+
+    .ant-btn {
+        height: 28px;
+        line-height: normal;
+        border-radius: 6px !important;
+        padding: 3px 11px;
+    }
+
+    .ant-transfer .ant-btn {
+        padding: 0px 0;
+        height: 24px;
+    }
+
+    .ant-space .ant-form-item {
+        margin-bottom: 16px;
+    }
+
+    .ant-transfer-list,
+    .ant-picker,
+    .ant-input,
+    .ant-select-selector,
+    .ant-input-affix-wrapper {
+        border-radius: var(--boder) !important;
+    }
+
+    .ant-transfer-list-header {
+        border-radius: var(--boder) var(--boder) 0 0 !important;
+    }
+
+    .ant-input-group {
+        .ant-input-affix-wrapper:not(:last-child) {
+            border-top-right-radius: 0 !important;
+            border-bottom-right-radius: 0 !important;
+            .ant-input {
+                border-top-right-radius: 0 !important;
+                border-bottom-right-radius: 0 !important;
+            }
+        }
+        .ant-btn {
+            border-radius: 0 6px 6px 0 !important;
+            height: 32px;
+            padding: 4px 15px;
+        }
+    }
+
+    .ant-table-tbody td {
+        font-size: 12px;
+        font-family: PingFang SC, Microsoft YaHei UI, Microsoft YaHei, Helvetica Neue, Helvetica, Hiragino Sans GB, Arial, sans-serif;
+    }
+}
+
+.selectModal {
+    .ant-modal-footer {
+        padding: 0 8px;
+    }
+}
+
+.cardResetCss {
+    --boder: 8px;
+    border-radius: var(--boder);
+
+    .ant-card-head {
+        padding: 0 16px;
+        min-height: auto;
+        border-radius: var(--boder) var(--boder) 0 0;
+    }
+
+    .ant-card-extra,
+    .ant-card-head-title {
+        padding: 8px 0;
+    }
+
+    .ant-card-body {
+        padding: 16px;
+    }
+
+}
+
+.newCss {
+    .ant-form-item-label {
+        padding: 0 !important;
+    }
+}
+
+// .ant-radio-button-wrapper {
+//     height: 28px;
+//     line-height: 28px;
+//     padding: 0 6px;
+// }
+
+.ant-radio-button-wrapper:first-child {
+    border-radius: 6px 0 0 6px !important;
+}
+
+.ant-radio-button-wrapper:last-child {
+    border-radius: 0 6px 6px 0 !important;
+}
+
+.submit_pull {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 4px 8px !important;
+    background-color: #FFF;
+    border-radius: 0 0 8px 8px;
+    margin-bottom: 0 !important;
+    text-align: right;
+}
+
+.targetingSelect .ant-drawer-body {
+    height: 100%;
+    overflow: hidden;
+    padding: 8px;
+    background-color: rgb(241, 244, 252);
+}
+
+
+.flexSpaceBetween {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.flexStart {
+    display: flex;
+    align-items: center;
+    gap: var(--g, 0);
+}
+
+.flexColumnStart {
+    display: flex;
+    flex-direction: column;
+    gap: var(--g, 0);
+}
+
+
+.buttonResetCss {
+    .ant-btn {
+        font-size: 12px;
+        height: 28px;
+        padding: 3px 11px;
+        border-radius: 6px;
+    }
+    
+}

+ 26 - 0
src/pages/iaaData/components/UpdateAd3/index.less

@@ -0,0 +1,26 @@
+
+
+.newSpace {
+    padding: 10px 12px;
+
+    .newSpace_top {
+        display: flex;
+        align-items: center;
+    }
+
+    .newSpace_bottom {
+        background-color: #fafafb;
+        padding: 18px 16px 10px;
+        margin-left: 124px;
+    }
+
+    &:not(:last-child) {
+        border-bottom: 1px solid #f0f0f0;
+    }
+
+    .newSpace_title {
+        width: 140px;
+        font-weight: bold;
+        padding-right: 15px;
+    }
+}

+ 371 - 0
src/pages/iaaData/components/UpdateAd3/index.tsx

@@ -0,0 +1,371 @@
+import { useAjax } from "@/Hook/useAjax"
+import { Button, Card, DatePicker, Form, Input, InputNumber, Modal, Radio, Select, Space, Table, message } from "antd"
+import React, { useEffect, useState } from "react"
+import './global.less'
+import { RangePickerProps } from "antd/lib/date-picker"
+import moment from "moment"
+import style from './index.less'
+import { txtLength } from "@/utils/utils"
+import TimeInSelect from "@/components/timeInSelect"
+import { getTimeSeriesList, SelectTimeList } from "../../const"
+import InputName from "@/components/InputName"
+import New1Radio from "@/components/New1Radio"
+import { delBatchApi, modifyAdTimeBatchApi, modifyAmountBatchApi, modifyDailyBudgetBatchApi, updateBatchAdgroupInfoApi } from "@/services/gameData"
+
+interface Props {
+    type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI' | '修改投放首日开始时间'
+    updateData: any[],
+    visible?: boolean,
+    onClose?: () => void
+    onChange?: () => void
+}
+
+const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateData }) => {
+
+    /****************************************/
+    const [form] = Form.useForm();
+    const timeSeriesType = Form.useWatch('timeSeriesType', form)
+    const updateType = Form.useWatch('updateType', form)
+
+    const [failIdList, setFailIdList] = useState<{ adgroupId: number, code: number, message: string, messageCn: string }[]>([])
+    const [failVisible, setFailVisible] = useState<boolean>(false)
+
+    const modifyAmountBatch = useAjax((params) => modifyAmountBatchApi(params)) // 出价
+    const modifyAdTimeBatch = useAjax((params) => modifyAdTimeBatchApi(params)) // 时间
+    const updateBatchAdgroupInfo = useAjax((params) => updateBatchAdgroupInfoApi(params)) // 名称
+    const modifyDailyBudgetBatch = useAjax((params) => modifyDailyBudgetBatchApi(params)) // 日限额
+    const delBatch = useAjax((params) => delBatchApi(params)) // 删除
+    /****************************************/
+
+    useEffect(() => {
+        if (type === '删除') {
+            form.setFieldsValue({ delAd: updateData.map(item => item.adgroupName) })
+        } else if (type === '深度优化ROI') {
+            form.setFieldsValue({ deepConversionSpec: updateData?.[0]?.deepConversionSpec })
+        }
+    }, [type, updateData])
+
+    const handleOk = (values: any) => {
+        console.log(values)
+        let accountAdgroupMaps = [...new Set(updateData?.map(item => item.accountId + ',' + item.adgroupId))]
+        switch (type) {
+            case '修改出价':
+                let paramsCj: any = {}
+                if (values?.updateType === 'percent') {
+                    paramsCj.bidAmountPercent = values?.bidAmountPercent / 100
+                } else {
+                    paramsCj.bidAmount = values?.bidAmount
+                }
+                modifyAmountBatch.run({ accountAdgroupMaps, ...paramsCj }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+            case '修改名称':
+            case '深度优化ROI':
+            case '修改投放首日开始时间':
+                let params2: any = {}
+                if (type === '深度优化ROI') {
+                    params2 = JSON.parse(JSON.stringify(values))
+                    if (params2.updateType === 'percent') {
+                        delete params2?.deepConversionSpec?.deepConversionWorthSpec?.expectedRoi
+                        params2.deepConversionSpec.deepConversionWorthSpec.expectedRoiPercent = params2?.deepConversionSpec?.deepConversionWorthSpec?.expectedRoiPercent / 100
+                    } else {
+                        delete params2?.deepConversionSpec?.deepConversionWorthSpec?.expectedRoiPercent
+                    }
+                    delete params2.updateType
+                } else {
+                    params2 = values
+                }
+                updateBatchAdgroupInfo.run({ accountAdgroupMaps, ...params2 }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+            case '修改投放时间':
+                let params = { accountAdgroupMaps, ...values }
+                params.beginDate = moment(params.date[0]).format('YYYY-MM-DD')
+                params.endDate = moment(params.date[1]).format('YYYY-MM-DD')
+                if (params.timeSeriesType === '0') {
+                    // params.timeSeries = Array(336).fill(1).join('');
+                } else {
+                    params.timeSeries = params.timeSeries.join('');
+                }
+                delete params.timeSeriesType
+                delete params.date
+                modifyAdTimeBatch.run(params).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+            case '修改日限额':
+                modifyDailyBudgetBatch.run({ accountAdgroupMaps, ...values }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+            case '删除':
+                delBatch.run({ accountAdgroupMaps }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`删除广告操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+        }
+
+    }
+
+    /** 禁止选择以前时间 */
+    const disabledDate: RangePickerProps['disabledDate'] = current => {
+        // Can not select days before today and today
+        return current && current < moment().startOf('day');
+    };
+
+    return <>
+        <Modal
+            title={<strong>{type}</strong>}
+            open={visible}
+            footer={null}
+            onCancel={onClose}
+            bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
+            className='modalResetCss'
+            width={type === '修改投放时间' ? 900 : type === '深度优化ROI' ? 800 : 600}
+        >
+            <Form
+                form={form}
+                name="updateAd3.0"
+                labelAlign='left'
+                labelCol={{ span: ['修改投放首日开始时间', '修改出价'].includes(type) ? 6 : 4 }}
+                colon={false}
+                style={{ backgroundColor: '#f1f4fc', maxHeight: 600, overflow: 'hidden', overflowY: 'auto', padding: '10px 10px 10px', borderRadius: '0 0 8px 8px' }}
+                scrollToFirstError
+                onFinishFailed={({ errorFields }) => {
+                    message.error(errorFields?.[0]?.errors?.[0])
+                }}
+                onFinish={handleOk}
+                initialValues={{ timeSeriesType: '0', timeSeries: getTimeSeriesList(), updateType: 'fixed' }}
+            >
+                <Card
+                    title={<strong style={{ fontSize: 14 }}>{type === '删除' ? '确认删除?' : '修改设置'}</strong>}
+                    className="cardResetCss"
+                >
+                    {type === '修改出价' ? <>
+                        <Form.Item
+                            label={<strong>出价修改方式</strong>}
+                            name='updateType'
+                            rules={[
+                                { required: true, message: '请选择出价修改方式' }
+                            ]}
+                        >
+                            <Radio.Group buttonStyle="solid">
+                                <Radio.Button value="fixed">固定值</Radio.Button>
+                                <Radio.Button value="percent">百分比上下浮动修改</Radio.Button>
+                            </Radio.Group>
+                        </Form.Item>
+                        {updateType === 'fixed' ? <Form.Item
+                            label={<strong>出价</strong>}
+                            name='bidAmount'
+                            rules={[
+                                { required: true, message: '请输入' }
+                            ]}
+                        >
+                            <InputNumber min={0} style={{ width: '100%' }} placeholder="请输入价格 元" />
+                        </Form.Item> : <Form.Item
+                            label={<strong>浮动比</strong>}
+                            name='bidAmountPercent'
+                            rules={[
+                                { required: true, message: '请输入' }
+                            ]}
+                        >
+                            <InputNumber placeholder="出价,原有基础上下调百分比" style={{ width: '100%' }} addonAfter="%" />
+                        </Form.Item>}
+
+                    </> : type === '修改名称' ? <Form.Item
+                        label={<strong>广告名称</strong>}
+                        name='adgroupName'
+                        // tooltip="下标、日期时分秒、广告账户创建时默认自带"
+                        rules={[
+                            { required: true, message: '请输入广告名称!' },
+                            {
+                                required: true, message: '广告名称不能包含特殊字符:< > & ‘ ” / 以及TAB、换行、回车键,请修改', validator(_, value) {
+                                    let reg = /[&‘’“”/\n\t\f]/ig
+                                    if (value && reg.test(value)) {
+                                        return Promise.reject()
+                                    }
+                                    return Promise.resolve()
+                                }
+                            },
+                            {
+                                required: true, message: '请确保广告名称长度不超过60个字(1个汉字等于2个字符)', validator(_, value) {
+                                    if (value && txtLength(value) > 50) {
+                                        return Promise.reject()
+                                    }
+                                    return Promise.resolve()
+                                }
+                            }
+                        ]}
+                    >
+                        <InputName placeholder='广告名称' style={{ width: 420 }} length={50} />
+                    </Form.Item> : type === '修改日限额' ? <Form.Item
+                        label={<strong>日限额</strong>}
+                        name='bidAmount'
+                        rules={[
+                            { required: true, message: '请输入' }
+                        ]}
+                    >
+                        <InputNumber min={0} style={{ width: '100%' }} placeholder="请输入日限额 元" />
+                    </Form.Item> : type === '修改投放时间' ? <>
+                        <Form.Item label={<strong>投放日期</strong>} name='date' rules={[{ required: true, message: '请选择投放日期' }]}>
+                        {/* @ts-ignore */}
+                            <DatePicker.RangePicker disabledDate={disabledDate} />
+                        </Form.Item>
+                        <Form.Item label={<strong>投放时间</strong>}>
+                            <Card bordered className="cardResetCss newCss" bodyStyle={{ padding: 0 }}>
+                                <div className={style.newSpace}>
+                                    <div className={style.newSpace_top}>
+                                        <div className={style.newSpace_title} style={{ width: 78 }}>选择时段</div>
+                                        <Form.Item name='timeSeriesType' style={{ marginBottom: 0 }}>
+                                            <Radio.Group>
+                                                <Radio value="0">全天</Radio>
+                                                <Radio value="2">指定多个时段</Radio>
+                                            </Radio.Group>
+                                        </Form.Item>
+                                    </div>
+                                    {timeSeriesType === '2' && <div className={style.newSpace_bottom} style={{ marginLeft: 65 }}>
+                                        <Form.Item name='timeSeries' noStyle rules={[{ required: true, message: '请选择时段' }]}>
+                                            <TimeInSelect />
+                                        </Form.Item>
+                                    </div>}
+                                </div>
+                            </Card>
+                        </Form.Item>
+                    </> : type === '删除' ? <Form.Item label={<strong>广告名称</strong>} name='delAd' rules={[{ required: true, message: '请选择广告' }]}>
+                        <Input.TextArea disabled />
+                    </Form.Item> : type === '深度优化ROI' ? <>
+                        <Form.Item label={<strong>深度优化类型</strong>} name={['deepConversionSpec', 'deepConversionType']} rules={[{ required: true, message: '请选择深度优化类型' }]}>
+                            <New1Radio data={[{ label: '优化ROI', value: 'DEEP_CONVERSION_WORTH', disabled: true }]} />
+                        </Form.Item>
+                        <Form.Item label={<strong>深度优化目标</strong>} name={['deepConversionSpec', 'deepConversionWorthSpec', 'goal']} rules={[{ required: true, message: '请选择深度优化目标' }]}>
+                            <Select style={{ width: 480 }} placeholder='请选择'>
+                                <Select.Option value={'GOAL_1DAY_PURCHASE_ROAS'}>首日付费ROI</Select.Option>
+                            </Select>
+                        </Form.Item>
+                        <Form.Item
+                            label={<strong>期望ROI修改方式</strong>}
+                            name='updateType'
+                            rules={[
+                                { required: true, message: '请选择期望ROI修改方式' }
+                            ]}
+                        >
+                            <Radio.Group buttonStyle="solid">
+                                <Radio.Button value="fixed">固定值</Radio.Button>
+                                <Radio.Button value="percent">百分比上下浮动修改</Radio.Button>
+                            </Radio.Group>
+                        </Form.Item>
+                        {updateType === 'fixed' ? <Form.Item
+                            label={<strong>期望ROI</strong>}
+                            name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']}
+                            rules={[
+                                { required: true, message: '请输入期望ROI' },
+                                { type: 'number', min: 0.001, max: 1000, message: '范围0.001~1000' },
+                                {
+                                    validator: (_: any, value: string) => {
+                                        if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                            return Promise.resolve();
+                                        }
+                                        return Promise.reject(new Error('请输入最多三位小数'));
+                                    }
+                                }
+                            ]}
+                        >
+                            <InputNumber style={{ width: 480 }} placeholder={`期望ROI目标范围0.001~1000,输入0.05,表示ROI目标为5%`} />
+                        </Form.Item> : <Form.Item
+                            label={<strong>期望ROI浮动比</strong>}
+                            name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoiPercent']}
+                            rules={[{ required: true, message: '请输入期望ROI浮动比' }]}
+                        >
+                            <InputNumber style={{ width: 480 }} placeholder="期望ROI,原有基础上下调百分比" addonAfter="%" />
+                        </Form.Item>}
+
+                    </> : type === '修改投放首日开始时间' ? <Form.Item name='firstDayBeginTime' label={<strong>首日开始时间</strong>} rules={[{ required: true, message: '请选择首日开始时间' }]}>
+                        <Select
+                            style={{ width: 180 }}
+                            allowClear
+                            placeholder='请选择首日开始时间'
+                            options={SelectTimeList}
+                        />
+                    </Form.Item> : null}
+                </Card>
+                <Form.Item className="submit_pull">
+                    <Space>
+                        <Button onClick={onClose}>取消</Button>
+                        <Button type="primary" htmlType="submit" className="modalResetCss" loading={modifyAmountBatch.loading || modifyAdTimeBatch.loading || updateBatchAdgroupInfo.loading || modifyDailyBudgetBatch.loading || delBatch.loading}>
+                            确定
+                        </Button>
+                    </Space>
+                </Form.Item>
+            </Form>
+        </Modal>
+
+        {failVisible && <Modal
+            title={<strong>报错信息</strong>}
+            open={failVisible}
+            className='modalResetCss'
+            width={650}
+            onCancel={() => { setFailVisible(false); setFailIdList([]) }}
+            footer={null}
+        >
+            <Table
+                size="small"
+                bordered
+                rowKey={'adgroupId'}
+                columns={[{
+                    title: '广告ID',
+                    dataIndex: 'adgroupId',
+                    key: 'adgroupId',
+                    width: 110,
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: 'code',
+                    dataIndex: 'code',
+                    key: 'code',
+                    width: 70,
+                    align: 'center',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: '错误信息',
+                    dataIndex: 'messageCn',
+                    key: 'messageCn',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }]}
+                dataSource={failIdList}
+            />
+        </Modal>}
+    </>
+}
+
+export default React.memo(UpdateAd3)

+ 112 - 1
src/pages/iaaData/const.tsx

@@ -1,5 +1,6 @@
 import { Badge } from "antd";
 import { Badge } from "antd";
 import React from "react"
 import React from "react"
+import moment from "moment";
 
 
 /** 出价方式 */
 /** 出价方式 */
 export enum BID_MODE_ENUM {
 export enum BID_MODE_ENUM {
@@ -279,4 +280,114 @@ export enum AdUnitType_Enum {
 export enum DYNAMIC_CREATIVE_TYPE {
 export enum DYNAMIC_CREATIVE_TYPE {
     DYNAMIC_CREATIVE_TYPE_COMMON = '手动指定',
     DYNAMIC_CREATIVE_TYPE_COMMON = '手动指定',
     DYNAMIC_CREATIVE_TYPE_PROGRAM = '自动匹配'
     DYNAMIC_CREATIVE_TYPE_PROGRAM = '自动匹配'
-}
+}
+
+
+export function getTimeSeriesList() {
+    return new Array(7 * 24 * 2).fill('1');
+}
+
+const [_, ...rest] = moment.weekdays();
+export const WEEK_SERIRES = [...rest, _];
+
+
+
+/** 默认时间选择列表 */
+export const SelectTimeList = [
+	{
+		label: '00:00',
+		value: '00:00:00'
+	},
+	{
+		label: '01:00',
+		value: '01:00:00'
+	},
+	{
+		label: '02:00',
+		value: '02:00:00'
+	},
+	{
+		label: '03:00',
+		value: '03:00:00'
+	},
+	{
+		label: '04:00',
+		value: '04:00:00'
+	},
+	{
+		label: '05:00',
+		value: '05:00:00'
+	},
+	{
+		label: '06:00',
+		value: '06:00:00'
+	},
+	{
+		label: '07:00',
+		value: '07:00:00'
+	},
+	{
+		label: '08:00',
+		value: '08:00:00'
+	},
+	{
+		label: '09:00',
+		value: '09:00:00'
+	},
+	{
+		label: '10:00',
+		value: '10:00:00'
+	},
+	{
+		label: '11:00',
+		value: '11:00:00'
+	},
+	{
+		label: '12:00',
+		value: '12:00:00'
+	},
+	{
+		label: '13:00',
+		value: '13:00:00'
+	},
+	{
+		label: '14:00',
+		value: '14:00:00'
+	},
+	{
+		label: '15:00',
+		value: '15:00:00'
+	},
+	{
+		label: '16:00',
+		value: '16:00:00'
+	},
+	{
+		label: '17:00',
+		value: '17:00:00'
+	},
+	{
+		label: '18:00',
+		value: '18:00:00'
+	},
+	{
+		label: '19:00',
+		value: '19:00:00'
+	},
+	{
+		label: '20:00',
+		value: '20:00:00'
+	},
+	{
+		label: '21:00',
+		value: '21:00:00'
+	},
+	{
+		label: '22:00',
+		value: '22:00:00'
+	},
+	{
+		label: '23:00',
+		value: '23:00:00'
+	},
+]

+ 90 - 2
src/pages/iaaData/game/tencent/adList/index.tsx

@@ -6,10 +6,12 @@ import columns12 from "./tableConfig"
 import QueryForm from "@/components/QueryForm"
 import QueryForm from "@/components/QueryForm"
 import moment from "moment"
 import moment from "moment"
 import { useModel } from "umi"
 import { useModel } from "umi"
-import { Button, message, notification, Space } from "antd"
+import { Button, Dropdown, message, notification, Space } from "antd"
 import { newEditAdqAdgroupsDataApi } from "@/services/gameData"
 import { newEditAdqAdgroupsDataApi } from "@/services/gameData"
-import { PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"
+import { DeleteOutlined, DownOutlined, PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"
 import DayAd from "./dayAd"
 import DayAd from "./dayAd"
+import AutoAcquisitionSet from "@/pages/iaaData/novel/tencent/adList/autoAcquisitionSet"
+import UpdateAd3 from "@/pages/iaaData/components/UpdateAd3"
 
 
 /**
 /**
  * 腾讯广告列表
  * 腾讯广告列表
@@ -30,6 +32,8 @@ const TencentIaaAd: React.FC = () => {
     const [visible, setVisible] = useState<boolean>(false)
     const [visible, setVisible] = useState<boolean>(false)
     const [promotionId, setPromotionId] = useState<number>()
     const [promotionId, setPromotionId] = useState<number>()
     const [adName, setAdName] = useState<string>('')
     const [adName, setAdName] = useState<string>('')
+    const [updateData, setUpdateDate] = useState<{ visible: boolean, type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI' | '修改投放首日开始时间' }>({ visible: false, type: '修改出价' })
+    const [autoAcqVisible, setAutoAcqVisible] = useState<boolean>(false)
 
 
     const editAdqAdgroupsData = useAjax((params) => newEditAdqAdgroupsDataApi(params))
     const editAdqAdgroupsData = useAjax((params) => newEditAdqAdgroupsDataApi(params))
     const getGDTList = useAjax((params) => getGDTListApi(params))
     const getGDTList = useAjax((params) => getGDTListApi(params))
@@ -95,6 +99,60 @@ const TencentIaaAd: React.FC = () => {
                 {/* <Switch checkedChildren="开启全选" unCheckedChildren="关闭全选" checked={!isZj} onChange={(e) => { setIsZj(!e); }} /> */}
                 {/* <Switch checkedChildren="开启全选" unCheckedChildren="关闭全选" checked={!isZj} onChange={(e) => { setIsZj(!e); }} /> */}
                 <Button type='primary' size="small" style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动</Button>
                 <Button type='primary' size="small" style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动</Button>
                 <Button type='primary' size="small" style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停</Button>
                 <Button type='primary' size="small" style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停</Button>
+                <Button type='primary' danger icon={<DeleteOutlined />} disabled={selectedRows.length === 0} onClick={() => {
+                    setUpdateDate({ visible: true, type: '删除' })
+                }}>删除</Button>
+                <Dropdown
+                    menu={{
+                        items: [
+                            {
+                                label: <span style={{ display: 'inline-block', width: 120 }}>修改出价</span>,
+                                key: '1',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setUpdateDate({ visible: true, type: '修改出价' }) }
+                            },
+                            {
+                                label: '修改名称',
+                                key: '2',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setUpdateDate({ visible: true, type: '修改名称' }) }
+                            },
+                            {
+                                label: '修改日限额',
+                                key: '3',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setUpdateDate({ visible: true, type: '修改日限额' }) }
+                            },
+                            {
+                                label: '修改投放日期',
+                                key: '4',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setUpdateDate({ visible: true, type: '修改投放时间' }) }
+                            },
+                            {
+                                label: '修改投放首日开始时间',
+                                key: '5',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setUpdateDate({ visible: true, type: '修改投放首日开始时间' }) }
+                            },
+                            {
+                                label: '一键起量',
+                                key: '6',
+                                disabled: selectedRows.length === 0,
+                                onClick: () => { setAutoAcqVisible(true) }
+                            }
+                        ]
+                    }}
+                    placement="bottomLeft"
+                    arrow
+                >
+                    <Button>
+                        <Space>
+                            修改广告
+                            <DownOutlined />
+                        </Space>
+                    </Button>
+                </Dropdown>
                 <span style={{ color: 'red' }}>操作完数据结果延时5分钟之内,即时结果去腾讯后台查看</span>
                 <span style={{ color: 'red' }}>操作完数据结果延时5分钟之内,即时结果去腾讯后台查看</span>
             </Space>}
             </Space>}
             leftChild={<QueryForm
             leftChild={<QueryForm
@@ -208,6 +266,36 @@ const TencentIaaAd: React.FC = () => {
         />
         />
 
 
         {visible && <DayAd iaaApp={initialState?.iaaApp as string} adName={adName} visible={visible} onClose={() => { setVisible(false); setPromotionId(undefined) }} queryForm={queryForm} promotionId={promotionId} />}
         {visible && <DayAd iaaApp={initialState?.iaaApp as string} adName={adName} visible={visible} onClose={() => { setVisible(false); setPromotionId(undefined) }} queryForm={queryForm} promotionId={promotionId} />}
+
+        {/* 修改广告 */}
+        {updateData.visible && <UpdateAd3
+            {...updateData}
+            updateData={selectedRows.map(item => ({ ...item, adgroupName: item.promotionName, adgroupId: item.promotionId }))}
+            onClose={() => {
+                setUpdateDate({ visible: false, type: '修改出价' })
+            }}
+            onChange={() => {
+                setUpdateDate({ visible: false, type: '修改出价' })
+                getGDTList.refresh()
+                if (updateData.type === '删除') {
+                    setSelectedRows([])
+                }
+            }}
+        />}
+
+        {/* 批量一键起量 */}
+        {autoAcqVisible && <AutoAcquisitionSet
+            selectAdList={selectedRows.map(item => ({ ...item, adgroupName: item.promotionName, adgroupId: item.promotionId }))}
+            visible={autoAcqVisible}
+            onClose={() => {
+                setAutoAcqVisible(false)
+            }}
+            onChange={() => {
+                setAutoAcqVisible(false)
+                getGDTList.refresh()
+                setSelectedRows([])
+            }}
+        />}
     </div>
     </div>
 }
 }
 
 

+ 197 - 0
src/pages/iaaData/novel/tencent/adList/autoAcquisitionSet.tsx

@@ -0,0 +1,197 @@
+import { InputNumber, message, Modal, Radio, Space, Switch, Table, Tooltip } from "antd"
+import React, { useEffect, useState } from "react"
+import '@/pages/iaaData/components/UpdateAd3/global.less'
+import style from './index.less'
+import { InfoCircleFilled, QuestionCircleOutlined } from "@ant-design/icons"
+import { useAjax } from "@/Hook/useAjax"
+import { updateBatchAdgroupInfoApi } from "@/services/gameData"
+
+interface Props {
+    selectAdList: any[]
+    visible?: boolean
+    onClose?: () => void
+    onChange?: () => void
+}
+
+/**
+ * 批量一键起量
+ * @param param0 
+ * @returns 
+ */
+const AutoAcquisitionSet: React.FC<Props> = ({ selectAdList, visible, onChange, onClose }) => {
+
+    /****************************************/
+    const [autoAcquisitionData, setAutoAcquisitionData] = useState<{ autoAcquisitionEnabled: boolean, autoAcquisitionBudget?: number, autoAcquisitionBudgetPercent?: number }>({ autoAcquisitionEnabled: false })
+    const [isPercent, setIsPercent] = useState<boolean>(false)
+    const [addType, setAddType] = useState<'fixed' | 'percent'>('fixed')
+    const updateBatchAdgroupInfo = useAjax((params) => updateBatchAdgroupInfoApi(params)) // 名称
+    const [failIdList, setFailIdList] = useState<{ adgroupId: number, code: number, message: string, messageCn: string }[]>([])
+    const [failVisible, setFailVisible] = useState<boolean>(false)
+    /****************************************/
+
+    useEffect(() => {
+        if (selectAdList.every(item => item.autoAcquisitionEnabled)) {
+            setIsPercent(true)
+        } else {
+            setIsPercent(false)
+        }
+    }, [selectAdList])
+
+    const handleOk = () => {
+        let params = { ...autoAcquisitionData }
+        if (params?.autoAcquisitionEnabled) {
+            if (addType === 'fixed' && !params?.autoAcquisitionBudget) {
+                message.error('请填写起量预算')
+                return
+            }
+            if (addType === 'percent' && !params?.autoAcquisitionBudgetPercent) {
+                message.error('请填写起量预算百分比')
+                return
+            }
+        }
+
+        if (params?.autoAcquisitionBudgetPercent !== null && params?.autoAcquisitionBudgetPercent !== undefined) params.autoAcquisitionBudgetPercent = params?.autoAcquisitionBudgetPercent / 100
+        let accountAdgroupMaps = [...new Set(selectAdList?.map(item => item.accountId + ',' + item.adgroupId))]
+        updateBatchAdgroupInfo.run({ accountAdgroupMaps, ...params }).then(res => {
+            if (res?.failIdList?.length === 0) {
+                message.success(`修改操作完成!`)
+                onChange?.()
+            } else {
+                setFailIdList(res?.list || [])
+                setFailVisible(true)
+            }
+        })
+        console.log(params)
+    }
+
+    return <Modal
+        title={<strong>批量修改一键起量</strong>}
+        open={visible}
+        onCancel={onClose}
+        onOk={handleOk}
+        className='modalResetCss'
+        width={750}
+        confirmLoading={updateBatchAdgroupInfo.loading}
+    >
+        <div className={style.autoAcquisitionSet}>
+            <div className={style.left}>
+                <Table
+                    dataSource={selectAdList}
+                    size="small"
+                    scroll={{ x: 400, y: 450 }}
+                    bordered
+                    rowKey={'adgroupId'}
+                    pagination={false}
+                    columns={[
+                        {
+                            title: '广告名称',
+                            dataIndex: 'adgroupName',
+                            key: 'adgroupName',
+                            width: 200,
+                            render(value) {
+                                return <span style={{ wordBreak: 'break-all' }}>{value}</span>
+                            },
+                        },
+                        {
+                            title: '原设置',
+                            dataIndex: 'beforeSet',
+                            key: 'beforeSet',
+                            width: 120,
+                            render(value, record) {
+                                if (!record?.autoAcquisitionEnabled) {
+                                    return '未开启'
+                                }
+                                return `一键起量中,起量预算:${record?.autoAcquisitionBudget} 元`
+                            },
+                        }
+                    ]}
+                />
+            </div>
+            <div className={style.right}>
+                <div className={style.header}>
+                    <Space>
+                        <span>修改一键起量</span>
+                        <Tooltip title={<div>
+                            <p>1. 一键起量期间产生的消耗不赔付,但转化计入赔付门槛判断;</p>
+                            <p>2. 一键起量可能导致转化成本高于预期,且起量结束后不一定能持续消耗。</p>
+                        </div>}>
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>
+                </div>
+                <div className={style.edit}>
+                    <div>
+                        <div className={style.tips}>
+                            <InfoCircleFilled style={{ color: '#296BEF', marginTop: 2 }} />
+                            {
+                                autoAcquisitionData?.autoAcquisitionEnabled ?
+                                    // '对于状态为“一键起量中”、“一键起量完成”、“一键起量中止”的广告,将会自动关闭一键起量,同时按照新的起量预算重新开启一键起量'
+                                    '开启一键起量'
+                                    :
+                                    '当前开关为关闭状态,点击「确定」将默认关闭已选广告的一键起量功能'
+                            }
+                        </div>
+                        <div>
+                            <Switch
+                                checkedChildren="开启"
+                                unCheckedChildren="未开启"
+                                onChange={(e) => {
+                                    setAutoAcquisitionData({ ...autoAcquisitionData, autoAcquisitionEnabled: e })
+                                }}
+                                checked={autoAcquisitionData?.autoAcquisitionEnabled}
+                            />
+                        </div>
+                        {autoAcquisitionData?.autoAcquisitionEnabled && <>
+                            <Radio.Group buttonStyle="solid" value={addType} onChange={(e) => setAddType(e.target.value)}>
+                                <Radio.Button value="fixed">固定值</Radio.Button>
+                                <Radio.Button value="percent" disabled={!isPercent}>百分比上下浮动修改</Radio.Button>
+                            </Radio.Group>
+                            {addType === 'fixed' ?
+                                <InputNumber placeholder="起量预算,建议设置为出价的10倍" min={200} max={100000} style={{ width: '100%' }} value={autoAcquisitionData?.autoAcquisitionBudget} onChange={(e) => setAutoAcquisitionData({ autoAcquisitionEnabled: true, autoAcquisitionBudget: e || 0 })} />
+                                :
+                                <InputNumber placeholder="起量预算,原有基础上下调百分比" style={{ width: '100%' }} addonAfter="%" value={autoAcquisitionData?.autoAcquisitionBudgetPercent} onChange={(e) => setAutoAcquisitionData({ autoAcquisitionEnabled: true, autoAcquisitionBudgetPercent: e || 0 })} />
+                            }
+                        </>}
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        {failVisible && <Modal
+            title={<strong>报错信息</strong>}
+            open={failVisible}
+            className='modalResetCss'
+            width={650}
+            onCancel={() => { setFailVisible(false); setFailIdList([]) }}
+            footer={null}
+        >
+            <Table
+                size="small"
+                bordered
+                rowKey={'adgroupId'}
+                columns={[{
+                    title: '广告ID',
+                    dataIndex: 'adgroupId',
+                    key: 'adgroupId',
+                    width: 110,
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: 'code',
+                    dataIndex: 'code',
+                    key: 'code',
+                    width: 70,
+                    align: 'center',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: '错误信息',
+                    dataIndex: 'messageCn',
+                    key: 'messageCn',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }]}
+                dataSource={failIdList}
+            />
+        </Modal>}
+    </Modal>
+}
+
+export default React.memo(AutoAcquisitionSet)

+ 12 - 0
src/pages/iaaData/novel/tencent/adList/const.tsx

@@ -46,4 +46,16 @@ export enum LANDINGTYPEEnum {
     'PROMOTED_OBJECT_TYPE_MINI_GAME_QQ' = 'QQ 小游戏',
     'PROMOTED_OBJECT_TYPE_MINI_GAME_QQ' = 'QQ 小游戏',
     'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT' = '微信公众号',
     'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT' = '微信公众号',
     'PROMOTED_OBJECT_TYPE_APP_QUICK_APP' = '快应用',
     'PROMOTED_OBJECT_TYPE_APP_QUICK_APP' = '快应用',
+}
+
+/** 一键起量 */
+export enum AUTO_ACQUISTION_STATUS {
+    AUTO_ACQUISTION_STATUS_UNKNOW="未开启一键起量功能",
+    AUTO_ACQUISTION_STATUS_PENDING="开启一键起量,探索中",
+    AUTO_ACQUISTION_STATUS_END_LESS_THAN_24H="起量完成(探索结束,预算花完,功能开启后未满 24h)",
+    AUTO_ACQUISTION_STATUS_END_MORE_THAN_24H="起量完成(探索结束,预算花完,功能开启后已满 24h)",
+    AUTO_ACQUISTION_STATUS_COMPLETED="起量结束(探索结束,距离广告开启已满 6h,但预算未花完(实际花费<起量预算*90%))",
+    AUTO_ACQUISTION_STATUS_SUSPEND_ON_LEARNING_FAIL="起量中止(探索过程中,因广告起量情况太差,从而探索中止)",
+    AUTO_ACQUISTION_STATUS_SUSPEND_ON_PLAYING_FAIL="起量中止(探索过程中,因广告无法播放,从而起量中止(包括广告主动或被动下线或 timeset 不连续))",
+    AUTO_ACQUISTION_STATUS_ADVERTISER_CLOSED="广告主主动关闭一键起量功能"
 }
 }

+ 48 - 0
src/pages/iaaData/novel/tencent/adList/index.less

@@ -0,0 +1,48 @@
+.autoAcquisitionSet {
+    display: flex;
+
+    .left {
+        width: 60%;
+    }
+
+    .right {
+        width: 40%;
+        border: 1px solid #f0f0f0;
+        display: flex;
+        flex-direction: column;
+
+        .header {
+            padding: 8px;
+            font-size: 14px;
+            font-weight: 600;
+            border-bottom: 1px solid #f0f0f0;
+            background: #fafafa;
+        }
+
+        .edit {
+            flex: 1;
+            display: flex;
+            align-items: center;
+            padding: 8px;
+            box-sizing: border-box;
+            width: 100%;
+
+            >div {
+                display: flex;
+                flex-direction: column;
+                gap: 10px;
+                width: 100%;
+            }
+        }
+
+        .tips {
+            border: 1px solid #D4E1FC;
+            border-radius: 18px;
+            display: flex;
+            gap: 8px;
+            padding: 7px 12px;
+            background-color: #f5f8ff;
+            margin-bottom: 10px;
+        }
+    }
+}

+ 111 - 7
src/pages/iaaData/novel/tencent/adList/index.tsx

@@ -5,11 +5,13 @@ import TablePro from "@/components/TablePro"
 import columns12 from "./tableConfig"
 import columns12 from "./tableConfig"
 import moment from "moment"
 import moment from "moment"
 import { useModel } from "umi"
 import { useModel } from "umi"
-import { Button, message, notification, Space } from "antd"
+import { Button, Dropdown, message, notification, Select, Space } from "antd"
 import { newEditAdqAdgroupsDataApi } from "@/services/gameData"
 import { newEditAdqAdgroupsDataApi } from "@/services/gameData"
-import { PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"
+import { DeleteOutlined, DownOutlined, PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"
 import DayAd from "./dayAd"
 import DayAd from "./dayAd"
 import QueryFormNovel from "@/components/QueryForm/queryFormNovel"
 import QueryFormNovel from "@/components/QueryForm/queryFormNovel"
+import UpdateAd3 from "@/pages/iaaData/components/UpdateAd3"
+import AutoAcquisitionSet from "./autoAcquisitionSet"
 
 
 /**
 /**
  * 腾讯广告列表
  * 腾讯广告列表
@@ -30,6 +32,9 @@ const TencentNovelAd: React.FC<{ configName?: string, dayConfigName?: string }>
     const [visible, setVisible] = useState<boolean>(false)
     const [visible, setVisible] = useState<boolean>(false)
     const [promotionId, setPromotionId] = useState<number>()
     const [promotionId, setPromotionId] = useState<number>()
     const [adName, setAdName] = useState<string>('')
     const [adName, setAdName] = useState<string>('')
+    const [updateData, setUpdateDate] = useState<{ visible: boolean, type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI' | '修改投放首日开始时间' }>({ visible: false, type: '修改出价' })
+    const [autoAcqVisible, setAutoAcqVisible] = useState<boolean>(false)
+    const [handleType, setHandleType] = useState<number>(1)
 
 
     const editAdqAdgroupsData = useAjax((params) => newEditAdqAdgroupsDataApi(params))
     const editAdqAdgroupsData = useAjax((params) => newEditAdqAdgroupsDataApi(params))
     const getGDTList = useAjax((params) => getNovelGDTListApi(params))
     const getGDTList = useAjax((params) => getNovelGDTListApi(params))
@@ -88,13 +93,82 @@ const TencentNovelAd: React.FC<{ configName?: string, dayConfigName?: string }>
         })
         })
     }
     }
 
 
-
     return <div>
     return <div>
         <TablePro
         <TablePro
             czChild={<Space>
             czChild={<Space>
                 {/* <Switch checkedChildren="开启全选" unCheckedChildren="关闭全选" checked={!isZj} onChange={(e) => { setIsZj(!e); }} /> */}
                 {/* <Switch checkedChildren="开启全选" unCheckedChildren="关闭全选" checked={!isZj} onChange={(e) => { setIsZj(!e); }} /> */}
-                <Button type='primary' size="small" style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动</Button>
-                <Button type='primary' size="small" style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停</Button>
+                <Select
+                    style={{ width: 120 }}
+                    onChange={(e) => {
+                        setHandleType(e)
+                        setSelectedRows([])
+                    }}
+                    value={handleType}
+                    dropdownMatchSelectWidth={false}
+                    options={[{ label: '广告操作', value: 1 }, { label: '修改深度优化期望ROI', value: 3 }]}
+                />
+                <Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动</Button>
+                <Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停</Button>
+                {handleType === 1 ? <>
+                    <Button type='primary' danger icon={<DeleteOutlined />} disabled={selectedRows.length === 0} onClick={() => {
+                        setUpdateDate({ visible: true, type: '删除' })
+                    }}>删除</Button>
+                    <Dropdown
+                        menu={{
+                            items: [
+                                {
+                                    label: <span style={{ display: 'inline-block', width: 120 }}>修改出价</span>,
+                                    key: '1',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setUpdateDate({ visible: true, type: '修改出价' }) }
+                                },
+                                {
+                                    label: '修改名称',
+                                    key: '2',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setUpdateDate({ visible: true, type: '修改名称' }) }
+                                },
+                                {
+                                    label: '修改日限额',
+                                    key: '3',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setUpdateDate({ visible: true, type: '修改日限额' }) }
+                                },
+                                {
+                                    label: '修改投放日期',
+                                    key: '4',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setUpdateDate({ visible: true, type: '修改投放时间' }) }
+                                },
+                                {
+                                    label: '修改投放首日开始时间',
+                                    key: '5',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setUpdateDate({ visible: true, type: '修改投放首日开始时间' }) }
+                                },
+                                {
+                                    label: '一键起量',
+                                    key: '6',
+                                    disabled: selectedRows.length === 0,
+                                    onClick: () => { setAutoAcqVisible(true) }
+                                }
+                            ]
+                        }}
+                        placement="bottomLeft"
+                        arrow
+                    >
+                        <Button>
+                            <Space>
+                                修改广告
+                                <DownOutlined />
+                            </Space>
+                        </Button>
+                    </Dropdown>
+                </> : <>
+                    <Button type='primary' disabled={selectedRows.length === 0} onClick={() => {
+                        setUpdateDate({ visible: true, type: '深度优化ROI' })
+                    }}>修改深度优化期望ROI</Button>
+                </>}
                 <span style={{ color: 'red' }}>操作完数据结果延时5分钟之内,即时结果去腾讯后台查看</span>
                 <span style={{ color: 'red' }}>操作完数据结果延时5分钟之内,即时结果去腾讯后台查看</span>
             </Space>}
             </Space>}
             leftChild={<QueryFormNovel
             leftChild={<QueryFormNovel
@@ -165,7 +239,7 @@ const TencentNovelAd: React.FC<{ configName?: string, dayConfigName?: string }>
             page={getGDTList?.data?.data?.current || 1}
             page={getGDTList?.data?.data?.current || 1}
             pageSize={getGDTList?.data?.data?.size || 20}
             pageSize={getGDTList?.data?.data?.size || 20}
             total={getGDTList?.data?.data?.total || 0}
             total={getGDTList?.data?.data?.total || 0}
-            dataSource={getGDTList?.data?.data?.records?.map((item: any) => ({ ...item, id: item.adgroupId }))}
+            dataSource={getGDTList?.data?.data?.records?.map((item: any) => ({ ...item, id: item.adgroupId, deepConversionSpec: item?.deepConversionSpecJson ? JSON.parse(item.deepConversionSpecJson) : {} }))}
             onChange={(pagination: any, _: any, sortData: any) => {
             onChange={(pagination: any, _: any, sortData: any) => {
                 let { current, pageSize } = pagination
                 let { current, pageSize } = pagination
                 let newQueryForm = JSON.parse(JSON.stringify(queryForm))
                 let newQueryForm = JSON.parse(JSON.stringify(queryForm))
@@ -183,7 +257,7 @@ const TencentNovelAd: React.FC<{ configName?: string, dayConfigName?: string }>
             rowSelection={{
             rowSelection={{
                 selectedRowKeys: selectedRows.map(item => item.adgroupId + ''),
                 selectedRowKeys: selectedRows.map(item => item.adgroupId + ''),
                 getCheckboxProps: (record: any) => ({
                 getCheckboxProps: (record: any) => ({
-                    disabled: record.status === 'STATUS_DELETED' || record?.accountId === '总计'
+                    disabled: handleType === 3 ?  record.status === 'STATUS_DELETED' || record?.accountId === '总计' || !(record?.deepConversionSpec?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_PURCHASE_ROAS') : record.status === 'STATUS_DELETED' || record?.accountId === '总计'
                 }),
                 }),
                 onSelect: (record: { adgroupId: number }, selected: boolean) => {
                 onSelect: (record: { adgroupId: number }, selected: boolean) => {
                     if (selected) {
                     if (selected) {
@@ -220,6 +294,36 @@ const TencentNovelAd: React.FC<{ configName?: string, dayConfigName?: string }>
         />
         />
 
 
         {visible && <DayAd configName={dayConfigName} iaaApp={initialState?.iaaApp as string} adName={adName} visible={visible} onClose={() => { setVisible(false); setPromotionId(undefined) }} queryForm={{ costDayBegin: queryForm?.dataTimeMin, costDayEnd: queryForm?.dataTimeMax }} promotionId={promotionId} />}
         {visible && <DayAd configName={dayConfigName} iaaApp={initialState?.iaaApp as string} adName={adName} visible={visible} onClose={() => { setVisible(false); setPromotionId(undefined) }} queryForm={{ costDayBegin: queryForm?.dataTimeMin, costDayEnd: queryForm?.dataTimeMax }} promotionId={promotionId} />}
+
+        {/* 修改广告 */}
+        {updateData.visible && <UpdateAd3
+            {...updateData}
+            updateData={selectedRows}
+            onClose={() => {
+                setUpdateDate({ visible: false, type: '修改出价' })
+            }}
+            onChange={() => {
+                setUpdateDate({ visible: false, type: '修改出价' })
+                getGDTList.refresh()
+                if (updateData.type === '删除') {
+                    setSelectedRows([])
+                }
+            }}
+        />}
+
+        {/* 批量一键起量 */}
+        {autoAcqVisible && <AutoAcquisitionSet
+            selectAdList={selectedRows}
+            visible={autoAcqVisible}
+            onClose={() => {
+                setAutoAcqVisible(false)
+            }}
+            onChange={() => {
+                setAutoAcqVisible(false)
+                getGDTList.refresh()
+                setSelectedRows([])
+            }}
+        />}
     </div>
     </div>
 }
 }
 
 

+ 44 - 22
src/pages/iaaData/novel/tencent/adList/tableConfig.tsx

@@ -1,10 +1,11 @@
 import WidthEllipsis from "@/components/widthEllipsis"
 import WidthEllipsis from "@/components/widthEllipsis"
-import { Badge, Progress, Space, Statistic } from "antd"
+import { Badge, Progress, Space, Statistic, Tag } from "antd"
 import React from "react"
 import React from "react"
-import { ADGROUP_STATUS, AdUnitType_Enum, BID_MODE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM, PRODUCT_TYPE_ENUM, SMART_BID_TYPE_ENUM } from "../../../const"
+import { ADGROUP_STATUS, BID_MODE_ENUM, MARKETING_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, OPTIMIZATIONGOAL_ENUM, PRODUCT_TYPE_ENUM, SMART_BID_TYPE_ENUM } from "../../../const"
 import SwitchStatus from "./switchStatus"
 import SwitchStatus from "./switchStatus"
 import CreativePreview from "../../../components/CreativePreview"
 import CreativePreview from "../../../components/CreativePreview"
 import TimeSeriesLook from "@/pages/iaaData/components/TimeSeriesLook"
 import TimeSeriesLook from "@/pages/iaaData/components/TimeSeriesLook"
+import { AUTO_ACQUISTION_STATUS } from "./const"
 
 
 function columns12(dayHandle: (data: any) => void, onChange?: () => void): { label: string, fieldSHow?: { label: string, saveField: string, defaultValue: any[], data: any[] }, data: any[] }[] {
 function columns12(dayHandle: (data: any) => void, onChange?: () => void): { label: string, fieldSHow?: { label: string, saveField: string, defaultValue: any[], data: any[] }, data: any[] }[] {
 
 
@@ -80,28 +81,41 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '深度优化出价', dataIndex: 'deepConversionWorthRate', label: '广告基本信息', align: 'center', width: 70, default: 14,
+                    title: '一键起量', dataIndex: 'autoAcquisitionEnabled', label: '广告基本信息', width: 200, default: 14,
+                    render: (a: boolean, b: any) => {
+                        if (b?.accountId === '总计') return '--';
+                        return <Space size={2}>
+                            {a ? <>
+                                <Tag color="success">开启</Tag>
+                                <Statistic prefix={'¥'} value={b?.autoAcquisitionBudget || 0} precision={2} />
+                            </> : <Tag color="error">关闭</Tag>}
+                            {b?.autoAcquisitionStatus && <div style={{ width: 65, paddingLeft: 4 }}><WidthEllipsis value={AUTO_ACQUISTION_STATUS[b?.autoAcquisitionStatus as keyof typeof AUTO_ACQUISTION_STATUS]} /></div>}
+                        </Space>
+                    }
+                },
+                {
+                    title: '深度优化出价', dataIndex: 'deepConversionWorthRate', label: '广告基本信息', align: 'center', width: 70, default: 15,
                     render: (a: string, b: { accountId: any }) => {
                     render: (a: string, b: { accountId: any }) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return <Statistic value={a || 0} precision={2} />
                         return <Statistic value={a || 0} precision={2} />
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '出价类型', dataIndex: 'smartBidType', label: '广告基本信息', align: 'center', width: 80, default: 15,
+                    title: '出价类型', dataIndex: 'smartBidType', label: '广告基本信息', align: 'center', width: 80, default: 16,
                     render: (a: string, b: any) => {
                     render: (a: string, b: any) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return SMART_BID_TYPE_ENUM[a as keyof typeof SMART_BID_TYPE_ENUM]
                         return SMART_BID_TYPE_ENUM[a as keyof typeof SMART_BID_TYPE_ENUM]
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '广告组日预算(元)', dataIndex: 'dailyBudget', label: '广告基本信息', align: 'right', width: 70, sorter: true, default: 16,
+                    title: '广告组日预算(元)', dataIndex: 'dailyBudget', label: '广告基本信息', align: 'right', width: 70, sorter: true, default: 17,
                     render: (a: string, b: any) => {
                     render: (a: string, b: any) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return <Statistic value={a || 0} precision={2} />
                         return <Statistic value={a || 0} precision={2} />
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '是否开启自动版位功能', dataIndex: 'automaticSiteEnabled', label: '广告基本信息', align: 'center', width: 80, default: 17,
+                    title: '是否开启自动版位功能', dataIndex: 'automaticSiteEnabled', label: '广告基本信息', align: 'center', width: 80, default: 18,
                     render: (a: string, b: any) => {
                     render: (a: string, b: any) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return <WidthEllipsis value={a ? '是' : '否'} />
                         return <WidthEllipsis value={a ? '是' : '否'} />
@@ -112,33 +126,33 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     render: (a: string) => (<WidthEllipsis value={a} />)
                     render: (a: string) => (<WidthEllipsis value={a} />)
                 },
                 },
                 {
                 {
-                    title: '是否已删除', dataIndex: 'isDeleted', label: '广告基本信息', align: 'center', width: 60, default: 18,
+                    title: '是否已删除', dataIndex: 'isDeleted', label: '广告基本信息', align: 'center', width: 60, default: 19,
                     render: (a: any, b: any) => {
                     render: (a: any, b: any) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return <Badge status={!a ? "processing" : "error"} text={a ? '是' : '否'} />
                         return <Badge status={!a ? "processing" : "error"} text={a ? '是' : '否'} />
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '广告状态', dataIndex: 'systemStatus', label: '广告基本信息', align: 'center', width: 100, default: 19,
+                    title: '广告状态', dataIndex: 'systemStatus', label: '广告基本信息', align: 'center', width: 100, default: 20,
                     render: (a: string, b: any) => {
                     render: (a: string, b: any) => {
                         if (b?.accountId === '总计') return '--';
                         if (b?.accountId === '总计') return '--';
                         return ADGROUP_STATUS[a as keyof typeof ADGROUP_STATUS]
                         return ADGROUP_STATUS[a as keyof typeof ADGROUP_STATUS]
                     }
                     }
                 },
                 },
                 {
                 {
-                    title: '营销目的', dataIndex: 'marketingGoal', label: '广告基本信息', align: 'center', width: 85, default: 20,
+                    title: '营销目的', dataIndex: 'marketingGoal', label: '广告基本信息', align: 'center', width: 85, default: 21,
                     render: (a: string) => (<WidthEllipsis value={MARKETING_GOAL_ENUM[a as keyof typeof MARKETING_GOAL_ENUM]} />)
                     render: (a: string) => (<WidthEllipsis value={MARKETING_GOAL_ENUM[a as keyof typeof MARKETING_GOAL_ENUM]} />)
                 },
                 },
                 {
                 {
-                    title: '推广内容资产类型', dataIndex: 'marketingTargetType', label: '广告基本信息', align: 'center', width: 85, default: 21,
+                    title: '推广内容资产类型', dataIndex: 'marketingTargetType', label: '广告基本信息', align: 'center', width: 85, default: 22,
                     render: (a: string) => (<WidthEllipsis value={MARKETING_TARGET_TYPE_ENUM[a as keyof typeof MARKETING_TARGET_TYPE_ENUM]} />)
                     render: (a: string) => (<WidthEllipsis value={MARKETING_TARGET_TYPE_ENUM[a as keyof typeof MARKETING_TARGET_TYPE_ENUM]} />)
                 },
                 },
                 {
                 {
-                    title: '标记备注', dataIndex: 'tagRemark', label: '广告基本信息', align: 'center', width: 80, default: 22,
+                    title: '标记备注', dataIndex: 'tagRemark', label: '广告基本信息', align: 'center', width: 80, default: 23,
                     render: (a: string) => (<WidthEllipsis value={a} />)
                     render: (a: string) => (<WidthEllipsis value={a} />)
                 },
                 },
                 {
                 {
-                    title: '创意预览', dataIndex: 'dynamicCreativeVOList', label: '腾讯广告列表', width: 150, default: 31,
+                    title: '创意预览', dataIndex: 'dynamicCreativeVOList', label: '腾讯广告列表', width: 150, default: 32,
                     render: (a: any, b: any) => {
                     render: (a: any, b: any) => {
                         if (b?.accountId === '总计') {
                         if (b?.accountId === '总计') {
                             return '--'
                             return '--'
@@ -160,7 +174,7 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
             label: '广告消耗信息',
             label: '广告消耗信息',
             data: [
             data: [
                 {
                 {
-                    title: '消耗', dataIndex: 'cost', label: '广告消耗信息', align: 'center', width: 85, default: 23, sorter: true,
+                    title: '消耗', dataIndex: 'cost', label: '广告消耗信息', align: 'center', width: 85, default: 24, sorter: true,
                     className: 'padding_0',
                     className: 'padding_0',
                     render: (a: number) => <div style={{ height: 27, position: 'relative' }}>
                     render: (a: number) => <div style={{ height: 27, position: 'relative' }}>
                         <Progress
                         <Progress
@@ -176,31 +190,31 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     </div>
                     </div>
                 },
                 },
                 {
                 {
-                    title: '曝光量', dataIndex: 'viewCount', label: '广告消耗信息', align: 'center', width: 70, default: 24, sorter: true,
+                    title: '曝光量', dataIndex: 'viewCount', label: '广告消耗信息', align: 'center', width: 70, default: 25, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} />
                     render: (a: string) => <Statistic value={a || 0} />
                 },
                 },
                 {
                 {
-                    title: '千次曝光成本', dataIndex: 'thousandDisplayPrice', label: '广告消耗信息', align: 'right', width: 65, default: 25, sorter: true,
+                    title: '千次曝光成本', dataIndex: 'thousandDisplayPrice', label: '广告消耗信息', align: 'right', width: 65, default: 26, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
                 {
                 {
-                    title: '点击量', dataIndex: 'clickCount', label: '广告消耗信息', align: 'center', width: 70, default: 26, sorter: true,
+                    title: '点击量', dataIndex: 'clickCount', label: '广告消耗信息', align: 'center', width: 70, default: 27, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} />
                     render: (a: string) => <Statistic value={a || 0} />
                 },
                 },
                 {
                 {
-                    title: '点击率', dataIndex: 'ctr', label: '广告消耗信息', align: 'center', width: 70, default: 27, sorter: true,
+                    title: '点击率', dataIndex: 'ctr', label: '广告消耗信息', align: 'center', width: 70, default: 28, sorter: true,
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 50 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 50 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                 },
                 },
                 {
                 {
-                    title: '点击均价', dataIndex: 'cpc', label: '广告消耗信息', align: 'center', width: 65, default: 28, sorter: true,
+                    title: '点击均价', dataIndex: 'cpc', label: '广告消耗信息', align: 'center', width: 65, default: 29, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
                 {
                 {
-                    title: '不感兴趣点击次数', dataIndex: 'noInterestCount', label: '广告消耗信息', align: 'center', width: 65, default: 29, sorter: true,
+                    title: '不感兴趣点击次数', dataIndex: 'noInterestCount', label: '广告消耗信息', align: 'center', width: 65, default: 30, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} />
                     render: (a: string) => <Statistic value={a || 0} />
                 },
                 },
                 {
                 {
-                    title: '朋友圈视频播放次数', dataIndex: 'videoPlayCount', label: '广告消耗信息', align: 'center', width: 65, default: 30, sorter: true,
+                    title: '朋友圈视频播放次数', dataIndex: 'videoPlayCount', label: '广告消耗信息', align: 'center', width: 65, default: 31, sorter: true,
                     render: (a: string) => <Statistic value={a || 0} />
                     render: (a: string) => <Statistic value={a || 0} />
                 },
                 },
             ]
             ]
@@ -336,7 +350,7 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
             data: [
             data: [
                 {
                 {
                     title: '激活首24小时广告变现ARPPU(平台上报)', dataIndex: 'firstDayAdPurArppuCost24hPla', label: '其他业务(平台上报指标)', width: 130, align: 'center', sorter: true, className: 'green2ColorClass',
                     title: '激活首24小时广告变现ARPPU(平台上报)', dataIndex: 'firstDayAdPurArppuCost24hPla', label: '其他业务(平台上报指标)', width: 130, align: 'center', sorter: true, className: 'green2ColorClass',
-                    render: (a: string) => <Statistic value={a || 0} precision={2}/>
+                    render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
                 {
                 {
                     title: '激活首24小时广告变现ROI(平台上报)', dataIndex: 'incomeRoi124hPla', label: '其他业务(平台上报指标)', width: 110, align: 'center', sorter: true, className: 'green2ColorClass',
                     title: '激活首24小时广告变现ROI(平台上报)', dataIndex: 'incomeRoi124hPla', label: '其他业务(平台上报指标)', width: 110, align: 'center', sorter: true, className: 'green2ColorClass',
@@ -475,6 +489,10 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '广告变现人数', dataIndex: 'appAdPayingUsers', label: '其他业务(其他指标)', width: 90, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} />
+                },
                 {
                 {
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
@@ -507,6 +525,10 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '注册次数成本', dataIndex: 'regPvCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} precision={2} />
+                },
                 {
                 {
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 110, align: 'center', sorter: true, className: 'purple1ColorClass',
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 110, align: 'center', sorter: true, className: 'purple1ColorClass',
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
@@ -622,7 +644,7 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
             label: '操作',
             label: '操作',
             data: [
             data: [
                 {
                 {
-                    title: '操作', dataIndex: 'cz', label: '操作', align: 'center', width: 150, default: 32,
+                    title: '操作', dataIndex: 'cz', label: '操作', align: 'center', width: 150, default: 33,
                     render: (_: number, b: any) => {
                     render: (_: number, b: any) => {
                         if (b?.accountId === '总计') return '--'
                         if (b?.accountId === '总计') return '--'
                         return <Space>
                         return <Space>

+ 8 - 0
src/pages/iaaData/novel/tencent/adList/tableConfigDay.tsx

@@ -367,6 +367,10 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '广告变现人数', dataIndex: 'appAdPayingUsers', label: '其他业务(其他指标)', width: 90, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} />
+                },
                 {
                 {
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
@@ -399,6 +403,10 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '注册次数成本', dataIndex: 'regPvCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} precision={2} />
+                },
                 {
                 {
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 110, align: 'center', sorter: true, className: 'purple1ColorClass',
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 110, align: 'center', sorter: true, className: 'purple1ColorClass',
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />

+ 8 - 0
src/pages/iaaData/novel/tencent/dynamic/tableConfig.tsx

@@ -494,6 +494,10 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '广告变现人数', dataIndex: 'appAdPayingUsers', label: '其他业务(其他指标)', width: 90, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} />
+                },
                 {
                 {
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
@@ -526,6 +530,10 @@ function columns12(dayHandle: (data: any) => void, onChange?: () => void): { lab
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '注册次数成本', dataIndex: 'regPvCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} precision={2} />
+                },
                 {
                 {
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />

+ 8 - 0
src/pages/iaaData/novel/tencent/dynamic/tableConfigDay.tsx

@@ -452,6 +452,10 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '激活14日广告变现金额', dataIndex: 'incomeVal14', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '广告变现人数', dataIndex: 'appAdPayingUsers', label: '其他业务(其他指标)', width: 90, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} />
+                },
                 {
                 {
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '广告变现金额', dataIndex: 'adMonetizationAmount', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
@@ -484,6 +488,10 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册成本', dataIndex: 'regCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                     render: (a: string) => <Statistic value={a || 0} precision={2} />
                 },
                 },
+                {
+                    title: '注册次数成本', dataIndex: 'regPvCost', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
+                    render: (a: string) => <Statistic value={a || 0} precision={2} />
+                },
                 {
                 {
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     title: '注册率', dataIndex: 'regRate', label: '其他业务(其他指标)', width: 80, align: 'center', sorter: true, className: 'volcanoColorClass',
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 0.5 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />

+ 62 - 0
src/services/gameData/index.ts

@@ -227,6 +227,68 @@ export async function newEditAdqAdgroupsDataApi(data: EditAdqAdgroupsProps) {
     });
     });
 }
 }
 
 
+/**
+ * 删除广告
+ * @param data 
+ * @returns 
+ */
+export async function delBatchApi(data: ADQV3.AccountAdgroupMapsProps) {
+    return request(api + '/adq/adgroup/delBatch', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 修改时间
+ * @param data 
+ * @returns 
+ */
+export async function modifyAdTimeBatchApi(data: ADQV3.ModifyAdTimeBatchProps) {
+    return request(api + '/adq/adgroup/modifyAdTimeBatch', {
+        method: 'PUT',
+        data
+    });
+}
+
+
+/**
+ * 出价
+ * @param data 
+ * @returns 
+ */
+export async function modifyAmountBatchApi(data: ADQV3.ModifyAmountBatchProps) {
+    return request(api + '/adq/adgroup/modifyAmountBatch', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 修改广告日限额
+ * @param data 
+ * @returns 
+ */
+export async function modifyDailyBudgetBatchApi(data: ADQV3.ModifyDailyBudgetBatchProps) {
+    return request(api + '/adq/adgroup/modifyDailyBudgetBatch', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 修改广告信息 名称
+ * @param data 
+ * @returns 
+ */
+export async function updateBatchAdgroupInfoApi(data: ADQV3.UpdateBatchAdgroupInfoProps) {
+    return request(api + '/adq/adgroup/updateBatchAdgroupInfo', {
+        method: 'PUT',
+        data
+    });
+}
+
+
 export interface EditTTAdgroupsProps {
 export interface EditTTAdgroupsProps {
     suspend: boolean
     suspend: boolean
     accountAdgroupMaps: string[] // "广告id和广告账号id的映射关系字符串 (逗号拼接)"
     accountAdgroupMaps: string[] // "广告id和广告账号id的映射关系字符串 (逗号拼接)"

+ 68 - 0
src/services/gameData/typings.d.ts

@@ -0,0 +1,68 @@
+declare namespace ADQV3 {
+    interface AdProps {
+        userId: number
+        creativeHandle?: (id: number) => void
+    };
+    interface CreativeProps {
+        queryForm: GetDynamicCreativeProps,
+        setQueryForm: React.Dispatch<React.SetStateAction<GetDynamicCreativeProps>>,
+        userId: number
+    };
+    interface GetAdListProps {
+        pageNum: number;
+        pageSize: number;
+        useType: 1 | 2,   // 1:小说(默认值)2:游戏
+        accountMemo?: string,  // 腾讯备注
+        accountRemark?: string, // 本地备注
+        accountIdList?: any[], // 广告账号
+        adgroupIdList?: any[], // 广告组
+        adgroupName?: string,  // 广告名称
+        putUserIdList?: number[], // 投手
+        systemStatusList?: string[], // 广告状态
+        beginDate?: string,
+        endDate?: string
+    };
+    type AccountAdgroupMapsProps = {
+        accountAdgroupMaps: string[]
+    };
+    interface ModifyStatusBatchProps extends AccountAdgroupMapsProps {
+        suspend: boolean
+    };
+    interface ModifyAmountBatchProps extends AccountAdgroupMapsProps {
+        bidAmount?: number
+        bidAmountPercent?: number
+    };
+    interface GetDynamicCreativeProps {
+        pageNum: number;
+        pageSize: number;
+        userId: number;
+        isDeleted?: boolean;
+        creativeName?: string;
+        creativeId?: number;
+        adgroupId?: number;
+        accountId?: number
+    }
+    interface ModifyAdTimeBatchProps extends AccountAdgroupMapsProps {
+        beginDate: string,
+        endDate: string,
+        timeSeries: string
+    }
+    interface UpdateBatchAdgroupInfoProps extends AccountAdgroupMapsProps {
+        adgroupName?: string
+        autoAcquisitionEnabled?: boolean
+        autoAcquisitionBudget?: number
+        autoAcquisitionBudgetPercent?: number
+    }
+    interface ModifyDailyBudgetBatchProps extends AccountAdgroupMapsProps {
+        bidAmount: number
+    }
+    interface DynamicCreativeLogProps {
+        pageNum: number,
+        pageSize: number,
+        accountId?: number,
+        adgroupId?: number,
+        creativeId?: number,
+        creativeName?: string,
+        userId?: number
+    }
+}