| @@ -1,15 +0,0 @@ | |||||
| .auto-ml-table { | |||||
| height: 100%; | |||||
| padding: 20px @content-padding 0; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| &__filter { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| &__table { | |||||
| height: calc(100% - 32px - 28px); | |||||
| margin-top: 28px; | |||||
| } | |||||
| } | |||||
| @@ -1,305 +0,0 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-16 13:58:08 | |||||
| * @Description: 自主机器学习 | |||||
| */ | |||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment'; | |||||
| import themes from '@/styles/theme.less'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import SessionStorage from '@/utils/sessionStorage'; | |||||
| import tableCellRender, { TableCellValueType } from '@/utils/table'; | |||||
| import { modalConfirm } from '@/utils/ui'; | |||||
| import { useNavigate } from '@umijs/max'; | |||||
| import { | |||||
| App, | |||||
| Button, | |||||
| ConfigProvider, | |||||
| Input, | |||||
| Table, | |||||
| type TablePaginationConfig, | |||||
| type TableProps, | |||||
| } from 'antd'; | |||||
| import { type SearchProps } from 'antd/es/input'; | |||||
| import classNames from 'classnames'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| // import ExecuteScheduleCell from '../components/ExecuteScheduleCell'; | |||||
| import { OperationType, ServiceData } from '@/pages/AutoML/types'; | |||||
| import RunStatusCell from '../RunStatusCell'; | |||||
| import styles from './index.less'; | |||||
| function AutoMLTable() { | |||||
| const navigate = useNavigate(); | |||||
| const { message } = App.useApp(); | |||||
| const [cacheState, setCacheState] = useCacheState(); | |||||
| const [searchText, setSearchText] = useState(cacheState?.searchText); | |||||
| const [inputText, setInputText] = useState(cacheState?.searchText); | |||||
| const [tableData, setTableData] = useState<ServiceData[]>([]); | |||||
| const [total, setTotal] = useState(0); | |||||
| const [pagination, setPagination] = useState<TablePaginationConfig>( | |||||
| cacheState?.pagination ?? { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| ); | |||||
| useEffect(() => { | |||||
| getServiceList(); | |||||
| }, [pagination, searchText]); | |||||
| // 获取模型部署服务列表 | |||||
| const getServiceList = async () => { | |||||
| const params: Record<string, any> = { | |||||
| page: pagination.current! - 1, | |||||
| size: pagination.pageSize, | |||||
| service_name: searchText, | |||||
| }; | |||||
| const [res] = await to(getServiceListReq(params)); | |||||
| if (res && res.data) { | |||||
| const { content = [], totalElements = 0 } = res.data; | |||||
| setTableData(content); | |||||
| setTotal(totalElements); | |||||
| } | |||||
| }; | |||||
| // 删除模型部署 | |||||
| const deleteService = async (record: ServiceData) => { | |||||
| const [res] = await to(deleteServiceReq(record.id)); | |||||
| if (res) { | |||||
| message.success('删除成功'); | |||||
| // 如果是一页的唯一数据,删除时,请求第一页的数据 | |||||
| // 否则直接刷新这一页的数据 | |||||
| // 避免回到第一页 | |||||
| if (tableData.length > 1) { | |||||
| setPagination((prev) => ({ | |||||
| ...prev, | |||||
| current: 1, | |||||
| })); | |||||
| } else { | |||||
| getServiceList(); | |||||
| } | |||||
| } | |||||
| }; | |||||
| // 搜索 | |||||
| const onSearch: SearchProps['onSearch'] = (value) => { | |||||
| setSearchText(value); | |||||
| }; | |||||
| // 处理删除 | |||||
| const handleServiceDelete = (record: ServiceData) => { | |||||
| modalConfirm({ | |||||
| title: '删除后,该服务将不可恢复', | |||||
| content: '是否确认删除?', | |||||
| onOk: () => { | |||||
| deleteService(record); | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| // 创建、更新服务 | |||||
| const createService = (type: OperationType, record?: ServiceData) => { | |||||
| SessionStorage.setItem( | |||||
| SessionStorage.serviceInfoKey, | |||||
| { | |||||
| ...record, | |||||
| operationType: type, | |||||
| }, | |||||
| true, | |||||
| ); | |||||
| setCacheState({ | |||||
| pagination, | |||||
| searchText, | |||||
| }); | |||||
| navigate(`/modelDeployment/createService`); | |||||
| }; | |||||
| // 查看详情 | |||||
| const toDetail = (record: ServiceData) => { | |||||
| setCacheState({ | |||||
| pagination, | |||||
| searchText, | |||||
| }); | |||||
| navigate(`/modelDeployment/serviceInfo/${record.id}`); | |||||
| }; | |||||
| // 分页切换 | |||||
| const handleTableChange: TableProps<ServiceData>['onChange'] = ( | |||||
| pagination, | |||||
| _filters, | |||||
| _sorter, | |||||
| { action }, | |||||
| ) => { | |||||
| if (action === 'paginate') { | |||||
| setPagination(pagination); | |||||
| } | |||||
| }; | |||||
| const columns: TableProps<ServiceData>['columns'] = [ | |||||
| { | |||||
| title: '序号', | |||||
| dataIndex: 'index', | |||||
| key: 'index', | |||||
| width: '20%', | |||||
| render: tableCellRender(false, TableCellValueType.Index, { | |||||
| page: pagination.current! - 1, | |||||
| pageSize: pagination.pageSize!, | |||||
| }), | |||||
| }, | |||||
| { | |||||
| title: 'Trial ID', | |||||
| dataIndex: 'service_name', | |||||
| key: 'service_name', | |||||
| width: '20%', | |||||
| render: tableCellRender(false, TableCellValueType.Link, { | |||||
| onClick: toDetail, | |||||
| }), | |||||
| }, | |||||
| { | |||||
| title: '状态', | |||||
| dataIndex: 'run_status', | |||||
| key: 'run_status', | |||||
| width: '20%', | |||||
| render: RunStatusCell, | |||||
| }, | |||||
| { | |||||
| title: '最终指标', | |||||
| dataIndex: 'service_type_name', | |||||
| key: 'service_type_name', | |||||
| width: '20%', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '当前指标', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| width: '20%', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: 'lr', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| width: '20%', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: 'batch_size', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| width: '20%', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '修改时间', | |||||
| dataIndex: 'update_time', | |||||
| key: 'update_time', | |||||
| width: '20%', | |||||
| render: tableCellRender(true, TableCellValueType.Date), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '执行时长', | |||||
| dataIndex: 'description', | |||||
| key: 'description', | |||||
| width: '20%', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '操作', | |||||
| dataIndex: 'operation', | |||||
| width: 250, | |||||
| key: 'operation', | |||||
| render: (_: any, record: ServiceData) => ( | |||||
| <div> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="edit" | |||||
| icon={<KFIcon type="icon-rizhi" />} | |||||
| onClick={() => createService(OperationType.Update, record)} | |||||
| > | |||||
| 日志 | |||||
| </Button> | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="run" | |||||
| icon={<KFIcon type="icon-tingzhi" />} | |||||
| onClick={() => toDetail(record)} | |||||
| > | |||||
| 停止 | |||||
| </Button> | |||||
| <ConfigProvider | |||||
| theme={{ | |||||
| token: { | |||||
| colorLink: themes['textColorTertiary'], | |||||
| }, | |||||
| }} | |||||
| > | |||||
| <Button | |||||
| type="link" | |||||
| size="small" | |||||
| key="remove" | |||||
| icon={<KFIcon type="icon-zhongpao" />} | |||||
| onClick={() => handleServiceDelete(record)} | |||||
| > | |||||
| 重跑 | |||||
| </Button> | |||||
| </ConfigProvider> | |||||
| </div> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <div className={styles['auto-ml-table']}> | |||||
| <div className={styles['auto-ml-table__filter']}> | |||||
| <Input.Search | |||||
| placeholder="按服务名称筛选" | |||||
| onSearch={onSearch} | |||||
| onChange={(e) => setInputText(e.target.value)} | |||||
| style={{ width: 300 }} | |||||
| value={inputText} | |||||
| allowClear | |||||
| /> | |||||
| <Button | |||||
| style={{ marginRight: 0, marginLeft: 'auto' }} | |||||
| type="default" | |||||
| onClick={() => {}} | |||||
| icon={<KFIcon type="icon-shuaxin" />} | |||||
| > | |||||
| 刷新 | |||||
| </Button> | |||||
| </div> | |||||
| <div className={classNames('vertical-scroll-table', styles['auto-ml-table__table'])}> | |||||
| <Table | |||||
| dataSource={tableData} | |||||
| columns={columns} | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| pagination={{ | |||||
| ...pagination, | |||||
| total: total, | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| }} | |||||
| onChange={handleTableChange} | |||||
| rowKey="id" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default AutoMLTable; | |||||
| @@ -1,12 +1,9 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { Typography } from 'antd'; | import { Typography } from 'antd'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| export type CopyingTextProps = { | export type CopyingTextProps = { | ||||
| text: string; | text: string; | ||||
| onCopySuccess?: () => void; | |||||
| onCopyFailed?: () => void; | |||||
| }; | }; | ||||
| function CopyingText({ text }: CopyingTextProps) { | function CopyingText({ text }: CopyingTextProps) { | ||||
| @@ -46,29 +46,6 @@ function BasicConfig() { | |||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| {/* <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="可见范围" | |||||
| name="version" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择可见范围', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Select | |||||
| allowClear | |||||
| placeholder="请选择可见范围" | |||||
| options={[]} | |||||
| fieldNames={{ label: 'name', value: 'name' }} | |||||
| optionFilterProp="name" | |||||
| showSearch | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> */} | |||||
| </> | </> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -448,107 +448,6 @@ function ExecuteConfig() { | |||||
| </Form.Item> | </Form.Item> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| {/* <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="文件夹路径" | |||||
| name="tmp_folder" | |||||
| tooltip="存放配置输出和日志文件的文件夹" | |||||
| rules={[ | |||||
| { | |||||
| pattern: /^\/[a-zA-Z0-9._/-]+$/, | |||||
| message: | |||||
| '请输入正确的文件夹路径,以 / 开头,只支持字母、数字、点、下划线、中横线、斜杠', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入文件夹路径" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> */} | |||||
| {/* <Form.List name="hyper-parameter"> | |||||
| {(fields, { add, remove }) => ( | |||||
| <> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="超参数" | |||||
| style={{ marginBottom: 0, marginTop: '-14px' }} | |||||
| tooltip="超参数" | |||||
| ></Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <div className={styles['hyper-parameter']}> | |||||
| <Flex align="center" className={styles['hyper-parameter__header']}> | |||||
| <div className={styles['hyper-parameter__header__name']}>参数名称</div> | |||||
| <div className={styles['hyper-parameter__header__type']}>约束类型</div> | |||||
| <div className={styles['hyper-parameter__header__space']}>搜索空间</div> | |||||
| <div className={styles['hyper-parameter__header__operation']}>操作</div> | |||||
| </Flex> | |||||
| {fields.map(({ key, name, ...restField }, index) => ( | |||||
| <Flex key={key} align="center" className={styles['hyper-parameter__body']}> | |||||
| <Form.Item | |||||
| className={styles['hyper-parameter__body__name']} | |||||
| {...restField} | |||||
| name={[name, 'name']} | |||||
| rules={[{ required: true, message: 'Missing first name' }]} | |||||
| > | |||||
| <Input placeholder="Key" /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| className={styles['hyper-parameter__body__name']} | |||||
| {...restField} | |||||
| name={[name, 'type']} | |||||
| rules={[{ required: true, message: 'Missing last name' }]} | |||||
| > | |||||
| <Input placeholder="Value" /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| className={styles['hyper-parameter__body__name']} | |||||
| {...restField} | |||||
| name={[name, 'space']} | |||||
| rules={[{ required: true, message: 'Missing last name' }]} | |||||
| > | |||||
| <Input placeholder="Value" /> | |||||
| </Form.Item> | |||||
| <div className={styles['hyper-parameter__body__operation']}> | |||||
| <Button | |||||
| style={{ | |||||
| marginRight: '3px', | |||||
| }} | |||||
| shape="circle" | |||||
| disabled={fields.length === 1} | |||||
| type="text" | |||||
| size="middle" | |||||
| onClick={() => remove(name)} | |||||
| icon={<MinusCircleOutlined />} | |||||
| ></Button> | |||||
| {index === fields.length - 1 && ( | |||||
| <Button | |||||
| shape="circle" | |||||
| size="middle" | |||||
| type="text" | |||||
| onClick={() => add()} | |||||
| icon={<PlusCircleOutlined />} | |||||
| ></Button> | |||||
| )} | |||||
| </div> | |||||
| </Flex> | |||||
| ))} | |||||
| {fields.length === 0 && ( | |||||
| <div className={styles['hyper-parameter__add']}> | |||||
| <Button type="link" onClick={() => add()} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 添加一行 | |||||
| </Button> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| </> | |||||
| )} | |||||
| </Form.List> */} | |||||
| </> | </> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,30 +0,0 @@ | |||||
| .execute-schedule-cell { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| &__progress { | |||||
| width: 112px; | |||||
| height: 16px; | |||||
| padding: 4px 5px; | |||||
| background: rgba(96, 107, 122, 0.15); | |||||
| border-radius: 8px; | |||||
| &__bar { | |||||
| height: 7px; | |||||
| background: linear-gradient(270deg, #1664ff 0%, rgba(22, 100, 255, 0.1) 100%); | |||||
| border-radius: 9px; | |||||
| } | |||||
| } | |||||
| &__text { | |||||
| margin-left: 6px; | |||||
| color: @text-color-tertiary; | |||||
| font-size: 12px; | |||||
| letter-spacing: 2px; | |||||
| strong { | |||||
| color: @text-color; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,26 +0,0 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-10-29 18:35:41 | |||||
| * @Description: 实验实例执行进度 | |||||
| */ | |||||
| import styles from './index.less'; | |||||
| function ExecuteScheduleCell(progress?: number) { | |||||
| const width = (progress || 0) * 100 + '%'; | |||||
| return ( | |||||
| <div className={styles['execute-schedule-cell']}> | |||||
| <div className={styles['execute-schedule-cell__progress']}> | |||||
| <div | |||||
| className={styles['execute-schedule-cell__progress__bar']} | |||||
| style={{ width: width }} | |||||
| ></div> | |||||
| </div> | |||||
| {/* <span className={styles['execute-schedule-cell__text']}> | |||||
| 1/<strong>2</strong> | |||||
| </span> */} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExecuteScheduleCell; | |||||
| @@ -1,19 +0,0 @@ | |||||
| .run-status-cell { | |||||
| color: @text-color; | |||||
| &--running { | |||||
| color: @primary-color; | |||||
| } | |||||
| &--stopped { | |||||
| color: @abort-color; | |||||
| } | |||||
| &--error { | |||||
| color: @error-color; | |||||
| } | |||||
| &--pending { | |||||
| color: @warning-color; | |||||
| } | |||||
| } | |||||
| @@ -1,44 +0,0 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-18 18:35:41 | |||||
| * @Description: 实验运行状态 | |||||
| */ | |||||
| import { ServiceRunStatus } from '@/enums'; | |||||
| import styles from './index.less'; | |||||
| export type ServiceRunStatusInfo = { | |||||
| text: string; | |||||
| classname: string; | |||||
| }; | |||||
| export const statusInfo: Record<ServiceRunStatus, ServiceRunStatusInfo> = { | |||||
| [ServiceRunStatus.Init]: { | |||||
| text: '启动中', | |||||
| classname: styles['run-status-cell'], | |||||
| }, | |||||
| [ServiceRunStatus.Running]: { | |||||
| classname: styles['run-status-cell--running'], | |||||
| text: '运行中', | |||||
| }, | |||||
| [ServiceRunStatus.Stopped]: { | |||||
| classname: styles['run-status-cell--stopped'], | |||||
| text: '已停止', | |||||
| }, | |||||
| [ServiceRunStatus.Failed]: { | |||||
| classname: styles['run-status-cell--error'], | |||||
| text: '失败', | |||||
| }, | |||||
| [ServiceRunStatus.Pending]: { | |||||
| classname: styles['run-status-cell--pending'], | |||||
| text: '挂起中', | |||||
| }, | |||||
| }; | |||||
| function RunStatusCell(status?: ServiceRunStatus | null) { | |||||
| if (status === null || status === undefined || !statusInfo[status]) { | |||||
| return <span>--</span>; | |||||
| } | |||||
| return <span className={statusInfo[status].classname}>{statusInfo[status].text}</span>; | |||||
| } | |||||
| export default RunStatusCell; | |||||
| @@ -1,8 +0,0 @@ | |||||
| .status-chart { | |||||
| flex: none; | |||||
| width: 380px; | |||||
| min-width: 380px; | |||||
| background: #ffffff; | |||||
| border: 1px solid @border-color-base; | |||||
| border-radius: 4px; | |||||
| } | |||||
| @@ -1,255 +0,0 @@ | |||||
| import themes from '@/styles/theme.less'; | |||||
| import * as echarts from 'echarts'; | |||||
| import React, { useEffect, useRef } from 'react'; | |||||
| import ConfigTitle from '../ConfigTitle'; | |||||
| import styles from './index.less'; | |||||
| const colors = ['#c73131', '#6ac21d', '#1664ff', '#f0864d', '#8a8a8a']; | |||||
| const color1 = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: '#c73131' }, | |||||
| { offset: 1, color: '#ff7e96' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| const color2 = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: '#6ac21d' }, | |||||
| { offset: 1, color: '#96e850' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| const color3 = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: '#8c8c8c' }, | |||||
| { offset: 1, color: '#c8c6c6' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| const color4 = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: '#ecb934' }, | |||||
| { offset: 1, color: '#f0864d' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| const color5 = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: '#7ea9fe' }, | |||||
| { offset: 1, color: '#1664ff' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| const circleBgColor = new echarts.graphic.LinearGradient( | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 1, | |||||
| [ | |||||
| { offset: 0, color: 'rgba(255, 255, 255, 0.62)' }, | |||||
| { offset: 1, color: '#ebf2ff ' }, | |||||
| ], | |||||
| false, | |||||
| ); | |||||
| export type ExperimentStatistics = { | |||||
| Failed: number; | |||||
| Pending: number; | |||||
| Running: number; | |||||
| Succeeded: number; | |||||
| Terminated: number; | |||||
| }; | |||||
| type ExperimentChartProps = { | |||||
| style?: React.CSSProperties; | |||||
| chartData: ExperimentStatistics; | |||||
| }; | |||||
| function StatusChart({ chartData, style }: ExperimentChartProps) { | |||||
| const chartRef = useRef<HTMLDivElement>(null); | |||||
| const total = | |||||
| chartData.Failed + | |||||
| chartData.Pending + | |||||
| chartData.Running + | |||||
| chartData.Succeeded + | |||||
| chartData.Terminated; | |||||
| const options: echarts.EChartsOption = { | |||||
| title: { | |||||
| show: true, | |||||
| left: '29%', | |||||
| top: 'center', | |||||
| textAlign: 'center', | |||||
| text: [`{a|${total}}`, '{b|Trials}'].join('\n'), | |||||
| textStyle: { | |||||
| rich: { | |||||
| a: { | |||||
| color: themes['textColor'], | |||||
| fontSize: 20, | |||||
| fontWeight: 700, | |||||
| lineHeight: 28, | |||||
| }, | |||||
| b: { | |||||
| color: themes['textColorSecondary'], | |||||
| fontSize: 10, | |||||
| fontWeight: 'normal', | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| tooltip: { | |||||
| trigger: 'item', | |||||
| }, | |||||
| legend: { | |||||
| top: 'center', | |||||
| right: '5%', | |||||
| orient: 'vertical', | |||||
| icon: 'circle', | |||||
| itemWidth: 6, | |||||
| itemGap: 20, | |||||
| height: 100, | |||||
| }, | |||||
| color: colors, //[color1, color2, color3, color4, color5], | |||||
| series: [ | |||||
| { | |||||
| type: 'pie', | |||||
| radius: '80%', | |||||
| center: ['30%', '50%'], | |||||
| avoidLabelOverlap: false, | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| tooltip: { | |||||
| show: false, | |||||
| }, | |||||
| emphasis: { | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| disabled: true, | |||||
| }, | |||||
| animation: false, | |||||
| labelLine: { | |||||
| show: false, | |||||
| }, | |||||
| data: [ | |||||
| { | |||||
| value: 100, | |||||
| itemStyle: { | |||||
| color: circleBgColor, | |||||
| borderColor: 'rgba(22, 100, 255, 0.08)', | |||||
| borderWidth: 1, | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| { | |||||
| type: 'pie', | |||||
| radius: ['50%', '70%'], | |||||
| center: ['30%', '50%'], | |||||
| avoidLabelOverlap: false, | |||||
| padAngle: 3, | |||||
| itemStyle: { | |||||
| borderRadius: 0, | |||||
| }, | |||||
| minAngle: 5, | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| emphasis: { | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| }, | |||||
| labelLine: { | |||||
| show: false, | |||||
| }, | |||||
| data: [ | |||||
| { value: chartData.Failed > 0 ? chartData.Failed : undefined, name: '失败' }, | |||||
| { value: chartData.Succeeded > 0 ? chartData.Succeeded : undefined, name: '成功' }, | |||||
| { value: chartData.Terminated > 0 ? chartData.Terminated : undefined, name: '中止' }, | |||||
| { value: chartData.Pending > 0 ? chartData.Pending : undefined, name: '等待' }, | |||||
| { value: chartData.Running > 0 ? chartData.Running : undefined, name: '运行中' }, | |||||
| ], | |||||
| }, | |||||
| { | |||||
| type: 'pie', | |||||
| radius: '40%', | |||||
| center: ['30%', '50%'], | |||||
| avoidLabelOverlap: false, | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| tooltip: { | |||||
| show: false, | |||||
| }, | |||||
| emphasis: { | |||||
| label: { | |||||
| show: false, | |||||
| }, | |||||
| disabled: true, | |||||
| }, | |||||
| animation: false, | |||||
| labelLine: { | |||||
| show: false, | |||||
| }, | |||||
| data: [ | |||||
| { | |||||
| value: 100, | |||||
| itemStyle: { | |||||
| color: circleBgColor, | |||||
| borderColor: 'rgba(22, 100, 255, 0.08)', | |||||
| borderWidth: 1, | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| ], | |||||
| }; | |||||
| useEffect(() => { | |||||
| // 创建一个echarts实例,返回echarts实例 | |||||
| const chart = echarts.init(chartRef.current); | |||||
| // 设置图表实例的配置项和数据 | |||||
| chart.setOption(options); | |||||
| // 组件卸载 | |||||
| return () => { | |||||
| // myChart.dispose() 销毁实例 | |||||
| chart.dispose(); | |||||
| }; | |||||
| }, []); | |||||
| return ( | |||||
| <div className={styles['status-chart']} style={style}> | |||||
| <ConfigTitle title="Trial 状态统计" /> | |||||
| <div style={{ width: '100%', height: '185px' }} ref={chartRef}></div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default StatusChart; | |||||