shenwu vor 2 Jahren
Ursprung
Commit
6a13ad53d9

+ 71 - 0
src/components/DebounceSelect/index.tsx

@@ -0,0 +1,71 @@
+import { Select, Spin } from 'antd';
+import type { SelectProps } from 'antd/es/select';
+import debounce from 'lodash/debounce';
+import React, { useMemo, useRef, useState } from 'react';
+
+export interface DebounceSelectProps<ValueType = any>
+    extends Omit<SelectProps<ValueType | ValueType[]>, 'options' | 'children'> {
+    fetchOptions: (search: string) => Promise<ValueType[]>;
+    debounceTimeout?: number;
+}
+
+function DebounceSelect<
+    ValueType extends { key?: string; label: React.ReactNode; value: string | number } = any,
+    >({ fetchOptions, debounceTimeout = 800, ...props }: DebounceSelectProps<ValueType>) {
+    const [fetching, setFetching] = useState(false);
+    const [options, setOptions] = useState<ValueType[]>([]);
+    const fetchRef = useRef(0);
+
+    const debounceFetcher = useMemo(() => {
+        const loadOptions = (value: string) => {
+            fetchRef.current += 1;
+            const fetchId = fetchRef.current;
+            setOptions([]);
+            setFetching(true);
+
+            fetchOptions(value).then(newOptions => {
+                if (fetchId !== fetchRef.current) {
+                    // for fetch callback order
+                    return;
+                }
+
+                setOptions(newOptions);
+                setFetching(false);
+            });
+        };
+
+        return debounce(loadOptions, debounceTimeout);
+    }, [fetchOptions, debounceTimeout]);
+
+    return (
+        <Select
+            labelInValue
+            filterOption={false}
+            onSearch={debounceFetcher}
+            notFoundContent={fetching ? <Spin size="small" /> : null}
+            {...props}
+            options={options}
+        />
+    );
+}
+interface UserValue {
+    label: string;
+    value: string;
+}
+
+async function fetchUserList(username: string): Promise<UserValue[]> {
+    console.log('fetching user', username);
+
+    return fetch('https://randomuser.me/api/?results=5')
+        .then(response => response.json())
+        .then(body =>
+            body.results.map(
+                (user: { name: { first: string; last: string }; login: { username: string } }) => ({
+                    label: `${user.name.first} ${user.name.last}`,
+                    value: user.login.username,
+                }),
+            ),
+        );
+}
+
+export {DebounceSelect,fetchUserList}

+ 0 - 1
src/components/FileBoxAD/index.tsx

@@ -185,7 +185,6 @@ function FlieBox(props: Props) {
         }
     }, [folderId, moveId, mediaType])
     
-    console.log('111111111111', get_folder_tree?.data);
     
 
     return <div style={{ display: 'flex', flexFlow: 'row' }}>

+ 2 - 2
src/pages/launchSystemNew/components/selectCloud/index.tsx

@@ -9,7 +9,7 @@ interface Props {
     visible?: boolean,
     onChange?: (content: string[]) => void,
     onClose?: () => void,
-    sliderImgContent?: { url: string, width?: number, height?: number }[]
+    sliderImgContent?: { url: string, width?: number, height?: number }[],
 }
 /**
  * 选择素材
@@ -19,7 +19,7 @@ const SelectCloud: React.FC<Props> = (props) => {
 
     /**================================**/
     const { visible, onChange, onClose, sliderImgContent } = props
-    const { state, set, getList } = useModel('useLaunchAdq.useBdMediaPup')
+    const { state, set, getList ,init} = useModel('useLaunchAdq.useBdMediaPup')
     const { mediaType, belongUser, parentId, selectItem, num } = state
     /**================================**/
 

+ 20 - 1
src/pages/launchSystemNew/launchManage/localAd/creative/index.less

@@ -35,6 +35,11 @@
         flex-flow: column;
         font-size: 10px;
         cursor: pointer;
