feat: 完成代码配置
This commit is contained in:
parent
ed3a9304bf
commit
5bdf3d247f
|
@ -198,6 +198,17 @@ export default [
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '代码配置',
|
||||
path: 'codeConfig',
|
||||
routes: [
|
||||
{
|
||||
name: '代码配置',
|
||||
path: '',
|
||||
component: './CodeConfig/List',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
.code-config-list {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
padding: 20px 0;
|
||||
background: white;
|
||||
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 32px;
|
||||
margin-bottom: 30px;
|
||||
padding: 0 30px;
|
||||
color: @text-color;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
align-content: flex-start;
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
padding: 0 30px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-pagination {
|
||||
margin-right: 30px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
import KFIcon from '@/components/KFIcon';
|
||||
import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig';
|
||||
import { openAntdModal } from '@/utils/modal';
|
||||
import { to } from '@/utils/promise';
|
||||
import { modalConfirm } from '@/utils/ui';
|
||||
import { App, Button, Empty, Input, Pagination, PaginationProps } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import AddCodeConfigModal, { OperationTypeEnum } from '../components/AddCodeConfigModal';
|
||||
import CodeConfigItem from '../components/CodeConfigItem';
|
||||
import styles from './index.less';
|
||||
|
||||
// 代码配置数据
|
||||
export type CodeConfigData = {
|
||||
id: number;
|
||||
code_repo_name: string;
|
||||
code_repo_vis: number;
|
||||
git_url: string;
|
||||
git_branch: string;
|
||||
git_user_name: string;
|
||||
git_password: string;
|
||||
ssh_key: string;
|
||||
verify_mode: number;
|
||||
create_by: string;
|
||||
create_time: string;
|
||||
update_by: string;
|
||||
update_time: string;
|
||||
};
|
||||
|
||||
export type ResourceListRef = {
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
function CodeConfigList() {
|
||||
const [dataList, setDataList] = useState<CodeConfigData[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [pagination, setPagination] = useState<PaginationProps>({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
const [searchText, setSearchText] = useState<string | undefined>(undefined);
|
||||
const [inputText, setInputText] = useState<string | undefined>(undefined);
|
||||
const { message } = App.useApp();
|
||||
|
||||
useEffect(() => {
|
||||
getDataList();
|
||||
}, [pagination, searchText]);
|
||||
|
||||
// 获取数据请求
|
||||
const getDataList = async () => {
|
||||
const params = {
|
||||
page: pagination.current! - 1,
|
||||
size: pagination.pageSize,
|
||||
code_repo_name: searchText !== '' ? searchText : undefined,
|
||||
};
|
||||
const [res] = await to(getCodeConfigListReq(params));
|
||||
if (res && res.data && res.data.content) {
|
||||
setDataList(res.data.content);
|
||||
setTotal(res.data.totalElements);
|
||||
}
|
||||
};
|
||||
|
||||
// 删除请求
|
||||
const deleteRecord = async (id: number) => {
|
||||
const [res] = await to(deleteCodeConfigReq(id));
|
||||
if (res) {
|
||||
getDataList();
|
||||
message.success('删除成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const handleSearch = (value: string) => {
|
||||
setSearchText(value);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleRemove = (record: CodeConfigData) => {
|
||||
modalConfirm({
|
||||
title: '确定删除这个代码配置吗?',
|
||||
onOk: () => {
|
||||
deleteRecord(record.id);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 修改
|
||||
const handleClick = (record: CodeConfigData) => {
|
||||
const { close } = openAntdModal(AddCodeConfigModal, {
|
||||
opType: OperationTypeEnum.Update,
|
||||
codeConfigData: record,
|
||||
onOk: () => {
|
||||
getDataList();
|
||||
close();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 新建
|
||||
const createCodeConfig = () => {
|
||||
const { close } = openAntdModal(AddCodeConfigModal, {
|
||||
opType: OperationTypeEnum.Create,
|
||||
onOk: () => {
|
||||
getDataList();
|
||||
close();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 分页切换
|
||||
const handlePageChange: PaginationProps['onChange'] = (page, pageSize) => {
|
||||
setPagination({
|
||||
current: page,
|
||||
pageSize: pageSize,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['code-config-list']}>
|
||||
<div className={styles['code-config-list__header']}>
|
||||
<span>数据总数:{total}个</span>
|
||||
<div>
|
||||
<Input.Search
|
||||
placeholder="按代码仓库名称筛选"
|
||||
allowClear
|
||||
onSearch={handleSearch}
|
||||
style={{
|
||||
width: 300,
|
||||
}}
|
||||
onChange={(e) => setInputText(e.target.value)}
|
||||
value={inputText}
|
||||
/>
|
||||
<Button
|
||||
type="default"
|
||||
style={{ marginLeft: '20px' }}
|
||||
onClick={createCodeConfig}
|
||||
icon={<KFIcon type="icon-xinjian2" />}
|
||||
>
|
||||
新建代码配置
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{dataList?.length !== 0 ? (
|
||||
<>
|
||||
<div className={styles['code-config-list__content']}>
|
||||
{dataList?.map((item) => (
|
||||
<CodeConfigItem
|
||||
item={item}
|
||||
key={item.id}
|
||||
onRemove={handleRemove}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Pagination
|
||||
total={total}
|
||||
showSizeChanger
|
||||
defaultPageSize={20}
|
||||
pageSizeOptions={[20, 40, 60, 80, 100]}
|
||||
showQuickJumper
|
||||
onChange={handlePageChange}
|
||||
{...pagination}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<div className={styles['code-config-list__empty']}>
|
||||
<Empty></Empty>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CodeConfigList;
|
|
@ -0,0 +1,248 @@
|
|||
import KFModal from '@/components/KFModal';
|
||||
import { type CodeConfigData } from '@/pages/CodeConfig/List';
|
||||
import { addCodeConfigReq, updateCodeConfigReq } from '@/services/codeConfig';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Form, Input, Radio, message, type ModalProps } from 'antd';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
export enum RepoVisibleEnum {
|
||||
Private = 0, // 私有
|
||||
Public = 1, // 公开
|
||||
}
|
||||
|
||||
export enum VerifyModeEnum {
|
||||
Password = 0, // 用户名密码
|
||||
SSH = 1, // SSH Key
|
||||
}
|
||||
|
||||
export enum OperationTypeEnum {
|
||||
Create = 0, // 新建
|
||||
Update = 1, // 更新
|
||||
}
|
||||
|
||||
type FormData = Partial<CodeConfigData>;
|
||||
|
||||
interface AddCodeConfigModalProps extends Omit<ModalProps, 'onOk'> {
|
||||
opType: OperationTypeEnum;
|
||||
codeConfigData?: CodeConfigData;
|
||||
onOk: () => void;
|
||||
}
|
||||
|
||||
function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeConfigModalProps) {
|
||||
// 上传请求
|
||||
const createCodeConfig = async (formData: FormData) => {
|
||||
const params: FormData & { id?: number } = {
|
||||
...formData,
|
||||
};
|
||||
// 清除多余的信息
|
||||
if (formData.code_repo_vis === RepoVisibleEnum.Public) {
|
||||
omit(params, ['verify_mode', 'git_user_name', 'git_password', 'ssh_key']);
|
||||
}
|
||||
if (formData.verify_mode === VerifyModeEnum.Password) {
|
||||
omit(params, ['ssh_key']);
|
||||
} else if (formData.verify_mode === VerifyModeEnum.SSH) {
|
||||
omit(params, ['git_user_name', 'git_password']);
|
||||
}
|
||||
if (opType === OperationTypeEnum.Update) {
|
||||
params.id = codeConfigData?.id;
|
||||
}
|
||||
const request = opType === OperationTypeEnum.Create ? addCodeConfigReq : updateCodeConfigReq;
|
||||
const [res] = await to(request(params));
|
||||
if (res) {
|
||||
message.success(opType === OperationTypeEnum.Create ? '创建成功' : '修改成功');
|
||||
onOk?.();
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const onFinish = (formData: FormData) => {
|
||||
createCodeConfig(formData);
|
||||
};
|
||||
|
||||
// 设置初始值
|
||||
const initialValues: FormData = codeConfigData ?? {
|
||||
code_repo_vis: RepoVisibleEnum.Public,
|
||||
verify_mode: VerifyModeEnum.Password,
|
||||
};
|
||||
if (initialValues.verify_mode === undefined || initialValues.verify_mode === null) {
|
||||
initialValues.verify_mode = VerifyModeEnum.Password;
|
||||
}
|
||||
|
||||
return (
|
||||
<KFModal
|
||||
{...rest}
|
||||
title="新建代码配置"
|
||||
image={require('@/assets/img/create-experiment.png')}
|
||||
width={825}
|
||||
okButtonProps={{
|
||||
htmlType: 'submit',
|
||||
form: 'form',
|
||||
}}
|
||||
destroyOnClose
|
||||
>
|
||||
<Form
|
||||
name="form"
|
||||
layout="vertical"
|
||||
onFinish={onFinish}
|
||||
initialValues={initialValues}
|
||||
autoComplete="off"
|
||||
>
|
||||
{/* 禁止 Chrome 自动填充 */}
|
||||
{/* <Input type="text" style={{ display: 'none' }} />
|
||||
<Input type="password" style={{ display: 'none' }} /> */}
|
||||
<Form.Item
|
||||
label="代码仓库名称"
|
||||
name="code_repo_name"
|
||||
required
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入代码仓库名称',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入代码仓库名称" showCount allowClear maxLength={64} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="代码仓库可见性"
|
||||
name="code_repo_vis"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择代码仓库可见性',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value={RepoVisibleEnum.Public}>公开</Radio>
|
||||
<Radio value={RepoVisibleEnum.Private}>私有</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Git 地址"
|
||||
name="git_url"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入 Git 地址',
|
||||
},
|
||||
{
|
||||
type: 'url',
|
||||
message: '请输入正确的 Git 地址',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入 Git 地址" showCount allowClear maxLength={256} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="代码分支/Tag"
|
||||
name="git_branch"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入代码分支/Tag',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入代码分支/Tag" showCount allowClear maxLength={64} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(prevValues, currentValues) =>
|
||||
prevValues?.code_repo_vis !== currentValues?.code_repo_vis
|
||||
}
|
||||
>
|
||||
{({ getFieldValue }) => {
|
||||
return getFieldValue('code_repo_vis') === RepoVisibleEnum.Private ? (
|
||||
<>
|
||||
<Form.Item
|
||||
label="验证方式"
|
||||
name="verify_mode"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择验证方式',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value={VerifyModeEnum.Password}>用户名/密码</Radio>
|
||||
<Radio value={VerifyModeEnum.SSH}>SSH Key</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(prevValues, currentValues) =>
|
||||
prevValues?.verify_mode !== currentValues?.verify_mode
|
||||
}
|
||||
>
|
||||
{({ getFieldValue }) => {
|
||||
return getFieldValue('verify_mode') === VerifyModeEnum.Password ? (
|
||||
<>
|
||||
<Form.Item
|
||||
label="Git 用户名"
|
||||
name="git_user_name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入 Git 用户名',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入 Git 用户名"
|
||||
autoComplete="off"
|
||||
showCount
|
||||
allowClear
|
||||
maxLength={64}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Git 密码"
|
||||
name="git_password"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入 Git 密码',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.Password
|
||||
autoComplete="new-password"
|
||||
placeholder="请输入 Git 密码"
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
) : (
|
||||
<Form.Item
|
||||
label="SSH Key"
|
||||
name="ssh_key"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入 SSH Key',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea
|
||||
placeholder="请输入 SSH Key"
|
||||
showCount
|
||||
maxLength={1024}
|
||||
autoSize={{ minRows: 3, maxRows: 6 }}
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</KFModal>
|
||||
);
|
||||
}
|
||||
|
||||
export default AddCodeConfigModal;
|
|
@ -0,0 +1,68 @@
|
|||
.code-config-item {
|
||||
position: relative;
|
||||
width: calc(25% - 15px);
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
@media screen and (max-width: 1860px) {
|
||||
& {
|
||||
width: calc(33.33% - 13.33px);
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
margin: 0 10px 0 0 !important;
|
||||
color: @text-color;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&__url {
|
||||
margin-bottom: 10px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
height: 44px;
|
||||
margin-bottom: 20px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 14px;
|
||||
.multiLine(2);
|
||||
}
|
||||
|
||||
&__time {
|
||||
display: flex;
|
||||
flex: 0 1 content;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
color: #808080;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @primary-color;
|
||||
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.resource-item__name {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.resource-item__name {
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%);
|
||||
content: '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import clock from '@/assets/img/clock.png';
|
||||
import creatByImg from '@/assets/img/creatBy.png';
|
||||
import KFIcon from '@/components/KFIcon';
|
||||
import { type CodeConfigData } from '@/pages/CodeConfig/List';
|
||||
import { formatDate } from '@/utils/date';
|
||||
import { Button, Flex, Typography } from 'antd';
|
||||
import styles from './index.less';
|
||||
|
||||
type CodeConfigItemProps = {
|
||||
item: CodeConfigData;
|
||||
onClick: (item: CodeConfigData) => void;
|
||||
onRemove: (item: CodeConfigData) => void;
|
||||
};
|
||||
|
||||
function CodeConfigItem({ item, onClick, onRemove }: CodeConfigItemProps) {
|
||||
return (
|
||||
<div className={styles['code-config-item']} onClick={() => onClick(item)}>
|
||||
<Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}>
|
||||
<Typography.Paragraph
|
||||
className={styles['code-config-item__name']}
|
||||
ellipsis={{ tooltip: item.code_repo_name }}
|
||||
>
|
||||
{item.code_repo_name}
|
||||
</Typography.Paragraph>
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRemove(item);
|
||||
}}
|
||||
>
|
||||
<KFIcon type="icon-shanchu" font={17} />
|
||||
</Button>
|
||||
</Flex>
|
||||
<div className={styles['code-config-item__description']}>{item.git_url}</div>
|
||||
<Flex justify="space-between">
|
||||
<div className={styles['code-config-item__time']}>
|
||||
<img style={{ width: '17px', marginRight: '6px' }} src={creatByImg} alt="" />
|
||||
<span>{item.create_by}</span>
|
||||
</div>
|
||||
<div className={styles['code-config-item__time']}>
|
||||
<img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" />
|
||||
<span>最近更新: {formatDate(item.update_time, 'YYYY-MM-DD')}</span>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CodeConfigItem;
|
|
@ -9,7 +9,7 @@ import { App, Button, Input, Pagination, PaginationProps } from 'antd';
|
|||
import { Ref, forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||
import { CategoryData, ResourceData, ResourceType, resourceConfig } from '../../config';
|
||||
import AddDatasetModal from '../AddDatasetModal';
|
||||
import ResourceItem from '../Resourcetem';
|
||||
import ResourceItem from '../ResourceItem';
|
||||
import styles from './index.less';
|
||||
|
||||
export type ResourceListRef = {
|
||||
|
@ -161,7 +161,7 @@ function ResourceList(
|
|||
<span>数据总数:{total}个</span>
|
||||
<div>
|
||||
<Input.Search
|
||||
placeholder="按数据名称筛选"
|
||||
placeholder={`按${config.name}名称筛选`}
|
||||
allowClear
|
||||
onSearch={handleSearch}
|
||||
style={{
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import { request } from '@umijs/max';
|
||||
|
||||
// 分页查询代码配置
|
||||
export function getCodeConfigListReq(params) {
|
||||
return request(`/api/mmp/codeConfig`, {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// 新增代码配置
|
||||
export function addCodeConfigReq(data) {
|
||||
return request(`/api/mmp/codeConfig`, {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 更新代码配置
|
||||
export function updateCodeConfigReq(data) {
|
||||
return request(`/api/mmp/codeConfig`, {
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除代码配置
|
||||
export function deleteCodeConfigReq(id) {
|
||||
return request(`/api/mmp/codeConfig/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
// 查询代码配置详情
|
||||
export function getCodeConfigDetailReq(id) {
|
||||
return request(`/api/mmp/codeConfig/${id}`, {
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue