纯列表版效果展示:

① 初始无值,展示为唤醒按钮+文案外链

②点击按钮唤醒弹窗(简易版示意图)

③配置后

可编辑表格组件文档:

https://procomponents.ant.design/components/editable-table

纯列表组件代码:

表单引用:

// antd-pro的高级表单组件
import SchemaForm from '@/components/SchemaForm';
import AssetsTable from './AssetsTable'; --------------------------------------- <SchemaForm<API.AssetsProps>
formRef={formRef}
dataSource={dataSource.map((item: any) => {
if (item.id === 'event_asset') {
return {
...item,
required: '请配置事件资产',
fieldProps: { ...item.fieldProps, fetchListApi },
renderFormItem: (schema: any) => <AssetsTable {...schema.fieldProps} />,
formItemProps: {
rules: [
{
required: true,
validator(rule: any, value: any[]) {
if (value && value.length) {
if (value.length !== accounts?.length) {
return Promise.reject(new Error('请为全部账户配置资产事件'));
}
if (value.find((itemDeep: any) => !itemDeep.deep_bid_type)) {
return Promise.reject(new Error('请为全部账户配置深度出价方式'));
}
return Promise.resolve();
}
return Promise.resolve();
},
},
],
},
};
}
return item;
})}
submitter={false}
autoFocusFirstInput={false}
onValuesChange={(changedFields: any, allFields: any) => {
// 表单值改变时的处理逻辑
}}
/>

  

组件代码:

import { useEffect, useState } from 'react';
import { Modal, Button, Input, message } from 'antd';
import { isEmpty } from 'lodash';
import type { ProColumns } from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
import { fetchAssetsList } from './services'; const { Search } = Input; type AssetsProps = {
value?: any[];
onChange?: (value?: any[]) => void;
/** 列表接口地址 */
fetchListApi?: string;
}; /** 弹窗 */
const AssetsTable: React.FC<AssetsProps> = (props) => {
const { value, onChange, fetchListApi } = props;
const [data, setData] = useState<API.AssetsProps[]>(value || []); // 存储选中的数据
const [visible, setVisible] = useState<boolean>(false);
const [dataSource, setDataSource] = useState<API.AssetsProps[]>([]); // 列表数据
const [tableColumns, setTableColumns] = useState<ProColumns[]>([]);
const [tableParams, setTableParams] = useState<any>();
const [tableLoading, setTableLoading] = useState<boolean>(false);
const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
const [keys, setKeys] = useState<(string | number)[]>([]); const handleOk = () => {
if (onChange) { onChange(data); setVisible(false);}
}; const fetchList = async () => {
setTableLoading(true);
if (fetchListApi) {
// 根据资产类型+投放账号调用头条已有的资产作为选择值
try {
const res: any = await fetchAssetsList(fetchListApi, tableParams);
if (res.result) {
setTableColumns([]);
const { tableHeaderList = [], tableList = [] } = res.result;
// 当有存储值时,覆盖掉接口返回的对应数据
if (data && data.length) {
const initObj = data.find((item: any) => item.account_id === id);
const newList = tableList.map((item: any) => {
if (initObj && initObj.id && item.id === initObj.id) {
return initObj;
}
return item;
});
setDataSource(newList);
setEditableRowKeys(newList?.map((item: any) => item.id));
} else {
setDataSource(tableList);
setEditableRowKeys(tableList?.map((item: any) => item.id));
}
// 深度优化目标下拉单选
setTableColumns([
...tableHeaderList.map((item: any) => {
if (item.dataIndex === 'deep_external_action') {
return {
...item,
width: 200,
valueType: 'select',
valueEnum: (row: any) => {
const optionList = row?.deep_goals
?.filter((itemF: any) => itemF.optimization_name)
.map((itemO: any) => {
return {
label: itemO.optimization_name,
value: itemO.deep_external_action,
};
});
const valueEnumObj = {};
optionList?.forEach((items: any) => {
valueEnumObj[items.value] = { text: items.label };
});
return valueEnumObj;
},
};
}
// 深度出价方式需要动态获取
if (item.dataIndex === 'deep_bid_type') {
return {
...item,
width: 200,
valueType: 'select',
valueEnum: (row: any) => {
let deepList: any[] = [];
const hasChoose = row?.deep_goals?.find(
(el: any) => el.deep_external_action === row.deep_external_action,
);
if (hasChoose) {
deepList =
row?.deep_goals.find(
(el: any) => el.deep_external_action === row.deep_external_action,
)?.deep_bid_type || [];
} else {
deepList = row?.default_deep_bid_type || [];
}
const optionList = deepList?.map((itemO: any) => {
return {
label: itemO.name,
value: itemO.id,
};
});
const valueEnumObj = {};
optionList?.forEach((items: any) => {
valueEnumObj[items.value] = { text: items.label };
});
return valueEnumObj;
},
};
}
return { ...item, editable: false };
}),
]);
}
setTableLoading(false);
} catch (error) {
//
}
}
}; // 关键词搜索
useEffect(() => {
if (!isEmpty(tableParams)) fetchList();
}, [tableParams]); useEffect(() => {
setData(dataSource || []);
}, [dataSource]); useEffect(() => {
if (visible) {
fetchList();
// 更新data
if (value && Array.isArray(value) && value.length) {
setData(value);
}
}
}, [visible]); useEffect(() => {
// 更新data
if (value && Array.isArray(value) && value.length) {
setData(value);
}
}, [value]); return (
<>
<div>
<Button onClick={() => setVisible(true)}>
{data && data.length ? '已' : ''}选择事件资产{data && data.length ? ',点击配置' : ''}
</Button>
</div>
<Modal width={1500} visible={visible} onCancel={() => setVisible(false)} onOk={handleOk}>
<div>
<Search
addonBefore="资产名称"
placeholder="请输入关键词搜索"
allowClear
onSearch={async (valueSearch: string) =>
setTableParams({ ...tableParams, asset_name: valueSearch })
}
style={{ width: 300, marginBottom: '8px' }}
/>
<EditableProTable
rowKey="id"
loading={tableLoading}
bordered
request={async () => ({
data: dataSource,
total: dataSource.length,
success: true,
})}
tableAlertRender={false}
value={dataSource}
onChange={(valueNew: any[]) => {
const newTableData = valueNew.map((item: any, index: number) => {
// 深度优化目标的值改变时,清空本条数据的深度出价方式的值
if (item.id === dataSource[index].id) {
if (item.deep_external_action !== dataSource[index].deep_external_action) {
return { ...item, deep_bid_type: undefined };
}
return item;
}
return item;
});
setDataSource(newTableData);
}}
controlled
recordCreatorProps={false}
editable={{
type: 'multiple',
editableKeys,
actionRender: undefined,
onChange: setEditableRowKeys,
}}
scroll={{ y: 320, x: 'max-content' }}
columns={tableColumns}
tableRender={undefined}
pagination={false}
rowSelection={{
type: 'radio',
selectedRowKeys: keys,
onChange: (selectedRowKeys: any, selectedRows: any) => {
// 存储选中数据逻辑
},
}}
/>
{dataSource && dataSource.length ? <p>共 {dataSource.length} 条</p> : null}
</div>
</Modal>
</>
);
}; export default AssetsTable;

  

