wjx 7 bulan lalu
induk
melakukan
a60ad460e9

+ 1 - 1
src/pages/launchSystemV3/material/cloudNew/folder.tsx

@@ -1,6 +1,6 @@
 import React, { forwardRef, Ref, useContext, useImperativeHandle } from "react"
 import style from './index.less'
-import { Button, Empty, Spin, Tree, Typography } from "antd"
+import { Button, Empty, Spin, Tree } from "antd"
 import { DataNode, DirectoryTreeProps, EventDataNode } from "antd/lib/tree";
 import { DispatchCloudNew } from ".";
 

+ 0 - 1
src/pages/launchSystemV3/material/cloudNew/index.tsx

@@ -11,7 +11,6 @@ import ManageFolder from "./manageFolder";
 import { ExclamationCircleOutlined, FolderOpenOutlined, FolderOutlined } from "@ant-design/icons";
 import { updateTreeData } from "./const";
 import Search from "./search";
-import Details from "./details";
 
 export const DispatchCloudNew = React.createContext<CLOUDNEW.CloudNewReactContent | null>(null);
 

+ 19 - 3
src/pages/launchSystemV3/material/cloudNew/material.tsx

@@ -1,8 +1,8 @@
 import React, { forwardRef, Ref, useContext, useEffect, useImperativeHandle, useRef, useState } from "react"
 import style from './index.less'
-import { Breadcrumb, Button, Card, Checkbox, Dropdown, Empty, message, Modal, Pagination, Radio, Spin, Typography } from "antd"
+import { Breadcrumb, Button, Card, Checkbox, Dropdown, Empty, message, Modal, Pagination, Popconfirm, Radio, Spin, Typography } from "antd"
 import { DispatchCloudNew } from "."
-import { delMaterialApi, getFolderListApi, getMaterialListApi } from "@/services/adqV3/cloudNew"
+import { deleteBatchApi, delMaterialApi, getFolderListApi, getMaterialListApi } from "@/services/adqV3/cloudNew"
 import { useAjax } from "@/Hook/useAjax"
 import { useSize } from "ahooks"
 import './global.less'