+        max-height: 150px;
+        margin-bottom:0;
+        img{
+            height: 100%;
+        }
     }
 }
 
@@ -44,7 +49,7 @@
     height:auto;
     justify-content: flex-start;
     >p{
-        width: 33%;
+        width: 150px;
         background-color: #f5f7fa;
         height: 150px;
         display: flex;
@@ -54,3 +59,17 @@
         margin: 0;
     }
 }
+.crt{
+    display: inline-flex;
+    align-items: center;
+    width: auto;
+    margin-left: 8px;
+    padding: 1px 4px;
+    height: 16px;
+    border-radius: 3px;
+    font-size: 12px;
+    color: #fff;
+    border: 1px solid #296bef;
+    background-color: #296bef;
+    line-height: normal;
+}

+ 242 - 36
src/pages/launchSystemNew/launchManage/localAd/creative/modal.tsx

@@ -1,14 +1,17 @@
 import React, { useCallback, useEffect, useMemo, useState } from 'react'
-import { Modal, Form, Input, Divider, Select, Radio,  Switch, Spin } from 'antd'
+import { Modal, Form, Input, Divider, Select, Radio, Switch, Spin, List } from 'antd'
 import { SiteSetEnum, PromotedObjectType } from '@/services/launchAdq/enum'
 import { ModalConfig } from '.'
 import styles from './index.less'
 import { outAdcreativeTemplateIdFun } from '../adenum';
 import { useAjax } from '@/Hook/useAjax'
-import { get_adcreative_template, get_adcreative_template_list } from '@/services/launchAdq/global'
+import { getText, get_adcreative_template, get_adcreative_template_list } from '@/services/launchAdq/global'
 import { AdcreativeTemplate, AdcreativeTemplateList } from '@/services/launchAdq'
 import { mySet } from '@/utils/arrFn'
 import SelectCloud from '@/pages/launchSystemNew/components/selectCloud'
