feat(scene): 新增工程场景页面功能

- 添加创建和编辑工程场景的弹窗
- 实现工程场景列表的展示和分页
- 增加工程场景的搜索功能
- 添加工程场景的封面图选择功能
- 实现工程场景的大屏配置功能
master
钟良源 5 months ago
parent 599d37c46d
commit 1bf8b3e9cf

@ -0,0 +1,101 @@
import React, { useState } from 'react';
import { Button, Input, Table, TableColumnProps } from '@arco-design/web-react';
import { IconDelete, IconPlusCircle } from '@arco-design/web-react/icon';
interface TableDataItem {
key: number | string;
label: string;
url: string;
[key: string]: any; // 允许其他自定义字段
}
const ConfigTable = () => {
const [tableData, setTableData] = useState([]);
const columns: TableColumnProps[] = [
{
title: '标签',
dataIndex: 'label',
render: (_: any, record: TableDataItem) => (
<Input
value={record.label}
onChange={(value) => handleSave({ ...record, label: value })}
/>
)
},
{
title: 'url',
dataIndex: 'url',
render: (_: any, record: TableDataItem) => (
<Input
value={record.url}
onChange={(value) => handleSave({ ...record, url: value })}
/>
)
},
{
title: '操作',
dataIndex: 'address',
render: (_: any, record: TableDataItem) => (
<Button onClick={() => removeRow(record.key)} type="text" status="danger">
<IconDelete />
</Button>
)
}
];
const newKey = Date.now();
const addRow = () => {
const newRow = {
key: newKey,
label: '',
url: ''
};
const newData = [...tableData, newRow];
setTableData(newData);
};
const removeRow = (key: number | string) => {
const newData = tableData.filter((item) => item.key !== key);
setTableData(newData);
};
const handleSave = (row: TableDataItem) => {
const newData = [...tableData];
const index = newData.findIndex((item) => row.key === item.key);
if (index >= 0) {
newData.splice(index, 1, { ...newData[index], ...row });
}
else {
newData.push(row);
}
setTableData(newData);
};
return (
<>
{!!tableData.length && (
<>
<Table columns={columns} data={tableData} />
<Button
style={{ height: 45, marginTop: 5 }}
long
type="outline"
onClick={addRow}
>
+
</Button>
</>
)}
{!tableData.length && (
<div className={'add-icon'}>
<IconPlusCircle style={{ fontSize: 24, color: 'rgb(0, 117, 255)', cursor: 'pointer' }} onClick={addRow} />
</div>
)}
</>
);
};
export default ConfigTable;

@ -0,0 +1,66 @@
import React, { useEffect, useState } from 'react';
import styles from '@/pages/scene/style/cover.module.less';
import { Image, Modal, List } from '@arco-design/web-react';
import scene01 from '@/assets/images/scene01.jpg';
import scene02 from '@/assets/images/scene02.jpg';
import scene03 from '@/assets/images/scene03.jpeg';
import scene04 from '@/assets/images/scene04.png';
import scene07 from '@/assets/images/scene07.png';
import scene08 from '@/assets/images/scene08.jpg';
import { getImageUrl } from '@/utils/pubUse';
const imageList = [scene01, scene02, scene03, scene04, scene07, scene08];
interface CoverProps {
defaultImage?: string;
}
const Cover: React.FC<CoverProps> = ({ defaultImage }) => {
const [visible, setVisible] = useState(false);
const [currentImage, setCurrentImage] = useState('');
useEffect(() => {
if (defaultImage) {
setCurrentImage(getImageUrl(defaultImage));
}
else {
const imageRandom = Math.floor(Math.random() * imageList.length);
setCurrentImage(imageList[imageRandom].src);
}
}, [defaultImage]);
return (
<div className={styles['cover-container']}>
<div className={styles['cover-image']}>
<Image width={200} src={currentImage} preview={false} onClick={() => setVisible(true)}></Image>
</div>
<Modal
style={{ width: '60%' }}
title="选择封面图"
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
autoFocus={false}
focusLock={true}
>
<List
grid={{ gutter: 0, span: 6 }}
size="small"
dataSource={imageList}
render={(item, index) => {
return (
<List.Item key={index}>
<Image width={200} src={item.src} preview={false} onClick={() => {
setCurrentImage(item.src);
setVisible(false);
}}></Image>
</List.Item>
);
}}
/>
</Modal>
</div>
);
};
export default Cover;

