feat(component): 新增组件表单与提交功能(接口设计未完成)

master
钟良源 3 months ago
parent cd9fce74b5
commit c986114e75

@ -7,3 +7,15 @@ const urlPrefix = '/api/v1/bpms-workbench';
export function getMyComponentList(params) { export function getMyComponentList(params) {
return axios.get(`${urlPrefix}/componentBase/list`, { params }); return axios.get(`${urlPrefix}/componentBase/list`, { params });
} }
export function getTagList() {
return axios.get(`${urlPrefix}/componentBase/tags`);
}
export function compProjectValidate(projectId) {
return axios.post(`${urlPrefix}/componentBase/validate?projectId=${projectId}`);
}
export function compSubmit(params) {
return axios.post(`${urlPrefix}/componentBase/submit`, params);
}

@ -1,9 +1,29 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Grid, Space, Divider, Button, Table, TableColumnProps } from '@arco-design/web-react'; import {
Modal,
Form,
Input,
Grid,
Space,
Divider,
Button,
Table,
TableColumnProps,
Select,
Message,
Upload,
Progress
} from '@arco-design/web-react';
import { IconPlus, IconEdit } from '@arco-design/web-react/icon';
import styles from './style/addComponentModal.module.less'; import styles from './style/addComponentModal.module.less';
import Cover from '@/pages/scene/cover'; import Cover from '@/pages/scene/cover';
import EditorSection from '@/components/EditorSection';
import { getComponentClassify } from '@/api/componentClassify';
import { compProjectValidate, compSubmit, getTagList } from '@/api/componentBase';
const FormItem = Form.Item; const FormItem = Form.Item;
const Option = Select.Option;
const columns: TableColumnProps[] = [ const columns: TableColumnProps[] = [
{ {
@ -34,32 +54,177 @@ const data = [
]; ];
const AddComponentModal = ({ visible, setVisible }) => { const AddComponentModal = ({ visible, setVisible, onReFresh }) => {
const [selectedImage, setSelectedImage] = useState(''); const [selectedImage, setSelectedImage] = useState('');
const [description, setDescription] = useState('');
const [classifyList, setClassifyList] = useState([]);
const [showSaveBtn, setShowSaveBtn] = useState(false);
const [tagsList, setTagsList] = useState([]);
const [componentData, setComponentData] = useState({});
const [file, setFile] = useState(null);
const [form] = Form.useForm(); const [form] = Form.useForm();
const transformImageUrl = (image: string) => { const cs = `arco-upload-list-item${file && file.status === 'error' ? ' is-error' : ''}`;
if (!image) return;
if (image.includes('/')) setSelectedImage(image.split('/')[image.split('/').length - 1]);
else setSelectedImage(image); const getComponentClassifyList = async () => {
const res: any = await getComponentClassify('component');
if (res.code === 200) {
const data = [];
res.data.forEach((item) => {
data.push({
label: item.classifyName,
value: item.id
});
});
setClassifyList(data);
}
};
const getTageList = async () => {
const res: any = await getTagList();
if (res.code === 200) setTagsList(res.data);
};
const validateProjectId = async (projectId: string) => {
if (!projectId) return;
try {
const res = await compProjectValidate(projectId);
if (res.data === false) {
// 项目标识已存在,设置表单字段错误
form.setFields({
projectId: {
value: projectId,
error: {
message: '项目标识已存在'
}
}
});
}
else {
// 项目标识可用,清除错误
form.setFields({
projectId: {
value: projectId,
error: null
}
});
}
} catch (error) {
// API调用出错
form.setFields({
projectId: {
value: projectId,
error: {
message: '验证项目标识时发生错误'
}
}
});
}
};
const onSubmit = async () => {
try {
await form.validate();
const formData = form.getFields();
const params = {
name: formData.name,
projectId: formData.projectId,
logoUrl: selectedImage,
desc: description,
componentClassify: formData.componentClassify,
codeLanguage: formData.codeLanguage === 'Java:8' ? 'Java' : 'Python',
type: formData.type === '普通组件' ? 'normal' : 'loop',
tags: formData.tags
}; };
const res: any = await compSubmit(params);
if (res.code === 200) {
setComponentData(res.data);
setShowSaveBtn(true);
Message.success('组件信息提交完成,可继续组件接口设计');
onReFresh();
}
else {
Message.error('组件信息提交失败');
}
} catch (error) {
}
};
useEffect(() => {
getComponentClassifyList();
getTageList();
}, []);
const modalFooter = () => { const modalFooter = () => {
return ( return (
<Space size={30}> <Space size={30}>
<Button size="small" type="secondary" style={{ borderRadius: 5 }}></Button> <Button size="small" type="outline" style={{ borderRadius: 5 }} onClick={() => setVisible(false)}></Button>
<Button size="small" type="outline" style={{ borderRadius: 5 }}></Button> {showSaveBtn &&
<Button size="small" type="primary" style={{ borderRadius: 5 }}></Button> <Button size="small" type="primary" style={{ borderRadius: 5 }} onClick={() => onSubmit()}></Button>}
{!showSaveBtn && <Button size="small" type="primary" style={{ borderRadius: 5 }}
onClick={() => onSubmit()}></Button>}
</Space> </Space>
); );
}; };
const UploadImage = () => {
return (
<Upload
action="/api/v1/bpms-workbench/fileSystem/fileUpload"
fileList={file ? [file] : []}
showUploadList={false}
onChange={(_, currentFile: any) => {
setFile({
...currentFile,
url: URL.createObjectURL(currentFile.originFile)
});
if (currentFile.status === 'done') setSelectedImage(currentFile.response.data.link);
}}
onProgress={(currentFile) => {
setFile(currentFile);
}}
>
<div className={cs}>
{file && file.url ? (
<div className="arco-upload-list-item-picture custom-upload-avatar">
<img src={file.url} />
<div className="arco-upload-list-item-picture-mask">
<IconEdit />
</div>
{file.status === 'uploading' && file.percent < 100 && (
<Progress
percent={file.percent}
type="circle"
size="mini"
style={{
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translateX(-50%) translateY(-50%)'
}}
/>
)}
</div>
) : (
<div className="arco-upload-trigger-picture">
<div className="arco-upload-trigger-picture-text">
<IconPlus />
</div>
</div>
)}
</div>
</Upload>
);
};
return ( return (
<Modal <Modal
className={styles['add-component-modal']} className={styles['add-component-modal']}
title="新增组件" title="新增组件"
visible={visible} visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
autoFocus={false} autoFocus={false}
focusLock={true} focusLock={true}
style={{ width: '60%' }} style={{ width: '60%' }}
@ -68,12 +233,8 @@ const AddComponentModal = ({ visible, setVisible }) => {
<Form form={form} className={styles['add-component-container']}> <Form form={form} className={styles['add-component-container']}>
<div className={styles['first-half']}> <div className={styles['first-half']}>
<div className={styles['component-preview']}> <div className={styles['component-preview']}>
<FormItem label="图标:"> <FormItem label="图标:" field="logoUrl">
<Cover <UploadImage />
defaultImage={selectedImage}
imgWidth={100}
onImageChange={(selectedImage) => transformImageUrl(selectedImage)}
/>
</FormItem> </FormItem>
<FormItem label="组件预览:"> <FormItem label="组件预览:">
<div <div
@ -83,7 +244,6 @@ const AddComponentModal = ({ visible, setVisible }) => {
border: '1px solid #dcdfe6', border: '1px solid #dcdfe6',
borderRadius: 5 borderRadius: 5
}} }}
> >
</div> </div>
</FormItem> </FormItem>
@ -91,53 +251,152 @@ const AddComponentModal = ({ visible, setVisible }) => {
<div className={styles['component-info']}> <div className={styles['component-info']}>
<Grid.Row gutter={8}> <Grid.Row gutter={8}>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="名称:" field="name" required rules={[
{
validator(value, cb) {
if (!value) {
return cb('请输入名称');
}
return cb();
}
}
]}>
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> <Input style={{ width: '90%' }} allowClear placeholder="请输入名称" />
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="代码标识:" field="projectId" required rules={[
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> {
validator(value, cb) {
if (!value) {
return cb('请输入代码标识');
}
return cb();
}
}
]}>
<Input
style={{ width: '90%' }}
allowClear
placeholder="请输入代码标识"
onChange={(e) => validateProjectId(e)}
/>
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
<Grid.Row gutter={8}> <Grid.Row gutter={8}>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="分类:" field="componentClassify" required rules={[
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> {
validator(value, cb) {
if (!value) {
return cb('请选择分类');
}
return cb();
}
}
]}>
<Select
placeholder="请选择分类"
style={{ width: '90%' }}
>
{classifyList.map((option, index) => (
<Option key={option.id} value={option.label}>
{option.label}
</Option>
))}
</Select>
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="组件语言:" field="codeLanguage" required rules={[
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> {
validator(value, cb) {
if (!value) {
return cb('请选择组件语言');
}
return cb();
}
}
]}>
<Select
placeholder="请选择组件语言"
style={{ width: '90%' }}
>
{['Java:8', 'Python:3.10.12'].map((option, index) => (
<Option key={option} disabled={index === 3} value={option}>
{option}
</Option>
))}
</Select>
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
<Grid.Row gutter={8}> <Grid.Row gutter={8}>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="标签:" field="tags">
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> <Select
placeholder="请选择标签"
allowCreate
mode="multiple"
style={{ width: '90%' }}
>
{tagsList.map((option, index) => (
<Option key={option.value} value={option.value}>
{option.label}
</Option>
))}
</Select>
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="名称:"> <FormItem label="组件类型:" field="type" required rules={[
<Input style={{ width: '90%' }} allowClear placeholder="请输入名称" /> {
validator(value, cb) {
if (!value) {
return cb('请选择组件类型');
}
return cb();
}
}
]}>
<Select
placeholder="请选择组件类型"
style={{ width: '90%' }}
>
{['普通组件', '监听组件'].map((option, index) => (
<Option key={option} disabled={index === 3} value={option}>
{option}
</Option>
))}
</Select>
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
<FormItem label="名称:">
<div className={styles['markdown-editor']}>
</FormItem> <div className={styles['markdown-label']}></div>
<EditorSection initialContent={description} />
</div> </div>
</div> </div>
<div className={styles['last-half']}> </div>
{showSaveBtn && <div className={styles['last-half']}>
<div className={styles['last-half-header']}> <div className={styles['last-half-header']}>
<p> </p> <p> </p>
<Space split={<Divider type="vertical" />}>
<Button size="small" type="secondary" style={{ borderRadius: 5 }}></Button>
<Button size="mini" type="primary" style={{ borderRadius: 5 }}>+ </Button> <Button size="mini" type="primary" style={{ borderRadius: 5 }}>+ </Button>
</Space>
</div> </div>
<Table columns={columns} data={data} pagination={false} /> <Table columns={columns} data={data} pagination={false} />
</div> </div>}
</Form> </Form>
</Modal> </Modal>
); );

@ -93,12 +93,12 @@ const GlobalVarContainer = () => {
pageSize: pagination.pageSize pageSize: pagination.pageSize
}); });
setComponentData(res.list); setComponentData(res.data.list);
setPagination({ setPagination({
totalCount: res.totalCount, totalCount: res.data.totalCount,
pageSize: res.pageSize, pageSize: res.data.pageSize,
totalPage: res.totalPage, totalPage: res.data.totalPage,
currPage: res.currPage currPage: res.data.currPage
}); });
} catch (error) { } catch (error) {
console.error('获取组件列表失败:', error); console.error('获取组件列表失败:', error);
@ -201,6 +201,7 @@ const GlobalVarContainer = () => {
<AddComponentModal <AddComponentModal
visible={visible} visible={visible}
setVisible={setVisible} setVisible={setVisible}
onReFresh={fetchComponentData}
/> />
</> </>
); );

@ -31,6 +31,18 @@
border: 1px solid transparent; border: 1px solid transparent;
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
.markdown-label {
font-size: 14px;
white-space: normal;
color: var(--color-text-2);
margin-bottom: 6px;
}
.markdown-editor {
padding-left: 50px;
padding-right: 40px;
}
} }
} }

Loading…
Cancel
Save