+import { useModel } from '@/.umi/plugin-model/useModel'
+import { DebounceSelect, fetchUserList } from '@/components/DebounceSelect'
+import e from '@umijs/deps/compiled/express'
 interface Props {
     title?: string,
     visible: boolean,
@@ -19,13 +22,17 @@ interface Props {
 /**创意模板*/
 function CreativeModal(props: Props) {
     let { visible, title, confirmLoading, PupFn, callback } = props
+    const { init } = useModel('useLaunchAdq.useBdMediaPup')
     // 请求
     const getAdcreativeTemplate = useAjax((params) => get_adcreative_template(params))
     const getAdcreativeTemplateList = useAjax((params) => get_adcreative_template_list(params))
+    const getTextLsit = useAjax((params) => getText(params))
     // 变量
     const [adcreative_template, set_adcreative_template] = useState<AdcreativeTemplate>()
     const [adcreative_template_list, set_adcreative_template_list] = useState<AdcreativeTemplateList[]>([])
-    const [selectImgVisible,set_selectImgVisible] = useState(true)
+    const [selectImgVisible, set_selectImgVisible] = useState(false)
+    const [descriptionShow, setdescriptionshow] = useState(false)
+    const [titleShow, settitleshow] = useState(false)
     const [form] = Form.useForm();
     const [pupState, setPupState] = useState({
         kp_show: false,
@@ -34,6 +41,12 @@ function CreativeModal(props: Props) {
         bq_show: false,
         sp_show: false
     })
+    const [materialConfig, setMaterialConfig] = useState<{ adcreativeTemplateId?: number, type: string, cloudSize: { relation: string, width: number, height: number }[], list: any[], max: number }>({
+        type: '',//类型
+        cloudSize: [],//素材搜索条件
+        list: [],//素材
+        max: 1,//素材数量
+    })//素材配置
     const [conversionList, setConversionList] = useState<any>(null)
     let pageType = Form.useWatch('pageType', form)
     let adcreativeTemplateId = Form.useWatch('adcreativeTemplateId', form)
@@ -43,16 +56,62 @@ function CreativeModal(props: Props) {
     let adcreativeElementsType = Form.useWatch('adcreativeElementsType', form)
     let dataShow = Form.useWatch('dataShow', form)
     let conversionDataType = Form.useWatch('conversionDataType', form)
+    let titles = Form.useWatch('title', form)
+    let description = Form.useWatch('description', form)
 
     // 确定事件
     const handleOk = useCallback(() => {
         form.validateFields().then(values => {
+            console.log('values=>1', values)
             let newValues = JSON.parse(JSON.stringify(values))
-            console.log(newValues)
+            for (let key in newValues) {
+                switch (key) {
+                    case 'image'://图素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            image: materialConfig.list[0].url,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'video'://视频素材
+                        newValues.adcreativeElements = {
+                            ...newValues.adcreativeElements,
+                            video: materialConfig.list[0].url,
+                        }
+                        delete newValues[key]
+                        break;
+                    case 'image_list'://图素材
+                        // newValues.adcreativeElements = {
+                        //     video: materialConfig.list[0].url,
+                        //     description: newValues.description,
+                        // }
+                        // delete newValues[key]
+                        break;
+                    case 'short_video1'://视频素材
+                        // newValues.adcreativeElements = {
+                        //     video: materialConfig.list[0].url,
+                        //     description: newValues.description,
+                        // }
+                        // delete newValues[key]
+                        break;
+                    case 'description'://文案
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, description: newValues.description }
+                        break;
+                    case 'title'://文案
+                        newValues.adcreativeElements = { ...newValues.adcreativeElements, title: newValues.title }
+                        break;
+                }
+            }
+            delete newValues.description //删除外层文案
+            delete newValues.title //删除外层文案
+            delete newValues.adcreativeElementsType //删除创意形式
+            delete newValues.dataShow //删除数据开关
+            delete newValues.actionBtn //删除行动开关
+            console.log('newValues=>2', newValues)
             // callback(newValues)
         })
         // PupFn({ visible: false })
-    }, [form])
+    }, [form, materialConfig])
     // 获取创意形式列表
     useEffect(() => {
         if (siteSet?.length > 0 && promotedObjectType) {
@@ -63,7 +122,7 @@ function CreativeModal(props: Props) {
             }).then(res => {
                 let newArr: any = []
                 // 过滤掉相同的和即将下线的
-                Object.values(res).forEach((arr: any) => {
+                Object.values(res)?.forEach((arr: any) => {
                     Array.isArray(arr) && arr?.forEach((item: any) => {
                         if (newArr.length > 0) {
                             if (outAdcreativeTemplateIdFun(item.adcreativeTemplateId) && newArr.every((i: { adcreativeTemplateId: any }) => i.adcreativeTemplateId !== item.adcreativeTemplateId)) {
@@ -98,7 +157,9 @@ function CreativeModal(props: Props) {
                     promotedObjectType,
                     adcreativeTemplateId
                 }).then(res => {
-                    set_adcreative_template(res[0])
+                    if (res?.length > 0) {
+                        set_adcreative_template(res[0])
+                    }
                 })
             }
         }
@@ -180,6 +241,33 @@ function CreativeModal(props: Props) {
             form.setFieldsValue(values)
         }
     }, [adcreative_template])
+    // 版位改变清空数据
+    useEffect(() => {
+        if (materialConfig.adcreativeTemplateId && adcreativeTemplateId !== materialConfig.adcreativeTemplateId) {
+            setMaterialConfig({ ...materialConfig, adcreativeTemplateId: undefined, list: [] })
+        }
+    }, [adcreativeTemplateId, materialConfig])
+    // 文案助手
+    const textList = useCallback((arg: { maxTextLength: number, keyword?: string }) => {
+        let { maxTextLength, keyword } = arg
+        getTextLsit.run({ keyword: keyword || titles || description, maxTextLength })
+    }, [titles, description])
+    // 监听点击取消文案助手弹窗
+    useEffect(() => {
+        let modal = document.querySelector('.myModal')
+        let onBiurdescription = (e: any) => {
+            let d = document.querySelector('.my_description')
+            if (!d?.contains(e.target)) {
+                setdescriptionshow(false)
+                settitleshow(false)
+            }
+        }
+        modal?.addEventListener('click', onBiurdescription)
+        return () => {
+            modal?.removeEventListener('click', onBiurdescription)
+        }
+
+    }, [])
     return <Modal
         visible={visible}
         title={title + '创意'}
@@ -187,6 +275,7 @@ function CreativeModal(props: Props) {
         onOk={handleOk}
         width={1200}
         confirmLoading={confirmLoading}
+        className='myModal'
     >
         <Form
             form={form}
@@ -264,34 +353,83 @@ function CreativeModal(props: Props) {
                         {/* 优先展示视频或图片 */}
                         {
                             adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'image_list' || item.name === 'short_video1' || item.name === 'video' || item.name === 'image').map(item => {
-                                return <Form.Item label={<strong>{item.description}</strong>} name={item.name} rules={[{ required: true, message: '请选择素材!' }]}>
+                                return <Form.Item label={<strong>{item.description}</strong>} rules={[{ required: true, message: '请选择素材!' }]} key={item.name} name={item.name}>
+                                    {/* 视频 */}
                                     {
-                                       ( item.name === 'short_video1'||item.name === 'video' )&& <div className={`${styles.box} ${styles.video}`}>
+                                        (item.name === 'short_video1' || item.name === 'video') && <div className={`${styles.box} ${styles.video}`} onClick={() => {
+                                            init({ mediaType: 'VIDEO', cloudSize: [[{ relation: '=', width: item.restriction.videoRestriction.minWidth, height: item.restriction.videoRestriction.minHeight }]] })
+                                            setTimeout(() => {
+                                                set_selectImgVisible(true)
+                                                setMaterialConfig({
+                                                    ...materialConfig,
+                                                    type: item.name,
+                                                    max: 1,
+                                                    adcreativeTemplateId
+                                                })
+                                            }, 100)
+                                        }}>
                                             <p>
-                                                <span>{`推荐尺寸(${item.restriction.videoRestriction.minWidth} x ${item.restriction.videoRestriction.minHeight})`}</span>
-                                                <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
+                                                {
+                                                    materialConfig?.list[0] ? <video src={materialConfig?.list[0].url} /> : <>
+                                                        <span>{`推荐尺寸(${item.restriction.videoRestriction.minWidth} x ${item.restriction.videoRestriction.minHeight})`}</span>
+                                                        <span>{`${item.restriction.videoRestriction.fileFormat?.map(str => str?.replace('MEDIA_TYPE_', ''))};< ${item.restriction.videoRestriction.fileSize / 1024}M;时长 ≥ ${item.restriction.videoRestriction.minDuration}s,≤ ${item.restriction.videoRestriction.maxDuration}s,必须带有声音`}</span>
+                                                    </>
+                                                }
                                             </p>
                                         </div>
                                     }
+                                    {/* 单图 */}
                                     {
-                                        item.name === 'image' && <div className={`${styles.box} ${styles.image}`}>
-                                        <p>
-                                            <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
-                                            <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
-                                        </p>
-                                    </div>
+                                        item.name === 'image' && <div className={`${styles.box} ${styles.image}`} onClick={() => {
+                                            init({ mediaType: 'IMG', cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]] })
+                                            setTimeout(() => {
+                                                set_selectImgVisible(true)
+                                                setMaterialConfig({
+                                                    ...materialConfig,
+                                                    type: item.name,
+                                                    max: 1,
+                                                    adcreativeTemplateId
+                                                })
+                                            }, 100)
+
+                                        }}>
+                                            <p>
+                                                {materialConfig?.list[0] ? <img src={materialConfig?.list[0].url} /> : <>
+                                                    <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                                    <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                                </>
+                                                }
+                                            </p>
+                                        </div>
                                     }
-                                     {
-                                        item.name === 'image_list' && <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ?styles.image_list : styles.image}`}>
+                                    {/* 多图 */}
+                                    {
+                                        item.name === 'image_list' && <div className={`${styles.box} ${item.arrayProperty.maxNumber >= 3 ? styles.image_list : styles.image}`} onClick={() => {
+                                            init({ mediaType: 'IMG', num: item.arrayProperty.maxNumber, cloudSize: [[{ relation: '=', width: item.restriction.imageRestriction.width, height: item.restriction.imageRestriction.height }]] })
+                                            setTimeout(() => {
+                                                set_selectImgVisible(true)
+                                                setMaterialConfig({
+                                                    ...materialConfig,
+                                                    type: item.name,
+                                                    max: item.arrayProperty.maxNumber,
+                                                    adcreativeTemplateId
+                                                })
+                                            }, 100)
+                                        }}>
                                             {
-                                                Array(item.arrayProperty.maxNumber).fill('').map((arr,index)=>{
+                                                Array(item.arrayProperty.maxNumber).fill('').map((arr, index) => {
                                                     return <p key={index}>
-                                                    <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
-                                                    <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
-                                                </p>
+                                                        {
+                                                            materialConfig?.list[index] ? <img src={materialConfig?.list[index].url} /> : <>
+                                                                <span>{`推荐尺寸(${item.restriction.imageRestriction.width} x ${item.restriction.imageRestriction.height})`}</span>
+                                                                <span>{`${item.restriction.imageRestriction.fileFormat?.map(str => str?.replace('IMAGE_TYPE_', ''))};小于 ${item.restriction.imageRestriction.fileSize}KB`}</span>
+                                                            </>
+                                                        }
+
+                                                    </p>
                                                 })
                                             }
-                                    </div>
+                                        </div>
                                     }
                                 </Form.Item>
                             })
@@ -299,20 +437,77 @@ function CreativeModal(props: Props) {
                         {/* 标题 */}
                         {
                             adcreative_template?.adcreativeElements?.filter(item => item.name === 'title').map(item => {
-                                return <Form.Item label={<strong>{item.description}(选填)</strong>} name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
-                                    <Input placeholder={'请输入' + item.description} style={{ width: 500 }} />
-                                </Form.Item>
+                                return <div key={item.fieldType}>
+                                    <Form.Item label={<strong>{item.description}(选填)</strong>} className={'my_description'} >
+                                        <Form.Item name={item.name} rules={[{ pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]} noStyle>
+                                            <Input
+                                                placeholder={'请输入' + item.description}
+                                                style={{ width: 500 }}
+                                                onFocus={() => {
+                                                    settitleshow(true)
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength })
+                                                }}
+                                                onChange={(e) => {
+                                                    let value = e.target.value
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
+                                                }}
+                                            />
+                                        </Form.Item>
+                                        <span>{`${titles?.length??0}/${item.restriction.textRestriction.maxLength}`}</span>
+                                        {
+                                            titleShow && <List
+                                                loading={getTextLsit?.loading}
+                                                size="small"
+                                                style={{ maxHeight: 300, overflowX: 'auto' }}
+                                                bordered
+                                                dataSource={getTextLsit?.data?.returnTexts}
+                                                renderItem={(item: any) => <List.Item onClick={() => {
+                                                    form.setFieldsValue({ title: item.text })
+                                                    settitleshow(false)
+                                                }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
+                                            />
+                                        }
+                                    </Form.Item>
+                                </div>
                             })
                         }
                         {//过滤了不必传和品牌名称,品牌标识图(外部传)短视频结构(组装使用)
-                            // adcreative_template?.adcreativeElements?.filter(item => item.required && item.name !== 'brand_name' && item.name !== 'brand_img' && item.name !== 'short_video_struct' && item.name !== 'image_list' && item.name !== 'short_video1' && item.name !== 'video' ).map(item => {
                             adcreative_template?.adcreativeElements?.filter(item => item.required && item.name === 'description').map(item => {
-                                return <Form.Item label={<strong>{item.description}</strong>} name={item.name} rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
-                                    <Input placeholder={'请输入' + item.description} style={{ width: 500 }} />
-                                </Form.Item>
+                                return <div key={item.fieldType}>
+                                    <Form.Item label={<strong>{item.description}</strong>} className={'my_description'}>
+                                        <Form.Item name={item.name} noStyle rules={[{ required: true, pattern: RegExp(item.restriction.textRestriction.textPattern), message: '请输入正确的' + item.description }]}>
+                                            <Input
+                                                placeholder={'请输入' + item.description}
+                                                style={{ width: 500 }}
+                                                onFocus={() => {
+                                                    setdescriptionshow(true)
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength })
+                                                }}
+                                                onChange={(e) => {
+                                                    let value = e.target.value
+                                                    textList({ maxTextLength: item.restriction.textRestriction.maxLength, keyword: value })
+                                                }}
+                                                allowClear
+                                            />
+                                        </Form.Item>
+                                        <span>{`${description?.length??0}/${item.restriction.textRestriction.maxLength}`}</span>
+                                        {
+                                            descriptionShow && <List
+                                                loading={getTextLsit?.loading}
+                                                size="small"
+                                                style={{ maxHeight: 300, overflowX: 'auto' }}
+                                                bordered
+                                                dataSource={getTextLsit?.data?.returnTexts}
+                                                renderItem={(item: any) => <List.Item onClick={(e: any) => {
+                                                    form.setFieldsValue({ description: item.text })
+                                                    setdescriptionshow(false)
+                                                }}><span >{item.text}{item.tag && <span className={styles.crt}>{'CTR 高'}</span>}</span></List.Item>}
+                                            />
+                                        }
+                                    </Form.Item>
+                                </div>
                             })
                         }
-
                         {/* ============================================================落地页============================================================= */}
                         <Form.Item label={<strong>落地页</strong>} name='pageType'>
                             <Radio.Group>
@@ -423,10 +618,21 @@ function CreativeModal(props: Props) {
             }
         </Form>
         {/* //sliderImgContent={sliderImgContent}  */}
-         {/* 选择素材 */}
-         {selectImgVisible && <SelectCloud visible={selectImgVisible} onClose={() => set_selectImgVisible(false)} onChange={(content)=>{
-             console.log(content)
-         }} />}
+        {/* 选择素材 */}
+        {
+            selectImgVisible && <SelectCloud
+                visible={selectImgVisible}
+                onClose={() => set_selectImgVisible(false)}
+                sliderImgContent={materialConfig.list}
+                onChange={(content) => {
+                    if (content.length > 0) {
+                        form.setFieldsValue({ [materialConfig.type]: materialConfig.type })
+                    }
+                    setMaterialConfig({ ...materialConfig, list: content })
+                    set_selectImgVisible(false)
+                    console.log(content)
+                }} />
+        }
     </Modal >
 }
 export default CreativeModal

+ 14 - 1
src/services/launchAdq/global.ts

@@ -48,4 +48,17 @@ export async function getTagsList(params:any){
         method:'POST',
         data:params
     })
-}
+}
+/**
+ * 文案助手
+ * */
+export async function getText(params:{
+    maxTextLength:number,
+    adAccountId:number,
+}) {
+    return request(api+`/adq/launch/tools/creative/tools/text`,{
+        method:'GET',
+        params
+    })
+    
+}