--------------------------------------以上代码可满足按钮唤醒弹窗并对列表数据进行行内修改的需求-------------------------------------

完整版需求效果展示:

其实就是多了左侧账号栏,要求给左侧每个账号进行配置,右侧展示可选列表,单项选择,可配置内容,其中选中项必须配置出价方式;

点击确定时校验是否满足要求,否则弹出提示;

重新点开弹窗时也要保留上次选择与配置的内容。

具体代码:

import { useEffect, useState, useRef, useContext } from 'react';
import { Modal, Button, Input, message } from 'antd';
import { isEmpty } from 'lodash';
import ScrollList from '@/components/ScrollList';
import type { ProColumns } from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
import { fetchAssetsList } from './services';
import SmartCreationContext from '../../context';
import styles from './Assets.less'; const { Search } = Input; type AssetsProps = {
value?: any[];
onChange?: (value?: any[]) => void;
/** 事件资产列表接口地址 */
fetchListApi?: string;
}; /** 事件资产弹窗 */
const AssetsTable: React.FC<AssetsProps> = (props) => {
const { value, onChange, fetchListApi } = props;
const { dependentData, values } = useContext(SmartCreationContext);
const { accounts = [] } = dependentData || {};
const { create_rules } = values || {};
const adsRef = useRef<any>();
const [data, setData] = useState<API.AssetsProps[]>(value || []); // 存储选中的数据
const [visible, setVisible] = useState<boolean>(false);
const [dataSource, setDataSource] = useState<API.AssetsProps[]>([]); // 列表数据
const [tableColumns, setTableColumns] = useState<ProColumns[]>([]);
const [tableParams, setTableParams] = useState<any>();
const [tableLoading, setTableLoading] = useState<boolean>(false);
const [targetAccount, setTargetAccount] = useState<any>('');
const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
const [keys, setKeys] = useState<(string | number)[]>([]); const handleOk = () => {
if (onChange) {
if (data.length === accounts.length) {
if (data?.find((itemDeep: any) => !itemDeep.deep_bid_type)) {
message.error('请为全部账户配置深度出价方式');
return;
}
onChange(data);
setVisible(false);
} else {
message.error('请为全部账户配置资产事件');
}
}
}; const fetchList = async (id: string) => {
setTargetAccount(id);
setTableLoading(true);
const trace_events = JSON.parse(sessionStorage.getItem('ASSETS_FORM') || '');
if (fetchListApi) {
// 根据账号调用已有的资产作为选择值
try {
const res: any = await fetchAssetsList(fetchListApi, {
account_id: id, // 账号
...tableParams,
});
if (res.result) {
setTableColumns([]);
const { tableHeaderList = [], tableList = [] } = res.result;
const dataTable = tableList.map((item: any) => {
return { ...item, account_id: id };
});
// 当有存储值时,覆盖掉接口返回的对应数据
if (data && data.length) {
const initObj = data.find((item: any) => item.account_id === id);
const newList = dataTable.map((item: any) => {
if (initObj && initObj.id && item.id === initObj.id) {
return initObj;
}
return item;
});
setDataSource(newList);
setEditableRowKeys(newList?.map((item: any) => item.id));
} else {
setDataSource(dataTable);
setEditableRowKeys(dataTable?.map((item: any) => item.id));
}
// 深度优化目标下拉单选
setTableColumns([
...tableHeaderList.map((item: any) => {
if (item.dataIndex === 'deep_external_action') {
return {
...item,
width: 200,
valueType: 'select',
valueEnum: (row: any) => {
const optionList = row?.deep_goals
?.filter((itemF: any) => itemF.optimization_name)
.map((itemO: any) => {
return {
label: itemO.optimization_name,
value: itemO.deep_external_action,
};
});
const valueEnumObj = {};
optionList?.forEach((items: any) => {
valueEnumObj[items.value] = { text: items.label };
});
return valueEnumObj;
},
};
}
// 深度出价方式需要动态获取
if (item.dataIndex === 'deep_bid_type') {
return {
...item,
width: 200,
valueType: 'select',
valueEnum: (row: any) => {
let deepList: any[] = [];
const hasChoose = row?.deep_goals?.find(
(el: any) => el.deep_external_action === row.deep_external_action,
);
if (hasChoose) {
deepList =
row?.deep_goals.find(
(el: any) => el.deep_external_action === row.deep_external_action,
)?.deep_bid_type || [];
} else {
deepList = row?.default_deep_bid_type || [];
}
const optionList = deepList?.map((itemO: any) => {
return {
label: itemO.name,
value: itemO.id,
};
});
const valueEnumObj = {};
optionList?.forEach((items: any) => {
valueEnumObj[items.value] = { text: items.label };
});
return valueEnumObj;
},
};
}
return {
...item,
width: 200,
editable: false,
};
}),
]);
}
setTableLoading(false);
} catch (error) {
//
}
}
}; // 关键词搜索
useEffect(() => {
if (!isEmpty(tableParams)) fetchList(targetAccount);
}, [tableParams]); useEffect(() => {
if (dataSource.length) {
const newList = data?.map((item: any) => {
if (item.account_id === targetAccount) {
const newObj = dataSource.find((itemList: any) => itemList.id === item.id);
return newObj;
}
return item;
});
setData(newList);
} else {
setData([]);
}
}, [dataSource]); // 当前选中key
useEffect(() => {
if (targetAccount) {
if (data && data.length) {
const idList = data
.filter((item) => item.account_id === targetAccount)
.map((item: API.AssetsProps) => {
return item.id;
});
setKeys(idList);
} else {
setKeys([]);
}
}
}, [targetAccount, data]); // 打开弹窗时,默认左侧广告投放列表选中第一项,并进行列表请求
useEffect(() => {
if (accounts && accounts[0]) {
adsRef?.current?.selectItem(accounts[0]);
setTargetAccount(accounts[0].id);
if (visible) {
fetchList(accounts[0].id || '');
// 更新data
if (value && Array.isArray(value) && value.length) {
setData(value);
}
}
}
}, [visible]); useEffect(() => {
// 更新data
if (value && Array.isArray(value) && value.length) {
setData(value);
}
}, [value]); return (
<>
<div>
<Button
onClick={() => {
const trace_events = JSON.parse(sessionStorage.getItem('ASSETS_FORM') || '');
if (!trace_events?.app_type) {
message.error('请选择资产类型');
return;
}
setVisible(true);
}}
>
{data && data.length ? '已' : ''}选择事件资产{data && data.length ? ',点击配置' : ''}
</Button>
{data && data.length ? null : (
<span style={{ marginLeft: '8px' }}>
找不到适用的资产,去
<a
href="/"
key="createAssets"
target="_blank"
rel="noreferrer"
>
创建资产
</a>

</span>
)}
</div>
<Modal width={1500} visible={visible} onCancel={() => setVisible(false)} onOk={handleOk}>
<div className={styles['existring-ads-list']}>
<div style={{ width: '16%', marginRight: '16px' }}>
<ScrollList cRef={adsRef} list={accounts} title="账号名称" onChange={fetchList} />
</div>
<div style={{ width: '84%' }}>
<Search
addonBefore="资产名称"
placeholder="请输入关键词搜索"
allowClear
onSearch={async (valueSearch: string) =>
setTableParams({ ...tableParams, asset_name: valueSearch })
}
style={{ width: 300, marginBottom: '8px' }}
/>
<EditableProTable
rowKey="id"
loading={tableLoading}
bordered
request={async () => ({
data: dataSource,
total: dataSource.length,
success: true,
})}
tableAlertRender={false}
className={styles['exist-table-edit']}
value={dataSource}
onChange={(valueNew: any[]) => {
const newTableData = valueNew.map((item: any, index: number) => {
// 深度优化目标的值改变时,清空本条数据的深度出价方式的值
if (item.id === dataSource[index].id) {
if (item.deep_external_action !== dataSource[index].deep_external_action) {
return { ...item, deep_bid_type: undefined };
}
return item;
}
return item;
});
setDataSource(newTableData);
}}
controlled
recordCreatorProps={false}
editable={{
type: 'multiple',
editableKeys,
actionRender: undefined,
onChange: setEditableRowKeys,
}}
scroll={{ y: 320, x: 'max-content' }}
columns={tableColumns}
tableRender={undefined}
pagination={false}
rowSelection={{
type: 'radio',
selectedRowKeys: keys,
onChange: (selectedRowKeys: any, selectedRows: any) => {
if (data && data.length) {
// hasAccount = 当前账号是否存在
const hasAccount = data.filter((item) => item.account_id === targetAccount);
if (hasAccount && hasAccount.length) {
const newList = data.map((item: API.AssetsProps) => {
if (item.account_id === targetAccount) {
return selectedRows[0];
}
return item;
});
setData(newList);
} else {
setData([...data, ...selectedRows]);
}
} else {
setData(selectedRows);
}
},
}}
/>
{dataSource && dataSource.length ? <p>共 {dataSource.length} 条</p> : null}
</div>
</div>
</Modal>
</>
);
}; export default AssetsTable;

  

