@ant-design/icons#PlusCircleOutlined JavaScript Examples
The following examples show how to use
@ant-design/icons#PlusCircleOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: baseForm.js From FP with MIT License | 6 votes |
BaseFormEl = (props) => {
const {isEdit, onEdit, onDel, onAdd} = props
const handleEdit = (v) => {
onEdit && onEdit(v)
}
return <div className={styles.formControl} style={{border: `1px solid ${isEdit ? 'red' : 'transparent'}`}}>
<div className={styles.formItem}>{ props.children }</div>
<div className={styles.actionBar}>
<span className={styles.actionItem} onClick={onDel}><MinusCircleOutlined /></span>
<span className={styles.actionItem} onClick={onAdd}><PlusCircleOutlined /></span>
<span className={styles.actionItem} onClick={handleEdit}><EditOutlined /></span>
</div>
</div>
}
Example #2
Source File: index.js From bank-client with MIT License | 5 votes |
export default function Bills() {
const dispatch = useDispatch();
const { bills, isLoading } = useSelector(stateSelector);
const getBills = () => dispatch(getBillsAction());
const toggleModal = () => dispatch(toggleModalAction());
useEffect(() => {
if (!bills.length) {
getBills();
}
}, []);
return (
<>
<FormattedMessage {...messages.title}>
{(title) => (
<StyledCard
darker="true"
loaded={isLoading ? 1 : 0}
bordered={false}
shadowed="true"
title={title}
extra={
<StyledButton type="link" onClick={toggleModal}>
<StyledButtonContent onMouseDown={(e) => e.stopPropagation()}>
<PlusCircleOutlined />{' '}
<FormattedMessage {...messages.action} />
</StyledButtonContent>
</StyledButton>
}
>
{isLoading ? (
<LoadingIndicator />
) : (
<StyledTableWrapper onMouseDown={(e) => e.stopPropagation()}>
<StyledTable
showHeader={false}
pagination={false}
dataSource={bills}
columns={columns}
rowKey={({ uuid }) => uuid}
/>
</StyledTableWrapper>
)}
</StyledCard>
)}
</FormattedMessage>
<Modal />
</>
);
}
Example #3
Source File: TecnologiasListas.jsx From node-project-manager with Apache License 2.0 | 4 votes |
Tecnologias = ({ techs, getAllTechs, selectedTech }) => {
const [showTechForm, setShowTechForm] = useState(false);
const replenishTable = useCallback(async () => {
const dataSource = await Http.get("/api/techs/findAllTechs");
dataSource.unshift({
id: "add",
nombre: "Add",
logo: "js.png",
descripcion: "Añade tecnología",
version: "",
creador: ""
});
getAllTechs(
dataSource.map(item => {
item.key = item.id;
item.icon = require(`../../img/techs/${item.logo}`);
return item;
})
);
selectedTech(dataSource[1]);
}, [getAllTechs,selectedTech]);
useEffect(() => {
// Wait for loading data user
//setLoading(true);
replenishTable();
//setLoading(false);
}, [replenishTable]);
return (
<React.Fragment>
<List
grid={{ gutter: 16, column: 4 }}
dataSource={techs}
className="itemList"
renderItem={item => (
<List.Item>
{item.id === "add" ? (
<Card
className="techCardAdd"
title="Añadir"
onClick={() => {
setShowTechForm(!showTechForm);
}}
>
<span>
<PlusCircleOutlined style={{fontSize:"73px",margin:"0 auto"}}/>
</span>
</Card>
) : (
<Card
className="techCard"
title={
<span>
<Avatar src={item.icon}></Avatar> {item.nombre}
</span>
}
onClick={() => {
selectedTech(item);
}}
>
{item.version}
<br />
{item.descripcion.substring(0,15)}
{(item.descripcion.length < 15) ? "" : " ..."}
</Card>
)}
</List.Item>
)}
/>
<Modal
title="Crear Tecnologia"
visible={showTechForm}
okText="Salir"
destroyOnClose={true}
onOk={() => {
setShowTechForm(!showTechForm);
}}
cancelText="Cancelar"
onCancel={() => {
setShowTechForm(!showTechForm);
}}
>
<TechForm />
</Modal>
</React.Fragment>
);
}
Example #4
Source File: tag.js From deadviz with MIT License | 4 votes |
CustomTag = ({deadlineTag, tagItem}) => {
const [tags, setTags] = useState(null);
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const refInput = useRef(null);
const handleClose = (indexTag) => {
ChromeStorage.removeTag(deadlineTag.id,tagItem.index, indexTag).then(result => {
updateCacheTag();
});
};
const showInput = useCallback(() => {
setInputVisible(true);
if(refInput.current != null) {
refInput.current.focus();
}
},[refInput]);
const handleInputChange = e => {
setInputValue(e.target.value);
};
const updateStorageTag = (tag) => {;
ChromeStorage.getDeadline(deadlineTag.id).then
( deadline => {
if(deadline.tag) {
// eslint-disable-next-line no-unused-expressions
deadline.tag[tagItem.index].push(tag);
} else {
const newTags = Array.from(Array(deadlineTag.boxes.length), () => []);
newTags[tagItem.index].push(tag);
deadline.tag = newTags;
}
ChromeStorage.saveDeadline(deadline).then(result => {
updateCacheTag();
});
});
}
const handleInputConfirm = () => {
if (inputValue) {
if (tags) {
setTags([...tags, inputValue]);
} else {
setTags([inputValue]);
}
updateStorageTag(inputValue);
}
setInputVisible(false);
setInputValue('');
};
const updateCacheTag = () => {
ChromeStorage.getTag(tagItem.index, deadlineTag.id).then((tags) => {
setTags(tags);
});
}
useEffect(() => {
setInputVisible(false);
if (tagItem) {
updateCacheTag();
}
},[tagItem, deadlineTag]);
return (
(tagItem != null ? tagItem.item.passed : false) && (
<>
{ (tags || [] ).map((item, index) => { return (
<>
<Tags icon={<CloseCircleOutlined />}
className="edit-tag"
key={index}
onClick={(e) => {handleClose(index)}}
>{item}
</Tags>
</>)})
}
{inputVisible && (
<Input
type="text"
size="small"
ref={refInput}
className="tag-input"
value={inputValue}
onChange={ (e)=>{ handleInputChange(e)}}
onPressEnter={ (e)=>{ handleInputConfirm(e)} }
/>
)}
{!inputVisible && (
<NewTag className="site-tag-plus" onClick={()=>{showInput()}}>
<PlusCircleOutlined /> New Tag
</NewTag>
)}
</>
)
);
}
Example #5
Source File: confgo.jsx From juno with Apache License 2.0 | 4 votes |
render() {
const that = this;
const {
appId = 0,
app = {},
apps = [],
configList = [],
configText,
commonText,
appConfigList = [],
configChangeList = [],
statusList = [],
configHistoryList = [],
resourceData = {},
appInfo: { aid, appName },
msg,
idcList,
file_path = '',
zoneCode,
} = this.props;
console.log('render -> configText', configText);
const { users = [] } = app;
const appInfo = appConfigList[0] || {};
const {
caid,
file_name,
format,
env,
filterKey,
selectItemID,
selectKey,
selectValue,
selectComment,
selectIsResource,
selectResourceID,
selectIsPublic,
fileDelModalVisible: showFileManage,
fileDelConfirmLoading,
result_list = [],
} = this.state;
const changeNum = configList.filter((v) => v.status * 1 !== 1).length;
const leftCardStyle = {
borderRadius: '4px',
marginTop: '4px',
marginLeft: '4px',
};
const statusMap = (t, status) => {
const map = {
1: <span></span>,
2: <span>{getOpSapn('new')}</span>,
3: <span>{getOpSapn('update')}</span>,
4: <span>{getOpSapn('del')}</span>,
};
return map[status];
};
const changListCols = [
{
key: 'key',
dataIndex: 'key',
title: 'Block',
width: 120,
render(t, r) {
return <span style={{ wordBreak: 'break-word' }}>{t}</span>;
},
},
{
key: 'op_type',
dataIndex: 'op_type',
title: '操作',
width: 80,
render(t) {
const opMap = {
1: getOpSapn('new', '新增'),
2: getOpSapn('update', '更新'),
3: getOpSapn('del', '删除'),
};
return <span>{opMap[t]}</span>;
},
},
{
key: 'old_value',
dataIndex: 'old_value',
title: '旧值',
render(t) {
let tmp = t;
if (t.length > 200) {
tmp = tmp.substring(0, 200) + '...';
}
return <span style={{ wordBreak: 'break-word' }}>{tmp}</span>;
},
},
{
key: 'new_value',
dataIndex: 'new_value',
title: '新值',
render(t) {
let tmp = t;
if (t.length > 200) {
tmp = tmp.substring(0, 200) + '...';
}
return <span style={{ wordBreak: 'break-word' }}>{tmp}</span>;
},
},
{
key: 'update_time',
dataIndex: 'update_time',
title: '时间',
width: 180,
render(t) {
return moment(t * 1000).format('YYYY-MM-DD HH:mm:ss');
},
},
{
key: 'op_name',
dataIndex: 'op_name',
width: 180,
title: '操作人',
},
];
const statusCol = [
{
key: 'is_use',
dataIndex: 'is_use',
title: (
<span>
配置状态
<Tooltip
title={`当前实例上的systemd配置文件项是否接入配置中心\n。若显示未接入,则需要修改systemd下发配置,路径改为配置中心提供的路径\n。若已经修改下发过,点击【同步实例状态】刷新。`}
>
<QuestionCircleOutlined style={{ marginLeft: '6px' }} />
</Tooltip>
</span>
),
render(t) {
return t ? getOpSapn('new', '已接入') : <div>{getOpSapn('del', '未接入')}</div>;
},
},
{
key: 'is_latest',
dataIndex: 'is_latest',
title: (
<span>
文件状态
<Tooltip
title={`当前实例上的配置文件是否为最新发布\n。若显示未同步,点击【刷新文件状态】。若刷新无效则需要【重新发布】一次。`}
>
<QuestionCircleOutlined style={{ marginLeft: '6px' }} />
</Tooltip>
</span>
),
render(t) {
return t ? getOpSapn('new', '已同步') : getOpSapn('del', '未同步');
},
},
{
key: 'is_effect',
dataIndex: 'is_effect',
title: (
<span>
配置状态
<Tooltip title={`重启之后应用配置是否生效`}>
<QuestionCircleOutlined style={{ marginLeft: '6px' }} />
</Tooltip>
</span>
),
render(t) {
return t ? getOpSapn('new', '已生效') : <div>{getOpSapn('del', '未生效')}</div>;
},
},
{
key: 'hostname',
dataIndex: 'hostname',
title: '实例名称',
},
{
key: 'message',
dataIndex: 'message',
title: '提交日志',
},
{
key: 'timestamp',
dataIndex: 'timestamp',
title: '文件同步时间/进程启动时间',
render(t, r) {
const { process_start_time = 0, is_latest, is_use } = r;
if (process_start_time !== 0) {
const syncTime = t * 1000;
const startTime = process_start_time * 1000;
//进程生效状态
let process_start_status = null;
if (syncTime > startTime) {
//配置未完全生效
process_start_status = (
<Tooltip title={'配置文件已经同步完成,进程尚未重启生效'}>
<Icon type="clock-circle" style={{ color: 'orange' }} />
</Tooltip>
);
} else if (is_latest && is_use) {
// 配置文件已同步,进程已重启,生效
process_start_status = (
<Tooltip title={'最新配置已经生效'}>
<Icon type="check-circle" style={{ color: 'green' }} />
</Tooltip>
);
}
return (
<div>
<p>{moment(syncTime).format('YYYY-MM-DD HH:mm:ss')}</p>
<p>
{moment(startTime).format('YYYY-MM-DD HH:mm:ss')} {process_start_status}
</p>
</div>
);
}
return (
<div>
<p>{moment(t * 1000).format('YYYY-MM-DD HH:mm:ss')}</p>
</div>
);
},
},
{
key: 'params',
dataIndex: 'params',
title: (
<span>
启动参数
<Tooltip
title={
'当前实例上的systemd配置中的启动参数, ${ConfigDir}变量为配置中心默认下发路径。启动时间为进程启动时间。'
}
>
<Icon style={{ marginLeft: '6px' }} type="question-circle" />
</Tooltip>
</span>
),
render(t, r) {
const paramsArr = t.split('/bin/%(program_name)s');
if (paramsArr.length !== 2) {
return t;
}
const params = paramsArr[1];
return (
<div>
<p style={{ margin: 0 }}>{params}</p>
</div>
);
},
},
{
key: 'op',
dataIndex: 'op',
title: '操作',
render(t, r) {
const { pub_id, is_latest } = r;
if (is_latest) {
return (
<div>
<Button
style={{ color: 'black' }}
onClick={(e) => {
that.showConfirm('restart', this.state.zone_code, r.hostname);
}}
>
重启
</Button>
</div>
);
}
},
},
];
const customPanelStyle = {
background: '#f7f7f7',
borderRadius: 4,
marginBottom: 8,
border: 0,
overflow: 'hidden',
};
//文本编辑器options
const options = {
lineNumbers: true, //显示行号
mode: { name: 'text/html' }, //定义mode
theme: 'ambiance', //选中的theme
lineWrapping: true,
};
if (msg === '权限错误') {
return (
<div style={{ marginTop: 10 }}>
<Alert
message="权限不足"
description="对线上配置操作需要管理员权限"
type="error"
showIcon
/>
</div>
);
}
let idcArr = [];
let zone_codeMap = [];
idcList.forEach((element) => {
idcArr.push(element.zone_code);
zone_codeMap[element.zone_code] = element.zone_name;
});
const genHeader = (record) => (
<div>
<div className={'cube'}>
{record.is_public == 0 && <Tag color="#2db7f5">私有</Tag>}
{record.is_public == 1 && <Tag color="#f50">公有</Tag>}
{record.is_public == 2 && <Tag color="#87d068">关联</Tag>}
</div>
<div className={'cube-title'}>
<h3>{record.key}</h3>
</div>
</div>
);
const genExtra = (record) => (
<div>
{statusMap(record.key, record.status)}
<Divider type="vertical" />
{record.status != 4 && (
<Tag
color={'blue'}
onClick={(event) => {
event.stopPropagation();
that.setState({
selectItemID: record.id,
selectKey: record.key,
selectValue: record.value,
selectComment: record.comment,
selectIsResource: record.is_resource,
selectResourceID: record.resource_id,
selectIsPublic: record.is_public,
showUpdateItem: true,
});
that.getEnvResource();
}}
>
编辑
</Tag>
)}
{record.status != 4 && (
<Popconfirm
title="确定删除吗?"
onConfirm={() => {
that.delItem({ id: record.id });
}}
>
<Tag color={'red'}>删除</Tag>
</Popconfirm>
)}
</div>
);
let configItemList = [];
configList.forEach((element) => {
configItemList.push(
<Panel
header={genHeader(element)}
key={element.key}
className="site-collapse-custom-panel"
extra={genExtra(element)}
>
<ReactCodeMirror
ref="editor"
value={element.value}
options={{
mode: 'text/x-toml',
lineNumbers: true,
autoMatchParens: true,
lineWrapping: false,
readOnly: this.state.readOnly,
scrollbarStyle: null,
}}
/>
</Panel>,
);
});
return (
<Layout>
<Sider width={250} style={{ backgroundColor: 'transparent' }}>
<Card style={leftCardStyle}>
<p style={{ textAlign: 'left' }}>
配置文件列表
<Button
style={{ marginLeft: '8px' }}
size={'small'}
type={'primary'}
icon={<PlusCircleOutlined />}
onClick={() => {
this.setState({ showConfigFile: true });
}}
>
添加配置
</Button>
</p>
{appInfo && appInfo.configs ? (
<Menu
selectedKeys={[caid + '_' + env + '_' + format]}
mode="inline"
style={{ height: '50%', borderRight: 0 }}
defaultOpenKeys={idcArr}
onClick={this.changeAppConfig}
>
{Object.keys(this.sortObj(appInfo.files, idcArr)).map((zone_code) => {
if (zoneCode == 'all' || zoneCode == zone_code) {
return (
<Menu.SubMenu key={zone_code} title={<h4>{`${zone_codeMap[zone_code]}`}</h4>}>
{appInfo.files[zone_code].map((v) => {
console.log('this.state.zone_code', this.state.zone_code);
return (
<Menu.Item
style={{ paddingLeft: '20px' }}
key={v.id + '_' + v.env + '_' + v.format}
>
{v.file_name}
</Menu.Item>
);
})}
</Menu.SubMenu>
);
}
})}
</Menu>
) : (
<div style={{ textAlign: 'left' }}>
<Button type={'primary'} onClick={() => this.setState({ showConfigFile: true })}>
添加配置文件
</Button>
</div>
)}
</Card>
<Card style={leftCardStyle}>
<p style={{ textAlign: 'left' }}>文件管理</p>
<Button type="primary" onClick={this.handleFileManage} style={{ marginLeft: '4px' }}>
文件管理
</Button>
<Button type="primary" onClick={this.handleFileDiff} style={{ marginLeft: '4px' }}>
文件对比
</Button>
</Card>
</Sider>
<Content>
<div>
{caid !== 0 && (
<Row style={{ marginTop: '4px', marginLeft: '4px', marginRight: '4px' }}>
<Col span={4} style={{ textAlign: 'left' }}>
<Button
style={{ float: 'left', marginRight: '6px' }}
onClick={(e) => {
//加载节点数据
this.getAppList().then((_) => {
//获取配置列表
this.autoChangeConfig(); //自动选择第一个配置文件
message.success('数据已更新');
});
}}
>
<Icon type="sync" />
刷新数据
</Button>
<Tooltip
title={`当前页面为静态页面,修改配置前需要刷新获取最新配置数据,以免覆盖其他人的配置数据`}
>
<QuestionCircleOutlined />
</Tooltip>
</Col>
<Col span={20} style={{ textAlign: 'right' }}>
<Button.Group>
<Button
type={'primary'}
onClick={() => {
that.setState({ showPublish: true });
}}
>
发布配置
</Button>
<Button
type={'danger'}
onClick={(e) => {
that.changeTab('status');
}}
>
重启列表
</Button>
<Button
type={'primary'}
onClick={(e) => {
that.setState({ showRollback: true });
}}
>
配置回滚
</Button>
<Button
onClick={() => {
that.getHistoryList();
that.setState({ showHistory: true });
}}
>
发布历史
</Button>
</Button.Group>
</Col>
</Row>
)}
{caid !== 0 && (
<Tabs
style={{
backgroundColor: '#fff',
marginTop: '5px',
marginLeft: '5px',
marginRight: '5px',
}}
activeKey={this.state.tab}
onChange={this.changeTab}
>
<TabPane
tab={
<span>
<div style={{ marginLeft: 10 }}>
<TableOutlined />
配置编辑
</div>
</span>
}
key="table"
>
<Row>
<Col style={{ marginTop: '-5px' }}>
<Button.Group>
<Button
style={{ marginLeft: '10px' }}
type="primary"
onClick={() => {
that.setState({ showAddItem: true });
that.getEnvResource();
}}
>
添加 Block
</Button>
</Button.Group>
</Col>
</Row>
<Row gutter={24}>
<Col span={24} style={{ marginTop: '10px' }}>
<Collapse
bordered={false}
defaultActiveKey={['application']}
expandIcon={({ isActive }) => (
<CaretRightOutlined rotate={isActive ? 90 : 0} />
)}
className="site-collapse-custom-collapse"
expandIconPosition="right"
>
{configItemList}
</Collapse>
</Col>
</Row>
</TabPane>
<TabPane
tab={
<span>
<FileOutlined />
发布预览
</span>
}
key="text"
>
<Spin spinning={this.state.loading} />
<Row>
<Col
style={{
textAlign: 'left',
marginLeft: '8px',
marginBottom: '8px',
fontSize: '18px',
}}
span={12}
>
{file_name}
</Col>
<Col
style={{
textAlign: 'right',
marginRight: '8px',
marginBottom: '8px',
}}
span={11}
>
<Button.Group>
<span>
<Button
onClick={(e) => {
copy(configText);
message.success('已复制到剪切板');
}}
>
复制
</Button>
</span>
</Button.Group>
</Col>
</Row>
<div className={'configEditor'}>
<ReactCodeMirror
ref="editor"
value={configText}
options={{
mode: 'text/x-toml',
lineNumbers: true,
autoMatchParens: true,
lineWrapping: true,
readOnly: this.state.readOnly,
}}
onChange={(editor, data, value) => {
this.configInputText = editor.getValue();
}}
/>
</div>
</TabPane>
<TabPane
tab={
<span>
<FileDoneOutlined />
<Badge count={changeNum} overflowCount={9999} offset={[0, 18]}>
变更历史
</Badge>
</span>
}
key="history"
>
<Table
columns={changListCols}
dataSource={configChangeList}
size={'small'}
pagination={false}
rowKey={'id'}
/>
</TabPane>
<TabPane
tab={
<span>
<HddOutlined />
实例列表
</span>
}
key="status"
>
<Spin spinning={this.state.showStatusSync} />
<div style={{ marginLeft: '10px' }}>
配置文件路径:
<span
style={{
marginLeft: '8px',
marginRight: '8px',
fontSize: '16px',
}}
>{`${file_path}`}</span>
<a
onClick={(e) => {
copy(`${file_path}`);
message.success('已复制,请重新下发配置文件生效');
}}
>
点击复制
</a>
<Tooltip
title={`修改systemd下发的配置文件路径,由原来的项目相对路径改为配置中心的路径`}
>
<Icon style={{ marginLeft: '6px' }} type="question-circle" />
</Tooltip>
<span
style={{
float: 'right',
marginRight: '8px',
marginBottom: '8px',
}}
>
<Button
type={'primary'}
onClick={(e) => {
that.setState({
showStatusSync: true,
});
SyncConfigNodes({ caid: caid })
.then((rs) => {
that.getConfigStatusList();
message.success('同步成功');
that.setState({
showStatusSync: false,
});
})
.catch((err) => {
that.setState({
showStatusSync: false,
});
});
}}
>
刷新实例状态
</Button>
</span>
<Table
size="small"
columns={statusCol}
dataSource={statusList}
pagination={false}
/>
</div>
</TabPane>
</Tabs>
)}
<NewItemForm
show={this.state.showAddItem}
cancel={() => {
this.setState({ showAddItem: false });
}}
item={{
resourceData: resourceData,
}}
env={this.state.env}
zone_code={this.state.zone_code}
submit={this.addItem}
caid={this.state.caid}
zone_codeMap={zone_codeMap}
/>
<UpdateItemForm
show={this.state.showUpdateItem}
env={this.state.env}
zone_code={this.state.zone_code}
cancel={() => {
this.setState({ showUpdateItem: false });
}}
changeResource={(e) => {
that.setState({
selectIsResource: e,
});
}}
changeResourceID={(e) => {
that.setState({
selectResourceID: e * 1,
});
}}
caid={this.state.caid}
submit={this.updateItem}
item={{
id: selectItemID,
key: selectKey,
value: selectValue,
comment: selectComment,
is_resource: selectIsResource,
resource_id: selectResourceID,
resourceData: resourceData,
is_public: selectIsPublic,
}}
zone_codeMap={zone_codeMap}
/>
<PublishForm
show={this.state.showPublish}
publish_loading={this.state.publish_loading}
file_name={file_name}
item={{ caid }}
cancel={() => {
this.setState({ showPublish: false });
}}
submit={this.publishItem}
/>
<NewConfigFile
show={this.state.showConfigFile}
cancel={() => {
this.setState({ showConfigFile: false });
}}
submit={this.AddConfigFile}
zoneList={this.props.zoneList}
/>
<HistoryList
show={this.state.showHistory}
cancel={() => {
this.setState({ showHistory: false });
this.props.dispatch({
type: 'confuNew/setPublishChangeData',
payload: {},
});
}}
list={configHistoryList}
/>
<Preview
oldCode={configText}
newCode={this.configInputText}
show={this.state.showPreview}
cancel={() => {
this.setState({ showPreview: false });
}}
/>
{this.state.showRollback && (
<RollbackView
caid={caid}
show={this.state.showRollback}
rollback={() => {
that.getConfigList();
}}
cancel={() => {
this.setState({ showRollback: false });
}}
/>
)}
<FileManageView
show={this.state.showFileManage}
app_name={appName}
app_id={aid}
env={env}
zone_code={this.state.zone_code}
cancel={() => {
this.setState({ showFileManage: false }, () => {
this.autoChangeConfig;
});
}}
/>
<FileDiffView
show={this.state.showFileDiff}
originCid={this.state.caid}
rafeCid={0}
appConfigList={this.props.appConfigList}
cancel={() => {
this.setState({ showFileDiff: false });
}}
/>
</div>
</Content>
<Modal
title="操作面板"
visible={this.state.visible}
onOk={(e) => {
this.refreshState();
this.setState({ visible: false, result_list: [] });
}}
okText={'确定'}
onCancel={(e) => {
this.refreshState();
this.setState({ visible: false, result_list: [] });
}}
cancelText={'关闭'}
>
<div>
<Spin spinning={this.state.loading} />
</div>
<div style={{ backgroundColor: 'black', borderRadius: '5px' }}>
{result_list.map((v, i) => {
const { name, content } = v;
return (
<p key={i} style={{ color: 'green' }}>
{content}
</p>
);
})}
</div>
</Modal>
</Layout>
);
}
Example #6
Source File: ChannelSetting.js From network-rc with Apache License 2.0 | 4 votes |
export default function ChannelSetting({
saveServerConfig,
serverConfig,
resetChannel,
}) {
const [form] = Form.useForm();
useEffect(() => {
form.resetFields();
}, [serverConfig, form]);
const ui = (index, fields, { add, remove }) => {
return (
<Space align="baseline" split={<Divider type="vertical" />} wrap>
{fields.map((field) => {
const uiId = form.getFieldValue([
"channelList",
index,
"ui",
field.name,
"id",
]);
const uiComponent = serverConfig.uiComponentList.find(
(i) => i.id === uiId
);
return (
<Space key={field.key} align="baseline">
<Form.Item
label="UI"
{...field}
name={[field.name, "id"]}
fieldKey={[field.fieldKey, "id"]}
rules={[{ required: true, message: "客官!选一个!" }]}
>
<Select style={{ width: 80 }}>
{serverConfig.uiComponentList.map(({ id, name }) => (
<Option value={id}> {name} </Option>
))}
</Select>
</Form.Item>
{uiComponent && uiComponent.type === "joystick" && (
<Form.Item
label="轴"
{...field}
name={[field.name, "axis"]}
fieldKey={[field.fieldKey, "axis"]}
rules={[{ required: true, message: "客官!选一个!" }]}
>
<Select style={{ width: 80 }}>
<Option value="x">x</Option>
<Option value="y">y</Option>
</Select>
</Form.Item>
)}
<Form.Item
label="控制方向"
{...field}
name={[field.name, "positive"]}
fieldKey={[field.fieldKey, "positive"]}
valuePropName="checked"
>
<Switch checkedChildren="正向" unCheckedChildren="反向" />
</Form.Item>
<Form.Item
label="控制方式"
{...field}
name={[field.name, "method"]}
fieldKey={[field.fieldKey, "method"]}
>
<Select style={{ width: 80 }}>
<Option value="default">默认</Option>
<Option value="step">步进</Option>
</Select>
</Form.Item>
<Form.Item
label="步进速度"
{...field}
name={[field.name, "speed"]}
fieldKey={[field.fieldKey, "speed"]}
initialValue={0.5}
>
<InputNumber
step={0.1}
min={0}
disabled={
"step" !==
form.getFieldValue([
"channelList",
index,
"ui",
field.name,
"method",
])
}
/>
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
);
})}
<PlusCircleOutlined
onClick={() =>
add({
positive: true,
method: "default",
})
}
/>
</Space>
);
};
const keyboard = (index, fields, { add, remove }) => {
const type = form.getFieldValue(["channelList", index, "type"]);
return (
<Space align="baseline" direction="vertical">
{fields.map((field) => {
const method = form.getFieldValue([
"channelList",
index,
"keyboard",
field.name,
"method",
]);
return (
<Space key={field.key} align="baseline">
<Form.Item
{...field}
name={[field.name, "name"]}
fieldKey={[field.fieldKey, "name"]}
rules={[{ required: true, message: "客官!选一个按键!" }]}
extra="键盘按键"
>
<Input style={{ width: 80 }} />
</Form.Item>
{type === "pwm" && (
<Form.Item
{...field}
name={[field.name, "method"]}
fieldKey={[field.fieldKey, "method"]}
defaultValue="default"
extra="控制方式"
>
<Radio.Group size="middle">
<Radio.Button value="default">默认</Radio.Button>
<Radio.Button value="step">步进</Radio.Button>
</Radio.Group>
</Form.Item>
)}
{type === "pwm" && (
<Form.Item
{...field}
name={[field.name, "speed"]}
fieldKey={[field.fieldKey, "speed"]}
extra={
method === "default"
? "-1 ~ 1, 0 为归位"
: "每秒步进速度系数"
}
>
<InputNumber max={1} min={-1} step={0.1} />
</Form.Item>
)}
{/* {type === "switch" && (
<Form.Item
{...field}
name={[field.name, "speed"]}
fieldKey={[field.fieldKey, "speed"]}
extra="高低电平"
>
<Radio.Group size="middle">
<Radio.Button value={1}>高</Radio.Button>
<Radio.Button value={-1}>低</Radio.Button>
</Radio.Group>
</Form.Item>
)} */}
{(method === "default" || type === "switch") && (
<Form.Item
{...field}
name={[field.name, "autoReset"]}
fieldKey={[field.fieldKey, "autoReset"]}
extra="释放键盘是否复位"
valuePropName="checked"
defaultValue={true}
>
<Switch />
</Form.Item>
)}
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
);
})}
<PlusCircleOutlined
onClick={() =>
add({
speed: 1,
autoReset: true,
method: "default",
})
}
/>
</Space>
);
};
const gamepad = (index, fields, { add, remove }) => {
const type = form.getFieldValue(["channelList", index, "type"]);
return (
<Space align="baseline" split={<Divider type="vertical" />} wrap>
{fields.map((field) => {
// const method = form.getFieldValue([
// "channelList",
// index,
// "gamepad",
// field.name,
// "method",
// ]);
return (
<Space key={field.key} align="baseline">
<Form.Item
{...field}
name={[field.name, "name"]}
fieldKey={[field.fieldKey, "name"]}
rules={[{ required: true, message: "客官!选一个!" }]}
extra="摇杆轴或按键"
>
<Select style={{ width: 100 }}>
{gamePadInputList.map(({ value, name }) => (
<Option value={value}> {name} </Option>
))}
</Select>
</Form.Item>
{type === "pwm" && (
<Form.Item
{...field}
name={[field.name, "method"]}
fieldKey={[field.fieldKey, "method"]}
defaultValue="default"
extra="控制方式"
>
<Radio.Group size="middle">
<Radio.Button value="default">默认</Radio.Button>
<Radio.Button value="step">步进</Radio.Button>
</Radio.Group>
</Form.Item>
)}
{type === "pwm" && (
<Form.Item
{...field}
name={[field.name, "speed"]}
fieldKey={[field.fieldKey, "speed"]}
extra="控制系数,-1 ~ 1"
>
<InputNumber min={-1} max={1} step={0.1} />
</Form.Item>
)}
{/* {method === "default" && (
<Form.Item
{...field}
name={[field.name, "autoReset"]}
fieldKey={[field.fieldKey, "autoReset"]}
extra="释放按钮是否复位"
valuePropName="checked"
defaultValue={true}
>
<Switch />
</Form.Item>
)} */}
{/* {type === "switch" && (
<Form.Item
{...field}
name={[field.name, "speed"]}
fieldKey={[field.fieldKey, "speed"]}
extra="高低电平"
>
<Radio.Group size="middle">
<Radio.Button value={1}>高</Radio.Button>
<Radio.Button value={-1}>低</Radio.Button>
</Radio.Group>
</Form.Item>
)} */}
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
);
})}
<PlusCircleOutlined
onClick={() =>
add({
speed: 1,
autoReset: true,
method: "default",
})
}
/>
</Space>
);
};
return (
<Form form={form} onFinish={saveServerConfig} initialValues={serverConfig}>
<Form.List name="channelList">
{(fields, { add, remove }) => (
<Space
key={fields.key}
direction="vertical"
style={{ width: "100%" }}
>
{fields.map((field) => (
<Card
key={field.key}
title={
<Space key={field.key} align="baseline" wrap>
<Form.Item
{...field}
name={[field.name, "enabled"]}
fieldKey={[field.fieldKey, "enabled"]}
valuePropName="checked"
>
<Switch checkedChildren="开启" unCheckedChildren="禁用" />
</Form.Item>
<Form.Item
{...field}
label="名称"
name={[field.name, "name"]}
fieldKey={[field.fieldKey, "name"]}
>
<Input style={{ width: 80 }} />
</Form.Item>
<Button danger onClick={() => remove(field.name)}>
<DeleteOutlined />
</Button>
</Space>
}
>
<Row>
<Space key={field.key} align="baseline" wrap>
<Form.Item
{...field}
label="GPIO"
name={[field.name, "pin"]}
fieldKey={[field.fieldKey, "pin"]}
rules={[{ required: true, message: "仔细想想" }]}
>
<Select style={{ width: 60 }}>
{pins.map((pin) => (
<Option key={pin} value={pin}>
{pin}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
{...field}
label="类型"
name={[field.name, "type"]}
fieldKey={[field.fieldKey, "type"]}
rules={[{ required: true, message: "你不能没有我!" }]}
>
<Select style={{ width: 80 }}>
{types.map(({ value, label }) => (
<Option key={value} value={value}>
{label}
</Option>
))}
</Select>
</Form.Item>
{form.getFieldValue([
"channelList",
field.fieldKey,
"type",
]) === "pwm" && (
<>
<Form.Item
{...field}
label="最大值"
name={[field.name, "valuePostive"]}
fieldKey={[field.fieldKey, "valuePostive"]}
>
<InputNumber
step={0.1}
max={2}
min={form.getFieldValue([
"channelList",
field.fieldKey,
"valueReset",
])}
/>
</Form.Item>
<Form.Item
{...field}
label="复位值"
name={[field.name, "valueReset"]}
fieldKey={[field.fieldKey, "valueReset"]}
shouldUpdate
>
<InputNumber
step={0.1}
min={form.getFieldValue([
"channelList",
field.fieldKey,
"valueNegative",
])}
max={form.getFieldValue([
"channelList",
field.fieldKey,
"valuePostive",
])}
/>
</Form.Item>
<Form.Item
{...field}
label="最小值"
name={[field.name, "valueNegative"]}
fieldKey={[field.fieldKey, "valueNegative"]}
>
<InputNumber
step={0.1}
min={-2}
max={form.getFieldValue([
"channelList",
field.fieldKey,
"valueReset",
])}
/>
</Form.Item>
</>
)}
</Space>
</Row>
<Collapse align="start">
<Panel header="UI 控件" size="small">
<Form.List name={[field.name, "ui"]}>
{(...props) => ui(field.fieldKey, ...props)}
</Form.List>
</Panel>
<Panel header="键盘" size="small">
<Form.List name={[field.name, "keyboard"]}>
{(...props) => keyboard(field.fieldKey, ...props)}
</Form.List>
</Panel>
<Panel header="手柄" size="small">
<Form.List name={[field.name, "gamepad"]}>
{(...props) => gamepad(field.fieldKey, ...props)}
</Form.List>
</Panel>
<Panel header="手机重力感应" size="small">
<Form.Item
{...field}
label="方向"
name={[field.name, "orientation", "axis"]}
fieldKey={[field.fieldKey, "orientation", "axis"]}
>
<Select style={{ width: 80 }} allowClear>
{[
{ name: "水平", value: "x" },
{ name: "垂直", value: "y" },
].map((i) => (
<Option key={i.value} value={i.value}>
{i.name}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
{...field}
label="系数"
name={[field.name, "orientation", "coefficient"]}
fieldKey={[field.fieldKey, "orientation", "coefficient"]}
>
<Slider defaultValue={1} max={2} min={-2} step={0.01} />
</Form.Item>
</Panel>
</Collapse>
</Card>
))}
<Form.Item>
<Button
onClick={() =>
add({
id: uuid(),
enabled: true,
valuePostive: 1,
valueNegative: -1,
valueReset: 0,
})
}
block
icon={<PlusOutlined />}
>
添加通道
</Button>
</Form.Item>
</Space>
)}
</Form.List>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
保存
</Button>
<Button
type="danger"
onClick={() => {
resetChannel();
store.remove("ui-position");
}}
>
恢复默认通道设置
</Button>
</Space>
</Form.Item>
</Form>
);
}
Example #7
Source File: SoundSetting.js From network-rc with Apache License 2.0 | 4 votes |
export default function SoundSetting({
micVolume,
audioList,
saveServerConfig,
host,
}) {
const [form] = Form.useForm();
const { data: currentSpeaker = {} } = useRequest(
`${protocol}//${host}/api/speaker/current`,
{
onSuccess: () => {
form.resetFields();
},
}
);
const { data: speakerList = [] } = useRequest(
`${protocol}//${host}/api/speaker`
);
const { run: setSpeaker } = useRequest(
() => ({
url: `${protocol}//${host}/api/speaker/set`,
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: form.getFieldValue("currentSpeakerName") }),
}),
{
manual: true,
}
);
const { run: setSpeakerVolume } = useRequest(
() => ({
url: `${protocol}//${host}/api/speaker/volume`,
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: form.getFieldValue("currentSpeakerName"),
volume: form.getFieldValue("currentSpeakerVolume"),
}),
}),
{
manual: true,
}
);
const { data: currentMic = {} } = useRequest(
`${protocol}//${host}/api/mic/current`,
{
onSuccess: () => {
form.resetFields();
},
}
);
const { data: micList = [] } = useRequest(`${protocol}//${host}/api/mic`);
const { run: setMic } = useRequest(
() => ({
url: `${protocol}//${host}/api/mic/set`,
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: form.getFieldValue("currentMicName") }),
}),
{
manual: true,
}
);
const { run: setMicVolume } = useRequest(
() => ({
url: `${protocol}//${host}/api/mic/volume`,
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: form.getFieldValue("currentMicName"),
volume: form.getFieldValue("currentMicVolume"),
}),
}),
{
manual: true,
}
);
return (
<Form
form={form}
{...layout}
initialValues={{
audioList,
currentSpeakerName: currentSpeaker?.name,
currentSpeakerVolume: currentSpeaker?.volume || 0,
currentMicName: currentMic?.name,
currentMicVolume: currentMic?.volume || 0,
}}
>
<Form.Item label="喇叭音量" name="currentSpeakerVolume">
<Slider
min={0}
max={100}
value={currentSpeaker?.volume}
onAfterChange={setSpeakerVolume}
/>
</Form.Item>
<Form.Item label="输出设备" name="currentSpeakerName">
<Select onChange={setSpeaker}>
{speakerList.map(({ name, displayName, volume }) => (
<Option key={name} value={name}>
{`${displayName}(${volume}%)`}
</Option>
))}
</Select>
</Form.Item>
<Form.Item label="麦克风音量" name="currentMicVolume">
<Slider
min={0}
max={100}
value={micVolume}
onAfterChange={setMicVolume}
/>
</Form.Item>
<Form.Item label="选择麦克风" name="currentMicName">
<Select onChange={setMic}>
{micList.map(({ name, displayName, volume }) => (
<Option key={name} value={name}>
{`${displayName}(${volume}%)`}
</Option>
))}
</Select>
</Form.Item>
<Form.Item label="快捷播放">
<Form.List name="audioList">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space
key={key}
style={{ display: "flex", marginBottom: 8 }}
align="baseline"
>
<Form.Item {...restField} name={[name, "type"]} extra="类型">
<Select onChange={setSpeaker}>
<Option key="audio" value="audio">
文件
</Option>
<Option key="test" value="text">
语音
</Option>
<Option key="stop" value="stop">
停止
</Option>
</Select>
</Form.Item>
{form.getFieldValue(["audioList", name, "type"]) ===
"audio" && (
<>
<Form.Item
{...restField}
name={[name, "name"]}
rules={[
{ required: true, message: "写个名字日后好相见" },
]}
style={{ width: 80 }}
extra="名称"
>
<Input placeholder="写个名字日后好相见" />
</Form.Item>
<Form.Item
{...restField}
name={[name, "path"]}
extra="文件在树莓派上完整路径"
>
<Input placeholder="文件路径" />
{/* <Upload /> */}
</Form.Item>
</>
)}
{form.getFieldValue(["audioList", name, "type"]) ===
"text" && (
<>
<Form.Item
{...restField}
name={[name, "text"]}
extra="语音播报文本"
>
<Input placeholder="语音播报文本" allowClear />
</Form.Item>
</>
)}
<Form.Item
{...restField}
name={[name, "keyboard"]}
style={{ width: 80 }}
extra="⌨️ 按键"
>
<Input placeholder="键盘" prefix="⌨️" />
</Form.Item>
<Form.Item
{...restField}
name={[name, "gamepadButton"]}
extra={
<span>
? 编号
<a
href="https://gamepad-tester.com"
target="_blank"
rel="noreferrer"
>
测试网页
</a>
</span>
}
>
<InputNumber min={0} max={99} />
</Form.Item>
<Form.Item
{...restField}
name={[name, "showFooter"]}
extra="在底部显示"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Button
icon={<MinusCircleOutlined />}
type="dashed"
onClick={() => remove(name)}
></Button>
</Space>
))}
<Form.Item>
<Space>
<Button
icon={<PlusCircleOutlined />}
type="dashed"
onClick={() => add({ showFooter: false })}
></Button>
<Button
type="primary"
onClick={() => {
saveServerConfig({
audioList: form.getFieldValue("audioList"),
});
}}
>
保存
</Button>
</Space>
</Form.Item>
</>
)}
</Form.List>
</Form.Item>
</Form>
);
}