@ -5,6 +5,7 @@ import { IconPlus, IconApps } from '@arco-design/web-react/icon';
import { openWindow, OpenWindowOptions } from '@/utils/common';
import { getPublicSceneList, getMySceneList } from '@/api/scene';
import CardWrap from '@/pages/scene/cardWrap';
import OperationModal from '@/pages/scene/operationModal';
const InputSearch = Input.Search;
const Row = Grid.Row;
@ -25,6 +26,9 @@ const Engineering: React.FC<EngineeringProps> = ({ dataType, showAdd = true }) =
});
const [currentPage, setCurrentPage] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(DEFAULT_PAGE_SIZE);
const [showModal, setShowModal] = useState(false);
const [operationType, setOperationType] = useState('ADD');
const [currentItem, setCurrentItem] = useState(null);
const onSearchHandle = (value: string) => {
// 搜索时重置到第一页
@ -46,16 +50,22 @@ const Engineering: React.FC<EngineeringProps> = ({ dataType, showAdd = true }) =
openWindow(url, params);
};
const openModalHandle = (type: string, item: any = null) => {
console.log('item:', item);
setShowModal(true);
setOperationType(type);
setCurrentItem(item);
};
const handleEdit = (item, e) => {
e.stopPropagation();
Message.info(`编辑项目: ${item.name}`);
// TODO 在这里添加编辑逻辑
openModalHandle('EDIT', item);
};
const handleDelete = (item, e) => {
e.stopPropagation();
// TODO 在这里添加删除逻辑
console.log("删除");
console.log('删除');
};
const handlePageChange = (page: number) => {
@ -125,6 +135,7 @@ const Engineering: React.FC<EngineeringProps> = ({ dataType, showAdd = true }) =
{showAdd && (
<Card
className={styles['card-style']}
onClick={() => openModalHandle('ADD')}
>
<Result
status="info"
@ -155,6 +166,7 @@ const Engineering: React.FC<EngineeringProps> = ({ dataType, showAdd = true }) =
</Col>
))}
</Row>
{/*分页组件*/}
<Row>
<Col>
<Pagination
@ -169,6 +181,13 @@ const Engineering: React.FC<EngineeringProps> = ({ dataType, showAdd = true }) =
</Col>
</Row>
</div>
{/*新增/编辑弹窗*/}
<OperationModal
show={showModal}
type={operationType}
item={currentItem}
onCancel={(status) => setShowModal(status)}
/>
</>
);
};

@ -0,0 +1,53 @@
import React, { useEffect } from 'react';
import { Modal, Form, Input, Checkbox } from '@arco-design/web-react';
import Cover from '@/pages/scene/cover';
import ConfigTable from '@/pages/scene/configTable';
const FormItem = Form.Item;
interface OperationModalProps {
show: boolean;
type: string;
item: any;
onCancel: (status: boolean) => void;
}
const OperationModal: React.FC<OperationModalProps> = ({ show, type, item, onCancel }) => {
const [visible, setVisible] = React.useState(false);
useEffect(() => {
setVisible(show);
}, [show]);
return (
<Modal
style={{ width: '50%' }}
title={type === 'ADD' ? '创建工程' : '编辑工程'}
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => onCancel(false)}
autoFocus={false}
focusLock={true}
>
<Form autoComplete="off">
<FormItem label="封面图">
<Cover defaultImage={item?.logo} />
</FormItem>
<FormItem label="名称" required>
<Input placeholder="请输入工程名称" />
</FormItem>
<FormItem label="描述" required>
<Input placeholder="请输入工程描述" />
</FormItem>
<FormItem label="大屏">
<ConfigTable />
</FormItem>
<FormItem label=" ">
<Checkbox></Checkbox>
</FormItem>
</Form>
</Modal>
);
};
export default OperationModal;

@ -0,0 +1,3 @@
.cover-container {
}
Loading…
Cancel
Save