最新文章

  1. 高性能JavaScript 编程实践
  2. java EE中使用PO和VO的注意事项
  3. Codeforces 570C 贪心
  4. StackOverflow发布年度开发者调查报告:JavaScript备受欢迎
  5. nginx不支持pathinfo函数
  6. IDE显示无法打开源文件时解决方案
  7. N个元素组成二叉树的种类
  8. linux创建git远程仓库
  9. 【转】SVN服务器客户端以及环境的搭建和使用
  10. Struts2零碎点整理
  11. TypeScript设计模式之工厂
  12. memcache基础
  13. 一、Html简介
  14. [CF364D]Ghd
  15. SQL视图命名规则:一般以V_xxx_xxxxxx
  16. 软件工程实践_Task1
  17. openstack--4--控制节点安装配置glance
  18. hadoop动态添加删除节点datanode及恢复
  19. Freemarker 基本数据类型
  20. 如何打war包和jar包

热门文章

  1. defineProperty和Proxy
  2. springboot gradle 集成流程引擎activiti
  3. docker镜像打包成tar包,上传到另一台服务器
  4. 简易Map模板
  5. ADC多通道采样DMA传输模板
  6. Win10下VM虚拟机桥接模式无法上网的相关问题?
  7. 日志 LOG / Debug
  8. 蓝桥杯训练赛二-1199 问题 E: 哥德巴赫曾猜测
  9. vue高级进阶( 三 ) 组件高级用法及最佳实践
  10. 使用Visual Studio工具将ActiveX控件的COM类库转换为窗体控件