@@ -61,6 +61,7 @@ const Material = forwardRef(({ onAddFolder, onUpdateFolder, onDelFolder }: Props
 
     const getFolderList = useAjax((params) => getFolderListApi(params))
     const delMaterial = useAjax((params) => delMaterialApi(params))
+    const deleteBatch = useAjax((params) => deleteBatchApi(params))
     const getMaterialList = useAjax((params) => getMaterialListApi(params))
     /********************************/
 
@@ -314,6 +315,21 @@ const Material = forwardRef(({ onAddFolder, onUpdateFolder, onDelFolder }: Props
                     setMoveVisible(true)
                     setMoveType(batchType as any)
                 }}>{batchType === 'folder' ? '移动文件夹' : '移动素材'}</Button>
+                {batchType === 'file' && <Popconfirm
+                    title="确定删除?"
+                    onConfirm={() => {
+                        const hide = message.loading('正在删除...', 0, () => {});
+                        deleteBatch.run(checkedFolderList).then(res => {
+                            hide()
+                            if (res) {
+                                getMaterialList.refresh()
+                                message.success('删除成功')
+                            }
+                        }).catch(() => hide())
+                    }}
+                >
+                    <Button danger disabled={checkedFolderList?.length === 0} loading={deleteBatch.loading}>删除</Button>
+                </Popconfirm>}
                 <Button type="primary" onClick={() => {
                     setBatchFolderVisible(false)
                 }}>完成</Button>
@@ -386,7 +402,7 @@ const Material = forwardRef(({ onAddFolder, onUpdateFolder, onDelFolder }: Props
                                     bodyStyle={{ padding: 0 }}
                                     className={`${style.content_col}`}
                                     cover={<div style={{ height: 120, padding: 0 }} className={style.content_cover}>
-                                        {batchFolderVisible && <div className={style.checkbox}><Checkbox value={item.id} disabled={!isPermission(item.createBy)} /></div>}
+                                        {batchFolderVisible && <div className={style.checkbox} onClick={(e) => { e.stopPropagation(); }}><Checkbox value={item.id} disabled={!isPermission(item.createBy)} /></div>}
                                         {item.materialType === 'video' && <div className={style.playr}>
                                             <img src={require('../../../../../public/image/play.png')} alt="" />
                                         </div>}

+ 163 - 158
src/pages/launchSystemV3/material/cloudNew/selectCloudNew.tsx

@@ -15,6 +15,7 @@ import UploadsTable from "./uploadsTable"
 import { DeleteOutlined, PlayCircleOutlined, SortAscendingOutlined } from "@ant-design/icons"
 import PlayVideo from "./playVideo"
 import { showFieldList } from "./const"
+import SelectFolder from "./selectFolder"
 
 
 const { Text, Paragraph } = Typography;
@@ -117,7 +118,7 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
         </Space>}
         open={visible}
         onCancel={onClose}
-        width={1200}
+        width={1400}
         footer={<div className={style.divFooter}>
             {checkedFolderList.length > 0 ? <>
                 <div className={style.selectedCloud}>
@@ -153,177 +154,181 @@ const SelectCloudNew: React.FC<CLOUDNEW.SelectCloudNewProps> = ({ visible, defau
                 className="cardResetCss buttonResetCss"
                 bordered
             >
-                <div className={style.material} style={{ height: '100%' }}>
-                    <div className={style.operates}>
-                        <div className={style.left_bts}>
-                            <Checkbox
-                                onChange={(e) => {
-                                    let newCheckedFolderList: any[] = JSON.parse(JSON.stringify(checkedFolderList))
-                                    const data: any[] = getMaterialDataList?.data?.records
+                <div className={style.cloudNew}>
+                    {/* 选择文件夹 */}
+                    <SelectFolder selectedKeys={queryParams?.folderId} onChange={(value) => { setQueryParams({ ...queryParams, folderId: value }) }} />
+                    <div className={style.material} style={{ height: '100%' }}>
+                        <div className={style.operates}>
+                            <div className={style.left_bts}>
+                                <Checkbox
+                                    onChange={(e) => {
+                                        let newCheckedFolderList: any[] = JSON.parse(JSON.stringify(checkedFolderList))
+                                        const data: any[] = getMaterialDataList?.data?.records
 
-                                    if (e.target.checked) { // 全选
-                                        const selectIds = newCheckedFolderList.map(item => item.id)
-                                        const remainData = data.filter(item => !selectIds.includes(item.id))
-                                        const remainDataLength = remainData.length
-                                        const remainNum = num - newCheckedFolderList.length
-                                        if (remainNum > remainDataLength) {
-                                            newCheckedFolderList.push(...data)
-                                        } else {
-                                            newCheckedFolderList.push(...remainData.splice(0, remainNum))
+                                        if (e.target.checked) { // 全选
+                                            const selectIds = newCheckedFolderList.map(item => item.id)
+                                            const remainData = data.filter(item => !selectIds.includes(item.id))
+                                            const remainDataLength = remainData.length
+                                            const remainNum = num - newCheckedFolderList.length
+                                            if (remainNum > remainDataLength) {
+                                                newCheckedFolderList.push(...data)
+                                            } else {
+                                                newCheckedFolderList.push(...remainData.splice(0, remainNum))
+                                            }
+                                            newCheckedFolderList = Array.from(new Set(newCheckedFolderList.map(item => JSON.stringify(item)))).map(item => JSON.parse(item));
+                                        } else { // 取消全选
+                                            const dataIds = data.map(item => item.id)
+                                            newCheckedFolderList = newCheckedFolderList.filter(i => !dataIds.includes(i.id))
                                         }
-                                        newCheckedFolderList = Array.from(new Set(newCheckedFolderList.map(item => JSON.stringify(item)))).map(item => JSON.parse(item));
-                                    } else { // 取消全选
-                                        const dataIds = data.map(item => item.id)
-                                        newCheckedFolderList = newCheckedFolderList.filter(i => !dataIds.includes(i.id))
-                                    }
-                                    setCheckedFolderList(newCheckedFolderList)
-                                }}
-                                disabled={checkedFolderList?.length >= num}
-                                indeterminate={indeterminateFolder}
-                                checked={checkFolderAll}
-                            >全选</Checkbox>
-                            <span>已选 <span style={{ color: '#1890FF' }}>{checkedFolderList?.length || 0}</span>/{num} 个素材</span>
-                            {checkedFolderList.length > 0 && <a style={{ color: 'red' }} onClick={() => setCheckedFolderList([])}>清除所有</a>}
-                            <Text>「排序-{showFieldList.find(item => item.value === sortData.sortField)?.label}-{sortData.sortType ? '正序' : '倒序'}」</Text>
-                        </div>
-                        <div className={style.left_bts}>
-                            <Popover
-                                content={<div style={{ width: 320 }}>
-                                    <Form
-                                        labelCol={{ span: 5 }}
-                                        labelAlign="left"
-                                        colon={false}
-                                    >
-                                        <Form.Item label={<strong>展示指标</strong>}>
-                                            <Select
-                                                placeholder="选择展示指标"
-                                                showSearch
-                                                filterOption={(input, option) =>
-                                                    (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                                                }
-                                                mode="multiple"
-                                                options={showFieldList}
-                                                value={showField}
-                                                onChange={(value) => {
-                                                    if (value.length > 6) {
-                                                        message.warn('最多只能选择6个指标')
-                                                        return
-                                                    }
-                                                    if (value.length < 1) {
-                                                        message.warn('最少选择1个指标')
-                                                        return
-                                                    }
-                                                    setShowField(value as any)
-                                                }}
-                                            />
-                                        </Form.Item>
-                                        <Form.Item label={<strong>排序</strong>}>
-                                            <Space>
+                                        setCheckedFolderList(newCheckedFolderList)
+                                    }}
+                                    disabled={checkedFolderList?.length >= num}
+                                    indeterminate={indeterminateFolder}
+                                    checked={checkFolderAll}
+                                >全选</Checkbox>
+                                <span>已选 <span style={{ color: '#1890FF' }}>{checkedFolderList?.length || 0}</span>/{num} 个素材</span>
+                                {checkedFolderList.length > 0 && <a style={{ color: 'red' }} onClick={() => setCheckedFolderList([])}>清除所有</a>}
+                                <Text>「排序-{showFieldList.find(item => item.value === sortData.sortField)?.label}-{sortData.sortType ? '正序' : '倒序'}」</Text>
+                            </div>
+                            <div className={style.left_bts}>
+                                <Popover
+                                    content={<div style={{ width: 320 }}>
+                                        <Form
+                                            labelCol={{ span: 5 }}
+                                            labelAlign="left"
+                                            colon={false}
+                                        >
+                                            <Form.Item label={<strong>展示指标</strong>}>
                                                 <Select
-                                                    style={{ width: 125 }}
-                                                    placeholder="选择排序指标"
+                                                    placeholder="选择展示指标"
                                                     showSearch
                                                     filterOption={(input, option) =>
                                                         (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
                                                     }
+                                                    mode="multiple"
                                                     options={showFieldList}
-                                                    value={sortData.sortField}
+                                                    value={showField}
                                                     onChange={(value) => {
-                                                        setSortData({ ...sortData, sortField: value as any })
+                                                        if (value.length > 6) {
+                                                            message.warn('最多只能选择6个指标')
+                                                            return
+                                                        }
+                                                        if (value.length < 1) {
+                                                            message.warn('最少选择1个指标')
+                                                            return
+                                                        }
+                                                        setShowField(value as any)
                                                     }}
                                                 />
-                                                <Radio.Group value={sortData.sortType} onChange={(e) => setSortData({ ...sortData, sortType: e.target.value })} buttonStyle="solid">
-                                                    <Radio.Button value={true}>正序</Radio.Button>
-                                                    <Radio.Button value={false}>倒序</Radio.Button>
-                                                </Radio.Group>
-                                            </Space>
-                                        </Form.Item>
-                                    </Form>
-                                </div>}
-                                trigger={['click']}
-                                title={<strong>自定义展示指标与排序</strong>}
-                                placement="bottomRight"
-                            >
-                                <Button icon={<SortAscendingOutlined />}>自定义展示指标与排序</Button>
-                            </Popover>
+                                            </Form.Item>
+                                            <Form.Item label={<strong>排序</strong>}>
+                                                <Space>
+                                                    <Select
+                                                        style={{ width: 125 }}
+                                                        placeholder="选择排序指标"
+                                                        showSearch
+                                                        filterOption={(input, option) =>
+                                                            (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                                                        }
+                                                        options={showFieldList}
+                                                        value={sortData.sortField}
+                                                        onChange={(value) => {
+                                                            setSortData({ ...sortData, sortField: value as any })
+                                                        }}
+                                                    />
+                                                    <Radio.Group value={sortData.sortType} onChange={(e) => setSortData({ ...sortData, sortType: e.target.value })} buttonStyle="solid">
+                                                        <Radio.Button value={true}>正序</Radio.Button>
+                                                        <Radio.Button value={false}>倒序</Radio.Button>
+                                                    </Radio.Group>
+                                                </Space>
+                                            </Form.Item>
+                                        </Form>
+                                    </div>}
+                                    trigger={['click']}
+                                    title={<strong>自定义展示指标与排序</strong>}
+                                    placement="bottomRight"
+                                >
+                                    <Button icon={<SortAscendingOutlined />}>自定义展示指标与排序</Button>
+                                </Popover>
+                            </div>
                         </div>
-                    </div>
-                    <div className={`${style.content} content_global`}>
-                        <Spin spinning={getMaterialDataList.loading}>
-                            <div className={style.content_scroll} ref={ref} {...dropAreaProps}>
-                                {isDragOver && <div className={`${style.placeholder} ${isDragOver ? style.dragOver : ''}`}><span>拖动文件到这里</span></div>}
-                                {getMaterialDataList?.data?.records?.length > 0 ? <Checkbox.Group value={checkedFolderList?.map(item => item.id)} style={{ width: '100%' }}>
-                                    <div className={style.content_scroll_div}>
-                                        {getMaterialDataList?.data?.records.map((item: any) => {
-                                            const isSelect = checkedFolderList?.map(item => item.id).includes(item.id)
-                                            const disabled = checkedFolderList.length >= num && !isSelect
-                                            return <div key={item.id} className={style.content_row} style={{ width: rowNum ? (1 / rowNum * 100) + '%' : 200 }}>
-                                                <Card
-                                                    hoverable
-                                                    bodyStyle={{ padding: 0 }}
-                                                    style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
-                                                    className={`${style.content_col}`}
-                                                    cover={<div style={{ height: 120, padding: 0 }} className={style.content_cover}>
-                                                        <div className={style.checkbox}><Checkbox disabled={disabled} value={item.id} onChange={(e) => onCheckboxChange(e.target.checked, item)} /></div>
-                                                        {item.material_type === 'video' && <div className={style.playr}>
-                                                            <PlayVideo videoUrl={item.oss_url}>{(onPlay) => <img onClick={(e) => {
-                                                                e.stopPropagation(); e.preventDefault()
-                                                                onPlay()
-                                                            }} src={require('../../../../../public/image/play.png')} alt="" />}</PlayVideo>
+                        <div className={`${style.content} content_global`}>
+                            <Spin spinning={getMaterialDataList.loading}>
+                                <div className={style.content_scroll} ref={ref} {...dropAreaProps}>
+                                    {isDragOver && <div className={`${style.placeholder} ${isDragOver ? style.dragOver : ''}`}><span>拖动文件到这里</span></div>}
+                                    {getMaterialDataList?.data?.records?.length > 0 ? <Checkbox.Group value={checkedFolderList?.map(item => item.id)} style={{ width: '100%' }}>
+                                        <div className={style.content_scroll_div}>
+                                            {getMaterialDataList?.data?.records.map((item: any) => {
+                                                const isSelect = checkedFolderList?.map(item => item.id).includes(item.id)
+                                                const disabled = checkedFolderList.length >= num && !isSelect
+                                                return <div key={item.id} className={style.content_row} style={{ width: rowNum ? (1 / rowNum * 100) + '%' : 200 }}>
+                                                    <Card
+                                                        hoverable
+                                                        bodyStyle={{ padding: 0 }}
+                                                        style={{ cursor: disabled ? 'not-allowed' : 'pointer' }}
+                                                        className={`${style.content_col}`}
+                                                        cover={<div style={{ height: 120, padding: 0 }} className={style.content_cover}>
+                                                            <div className={style.checkbox}><Checkbox disabled={disabled} value={item.id} onChange={(e) => onCheckboxChange(e.target.checked, item)} /></div>
+                                                            {item.material_type === 'video' && <div className={style.playr}>
+                                                                <PlayVideo videoUrl={item.oss_url}>{(onPlay) => <img onClick={(e) => {
+                                                                    e.stopPropagation(); e.preventDefault()
+                                                                    onPlay()
+                                                                }} src={require('../../../../../public/image/play.png')} alt="" />}</PlayVideo>
+                                                            </div>}
+                                                            <div className={style.file_info}>
+                                                                <div>{item.width}*{item.height}</div>
+                                                                {item.material_type === 'video' && <div>{formatSecondsToTime(Math.floor(item.video_duration))}</div>}
+                                                            </div>
+                                                            <img src={item.material_type === 'image' ? item.oss_url : getVideoImgUrl(item.oss_url)} className={style.coverImg} alt="" />
                                                         </div>}
-                                                        <div className={style.file_info}>
-                                                            <div>{item.width}*{item.height}</div>
-                                                            {item.material_type === 'video' && <div>{formatSecondsToTime(Math.floor(item.video_duration))}</div>}
+                                                        onClick={() => !disabled && onCheckboxChange(!isSelect, item)}
+                                                    >
+                                                        <div className={style.body}>
+                                                            <Text ellipsis strong style={{ flex: '1 0' }}>{item?.material_name}</Text>
+                                                            <Text style={{ fontSize: 12 }}>{formatBytes(item?.file_size)}</Text>
                                                         </div>
-                                                        <img src={item.material_type === 'image' ? item.oss_url : getVideoImgUrl(item.oss_url)} className={style.coverImg} alt="" />
-                                                    </div>}
-                                                    onClick={() => !disabled && onCheckboxChange(!isSelect, item)}
-                                                >
-                                                    <div className={style.body}>
-                                                        <Text ellipsis strong style={{ flex: '1 0' }}>{item?.material_name}</Text>
-                                                        <Text style={{ fontSize: 12 }}>{formatBytes(item?.file_size)}</Text>
-                                                    </div>
-                                                    <Divider style={{ margin: '0 0 4px 0' }} />
-                                                    <div style={{ padding: '0 10px 6px' }}>
-                                                        {showField.map(field => {
-                                                            switch (field) {
-                                                                case 'material.create_time':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>创建时间:{item?.create_time}</Paragraph>
-                                                                case 'material_data_day.cost':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>消耗:{(item?.cost === null || item?.cost === undefined) ? '--' : item?.cost}</Paragraph>
-                                                                case 'material_data_day.ctr':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>点击率:{(item?.ctr === null || item?.ctr === undefined) ? '--' : item?.ctr * 100 + '%'}</Paragraph>
-                                                                case 'material_data_day.conversions_rate':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>目标转化率:{(item?.conversions_rate === null || item?.conversions_rate === undefined) ? '--' : item?.conversions_rate * 100 + '%'}</Paragraph>
-                                                                case 'material_data_day.adgroup_count':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>广告关联数:{(item?.adgroup_count === null || item?.adgroup_count === undefined) ? '--' : item?.adgroup_count}</Paragraph>
-                                                                case 'material_data_day.dynamic_creative_count':
-                                                                    return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>创意关联数:{(item?.dynamic_creative_count === null || item?.dynamic_creative_count === undefined) ? '--' : item?.dynamic_creative_count}</Paragraph>
-                                                                default:
-                                                                    return null
-                                                            }
-                                                        })}
-                                                    </div>
-                                                </Card>
-                                            </div>
-                                        })}
-                                    </div>
-                                </Checkbox.Group> : <div style={{ height: '100%', width: '100%', alignContent: 'center' }}><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></div>}
-                            </div>
-                        </Spin>
-                    </div>
-                    <div className={style.fotter}>
-                        <Pagination
-                            size="small"
-                            total={getMaterialDataList?.data?.total || 0}
-                            showSizeChanger
-                            showQuickJumper
-                            pageSize={getMaterialDataList?.data?.size || 20}
-                            current={getMaterialDataList?.data?.current || 1}
-                            onChange={(page: number, pageSize: number) => {
-                                setQueryParams({ ...queryParams, pageNum: page, pageSize })
-                            }}
-                        />
+                                                        <Divider style={{ margin: '0 0 4px 0' }} />
+                                                        <div style={{ padding: '0 10px 6px' }}>
+                                                            {showField.map(field => {
+                                                                switch (field) {
+                                                                    case 'material.create_time':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>创建时间:{item?.create_time}</Paragraph>
+                                                                    case 'material_data_day.cost':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>消耗:{(item?.cost === null || item?.cost === undefined) ? '--' : item?.cost}</Paragraph>
+                                                                    case 'material_data_day.ctr':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>点击率:{(item?.ctr === null || item?.ctr === undefined) ? '--' : (item?.ctr * 100).toFixed(2) + '%'}</Paragraph>
+                                                                    case 'material_data_day.conversions_rate':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>目标转化率:{(item?.conversions_rate === null || item?.conversions_rate === undefined) ? '--' : (item?.conversions_rate * 100).toFixed(2) + '%'}</Paragraph>
+                                                                    case 'material_data_day.adgroup_count':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>广告关联数:{(item?.adgroup_count === null || item?.adgroup_count === undefined) ? '--' : item?.adgroup_count}</Paragraph>
+                                                                    case 'material_data_day.dynamic_creative_count':
+                                                                        return <Paragraph key={field} style={{ fontSize: 12, marginBottom: 1 }}>创意关联数:{(item?.dynamic_creative_count === null || item?.dynamic_creative_count === undefined) ? '--' : item?.dynamic_creative_count}</Paragraph>
+                                                                    default:
+                                                                        return null
+                                                                }
+                                                            })}
+                                                        </div>
+                                                    </Card>
+                                                </div>
+                                            })}
+                                        </div>
+                                    </Checkbox.Group> : <div style={{ height: '100%', width: '100%', alignContent: 'center' }}><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></div>}
+                                </div>
+                            </Spin>
+                        </div>
+                        <div className={style.fotter}>
+                            <Pagination
+                                size="small"
+                                total={getMaterialDataList?.data?.total || 0}
+                                showSizeChanger
+                                showQuickJumper
+                                pageSize={getMaterialDataList?.data?.size || 20}
+                                current={getMaterialDataList?.data?.current || 1}
+                                onChange={(page: number, pageSize: number) => {
+                                    setQueryParams({ ...queryParams, pageNum: page, pageSize })
+                                }}
+                            />
+                        </div>
                     </div>
                 </div>
             </Card>

+ 90 - 0
src/pages/launchSystemV3/material/cloudNew/selectFolder.tsx

@@ -0,0 +1,90 @@
+import { useAjax } from "@/Hook/useAjax"
+import { getFolderListApi } from "@/services/adqV3/cloudNew"
+import { DataNode, DirectoryTreeProps, EventDataNode } from "antd/lib/tree";
+import React, { useEffect, useState } from "react"
+import { updateTreeData } from "./const";
+import style from './index.less'
+import { Button, Empty, Spin, Tree } from "antd";
+
+interface Props {
+    selectedKeys?: number
+    onChange?: (selectedKeys?: number) => void
+}
+/**
+ * 文件夹
+ * @returns 
+ */
+const SelectFolder: React.FC<Props> = ({ selectedKeys, onChange }) => {
+
+    /******************************/
+    const [treeData, setTreeData] = useState<DataNode[]>([]);
+
+    const getFolderList = useAjax((params) => getFolderListApi(params))
+    /******************************/
+
+    useEffect(() => {
+        getFolder()
+    }, [])
+
+    const getFolder = () => {
+        getFolderList.run({}).then(res => {
+            setTreeData(() => res?.map((item: { folderName: any; id: any; createBy: number }) => ({
+                title: item.folderName,
+                value: item.id,
+                key: item.id,
+            })) || [])
+        })
+    }
+
+    // 下级目录
+    const handleUpdateFolder = (parentId: number) => {
+        return getFolderListApi({ parentId }).then(res => {
+            setTreeData(origin =>
+                updateTreeData(origin, parentId, res?.data?.map((item: { folderName: any; id: any; createBy: number }) => ({
+                    title: item.folderName,
+                    value: item.id,
+                    key: item.id,
+                })) || []),
+            );
+        })
+    }
+
+    // 选中文件
+    const onSelect: DirectoryTreeProps['onSelect'] = (keys, info) => {
+        console.log('Trigger Expand', keys, info);
+        onChange?.(keys?.length > 0 ? keys[0] : undefined as any)
+    };
+
+    return <div className={style.folder} style={{ width: 180 }}>
+        <div className={style.top}>
+            <Button
+                style={{ padding: 0, height: 'auto', width: 71, fontSize: 14 }}
+                onClick={() => {
+                    onChange?.()
+                }}
+                type="link"
+            >全部素材</Button>
+        </div>
+        <div className={style.bottom}>
+            <Spin spinning={getFolderList.loading}>
+                <Tree
+                    showIcon
+                    blockNode={true}
+                    selectedKeys={selectedKeys ? [selectedKeys] : undefined}
+                    loadData={(treeNode: EventDataNode<DataNode>) => {
+                        return new Promise<void>(async (resolve) => {
+                            console.log('Trigger Select', treeNode);
+                            await handleUpdateFolder(Number(treeNode.key))
+                            resolve()
+                        })
+                    }}
+                    onSelect={onSelect}
+                    treeData={treeData}
+                />
+                {!(treeData?.length > 0) && (getFolderList.loading ? <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: 200 }} ></div> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无文件夹" />)}
+            </Spin>
+        </div>
+    </div>
+}
+
+export default React.memo(SelectFolder)

+ 13 - 62
src/pages/launchSystemV3/material/cloudNew/selectSearch.tsx

@@ -1,11 +1,8 @@
-import { Button, Card, Col, DatePicker, Form, Input, InputNumber, Row, Select, Space, TreeSelect } from "antd"
-import React, { useEffect, useState } from "react"
+import { Button, Card, Col, DatePicker, Form, Input, InputNumber, Row, Select, Space } from "antd"
+import React, { useEffect } from "react"
 import { getUserAllApi } from "@/services/operating/account";
 import { useAjax } from "@/Hook/useAjax";
 import { SearchOutlined } from "@ant-design/icons";
-import { getFolderListApi } from "@/services/adqV3/cloudNew";
-import { DataNode } from "antd/lib/tree";
-import { updateTreeData } from "./const";
 import moment from "moment";
 
 interface Props {
@@ -17,39 +14,10 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
 
     /**********************************/
     const [form] = Form.useForm();
-    const [treeData, setTreeData] = useState<DataNode[]>([]);
 
     const getUserAll = useAjax(() => getUserAllApi())
-    const getFolderList = useAjax((params) => getFolderListApi(params))
     /**********************************/
 
-    useEffect(() => {
-        getFolder()
-    }, [])
-
-    const getFolder = () => {
-        getFolderList.run({}).then(res => {
-            setTreeData(() => res?.map((item: { folderName: any; id: any; createBy: number }) => ({
-                title: item.folderName,
-                value: item.id,
-                key: item.id,
-            })) || [])
-        })
-    }
-
-    // 下级目录
-    const handleUpdateFolder = (parentId: number) => {
-        return getFolderListApi({ parentId }).then(res => {
-            setTreeData(origin =>
-                updateTreeData(origin, parentId, res?.data?.map((item: { folderName: any; id: any; createBy: number }) => ({
-                    title: item.folderName,
-                    value: item.id,
-                    key: item.id,
-                })) || []),
-            );
-        })
-    }
-
     useEffect(() => {
         getUserAll.run()
     }, [])
@@ -88,23 +56,6 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                 <Col><Form.Item name={'materialName'}>
                     <Input style={{ width: 190 }} allowClear placeholder="请输入关键词" />
                 </Form.Item></Col>
-                <Col><Form.Item name={'folderId'}>
-                    <TreeSelect
-                        loading={getFolderList.loading}
-                        allowClear
-                        style={{ width: 130 }}
-                        dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-                        placeholder="请选择文件夹"
-                        loadData={({ value }) => {
-                            return new Promise<void>(async (resolve) => {
-                                await handleUpdateFolder(Number(value))
-                                resolve()
-                            })
-                        }}
-                        dropdownMatchSelectWidth={false}
-                        treeData={treeData}
-                    />
-                </Form.Item></Col>
                 <Col><Form.Item name={'designerIds'}>
                     <Select
                         placeholder="设计师"
@@ -131,17 +82,6 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                         options={getUserAll?.data?.map((item: { nickname: any; userId: any }) => ({ label: item.nickname, value: item.userId }))}
                     />
                 </Form.Item></Col>
-                <Col><Form.Item name={'useStatus'}>
-                    <Select
-                        placeholder="使用情况"
-                        filterOption={(input, option) =>
-                            ((option?.label ?? '') as any).toLowerCase().includes(input.toLowerCase())
-                        }
-                        style={{ minWidth: 120 }}
-                        allowClear
-                        options={[{ label: '未使用', value: 0 }, { label: '无消耗', value: 1 }, { label: '有消耗', value: 2 }]}
-                    />
-                </Form.Item></Col>
                 <Col><Form.Item name={'accountIds'}>
                     <Input.TextArea rows={1} style={{ width: 190 }} allowClear placeholder="广告账号(多个逗号、换行等隔开)" />
                 </Form.Item></Col>
@@ -157,6 +97,17 @@ const SelectSearch: React.FC<Props> = ({ onSearch }) => {
                 <Col><Form.Item name={'minCost'}>
                     <InputNumber style={{ width: 80 }} placeholder="最小消耗" />
                 </Form.Item></Col>
+                <Col><Form.Item name={'useStatus'}>
+                    <Select
+                        placeholder="使用情况"
+                        filterOption={(input, option) =>
+                            ((option?.label ?? '') as any).toLowerCase().includes(input.toLowerCase())
+                        }
+                        style={{ minWidth: 120 }}
+                        allowClear
+                        options={[{ label: '未使用', value: 0 }, { label: '无消耗', value: 1 }, { label: '有消耗', value: 2 }]}
+                    />
+                </Form.Item></Col>
                 <Col><Form.Item name={'uploadTime'}>
                     <DatePicker.RangePicker style={{ width: 260 }} placeholder={['上传时间开始', '上传时间结束']} />
                 </Form.Item></Col>

+ 12 - 0
src/services/adqV3/cloudNew.ts

@@ -150,6 +150,18 @@ export async function delMaterialApi(id: number) {
     })
 }
 
+/**
+ * 批量删除
+ * @param data 
+ * @returns 
+ */
+export async function deleteBatchApi(data: number[]) {
+    return request(api + `/material/material/deleteBatch`, {
+        method: 'DELETE',
+        data
+    })
+}
+
 /**
  * 移动素材
  * @param param0