Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature-789][admin,web] One click online and offline operation #788

Merged
merged 16 commits into from
Jul 28, 2022
Prev Previous commit
Next Next commit
feat:上下线状态明细批量执行开发
  • Loading branch information
mydq committed Jul 27, 2022
commit 99ca4f7884953c967bf8a35d1336954cabc9b76d
134 changes: 118 additions & 16 deletions dlink-web/src/pages/DevOps/JobInstanceTable/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,110 @@
import {history} from 'umi';
import {queryData} from "@/components/Common/crud";
import React, {useEffect, useRef, useState} from "react";
import type {ActionType, ProColumns} from '@ant-design/pro-table';
import {useState, useRef, useEffect} from "react";
import type {ProColumns, ActionType} from '@ant-design/pro-table';
import ProTable from "@ant-design/pro-table";
import {Badge, message} from 'antd'
import {JobInstanceTableListItem} from "@/pages/DevOps/data";
import moment from 'moment';
import {RUN_MODE} from "@/components/Studio/conf";
import JobStatus from "@/components/Common/JobStatus";
import JobLifeCycle, {JOB_LIFE_CYCLE} from "@/components/Common/JobLifeCycle";
import {parseSecondStr} from "@/components/Common/function";
import OpsStatusModal from "../OpsStatusModal/index";
import StatusDetailedModal from "../StatusDetailedModal/index";
import {
queryOneClickOperatingTaskStatus,
onClickOperatingTask,
queryAllCatalogue
} from "@/pages/DevOps/service";

const OPS_STATUS_COLOR = {
success: 'lime',
padding: 'yellow',

}
const url = '/api/jobInstance';
const JobInstanceTable = (props: any) => {

const {status, activeKey,isHistory, dispatch} = props;
const {status, activeKey, isHistory, taskStatus} = props;
const [time, setTime] = useState(() => Date.now());
const [opsStatusVisible, setOpsStatusVisible] = useState<boolean>(false);
const [opsStatus, setOpsStatus] = useState<string>('');
const [opsStatusListTree, setOpsStatusListTree] = useState<any[]>([]);
const [statusDetailedVisible, setStatusDetailedVisible] = useState<boolean>(false);
const [statusDetailedList, setStatusDetailedList] = useState<any[]>([]);
const ref = useRef<ActionType>();

useEffect(() => {
ref?.current?.reload();
}, [isHistory]);

/**
* oGoOnline 状态上下线
* */
// eslint-disable-next-line @typescript-eslint/no-shadow
const onStatusChange = async (status: string) => {
try {
const {datas} = await queryAllCatalogue({operating: status})
setOpsStatusListTree([datas])
setOpsStatusVisible(true)
setOpsStatus(status);
} catch (e) {
console.log(e)
}
}

/**
* onOpsStatusCallBack 上下线提交操作
* */
const onOpsStatusCallBack = async (values?: any) => {
if (values) {
try {
await onClickOperatingTask(values)
message.success('操作成功')
setOpsStatusVisible(false)
} catch (e) {
console.log(e)
}
} else {
setOpsStatusVisible(false)
}
}

/**
* onOfflineDetailed 上下线明细详情
* */
// eslint-disable-next-line @typescript-eslint/no-shadow
const onStatusDetailed = async (status: string) => {
const {datas} = await queryOneClickOperatingTaskStatus()
datas.online = datas.online.map(({task, ...rest}: any) => {
return {
...task,
...rest
}
})
datas.offline = datas.offline.map(({task, ...rest}: any) => {
return {
...task,
...rest
}
})
const newStatusData = status === '1' ? datas.online : datas.offline
setStatusDetailedList(newStatusData)
setStatusDetailedVisible(true)
setOpsStatus(status);
}
/**
* onCancelStatusDetailed 上下线明细弹窗关闭回调
* */
const onCancelStatusDetailed = () => {
setStatusDetailedVisible(false)
}

const getColumns = () => {
const columns: ProColumns<JobInstanceTableListItem>[] = [{
const columns: ProColumns<JobInstanceTableListItem>[] = [{
title: "作业名",
dataIndex: "name",
sorter: true,
},{
}, {
title: "生命周期",
dataIndex: "step",
sorter: true,
Expand All @@ -53,7 +131,7 @@ const JobInstanceTable = (props: any) => {
render: (_, row) => {
return (<JobLifeCycle step={row.step}/>);
}
},{
}, {
title: "运行模式",
dataIndex: "type",
sorter: true,
Expand Down Expand Up @@ -89,11 +167,11 @@ const JobInstanceTable = (props: any) => {
status: RUN_MODE.KUBERNETES_APPLICATION,
},
},
},{
}, {
title: "集群实例",
dataIndex: "clusterAlias",
sorter: true,
},{
}, {
title: "作业ID",
dataIndex: "jid",
key: "jid",
Expand Down Expand Up @@ -129,33 +207,50 @@ const JobInstanceTable = (props: any) => {
hideInSearch: true,
}, {
title: "耗时",
dataIndex: "duration",
sorter: true,
valueType: 'second',
hideInSearch: true,
render: (_, row) => {
return parseSecondStr(row.duration);
}
},];
return columns;
};

return (
<><ProTable
actionRef={ref}
toolBarRender={() => [<Badge
color={taskStatus?.onlineStatus ? OPS_STATUS_COLOR.padding : OPS_STATUS_COLOR.success} text={<a
onClick={() => {
onStatusChange('1')
}}>一键上线</a>}/>,
<a
style={{color: taskStatus?.onlineStatus ? '#FF0000' : '#1E90FF'}}
onClick={() => {
onStatusDetailed('1')
}}>上线明细</a>,
<Badge color={taskStatus?.offlineStatus ? OPS_STATUS_COLOR.padding : OPS_STATUS_COLOR.success}
text={<a onClick={() => {
onStatusChange('2')
}}>一键下线</a>}/>, <a
style={{color: taskStatus?.onlineStatus ? '#FF0000' : '#1E90FF'}}
onClick={() => {
onStatusDetailed('2')
}}>下线明细</a>,]}
request={(params, sorter, filter) => {
setTime(Date.now());
return queryData(url, {...params,status,isHistory, sorter: {id: 'descend'}, filter});
return queryData(url, {...params, status, isHistory, sorter: {id: 'descend'}, filter});
}}
columns={getColumns()}
size="small"
search={{
filterType: 'light',
}}
headerTitle={`上次更新时间:${moment(time).format('HH:mm:ss')}`}
polling={status==activeKey?3000:undefined}
polling={status == activeKey ? 3000 : undefined}
pagination={{
pageSize: 5,
}}
onRow={ record => {
onRow={record => {
return {
onClick: event => {
history.push({
Expand All @@ -168,6 +263,13 @@ const JobInstanceTable = (props: any) => {
};
}}
/>
<OpsStatusModal opsStatusListTree={opsStatusListTree} opsStatusVisible={opsStatusVisible} opsStatus={opsStatus}
onOpsStatusCallBack={onOpsStatusCallBack}/>
<StatusDetailedModal opsStatus={opsStatus} statusDetailedList={statusDetailedList}
statusDetailedVisible={statusDetailedVisible}
onCancelStatusDetailed={onCancelStatusDetailed}
/>

</>
);
};
Expand Down
173 changes: 173 additions & 0 deletions dlink-web/src/pages/DevOps/OpsStatusModel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import React, {useState, useRef, useEffect} from 'react'
import {Modal, Card, Select, Checkbox, Form, Divider, Row, Col, TreeSelect, Button} from 'antd'
import {queryOnClickOperatingTask} from '../service'
import type {CheckboxChangeEvent} from 'antd/es/checkbox';
import type {CheckboxValueType} from 'antd/es/checkbox/Group';

interface IOpsStatusModalProps {
opsStatusVisible: boolean;
opsStatus: string;
opsStatusListTree: any;
onOpsStatusCallBack: (values?: any) => void
}

export const OpsStatusLabel = {
'1': '上线',
'0': '下线'
}

const {Option} = Select
const CheckboxGroup = Checkbox.Group;

const OpsStatusModal: React.FC<IOpsStatusModalProps> = (props): React.ReactElement => {
const {opsStatusVisible, opsStatus, opsStatusListTree, onOpsStatusCallBack} = props
const formRef = useRef<any>(null)
const [opsStatusList, setOpsStatusList] = useState<any[]>([])
const [treeValue, setTreeValue] = useState<number | null>(null);

useEffect(() => {
setTreeValue(null)
setOpsStatusList([])
formRef.current?.resetFields(['tasks','checkoutAll'])
console.log(opsStatus)
if (opsStatus === '1') {
formRef.current?.setFieldsValue({
taskOperatingSavepointSelect: '0'
})
}
}, [opsStatusVisible, opsStatus])

/**
* onCheckAllChange 全选
* */
const onCheckAllChange = (e: CheckboxChangeEvent) => {
formRef.current?.setFieldsValue({
tasks: e.target.checked ? opsStatusList.map((item: any) => item.id) : []
})
};

/**
* onChangeCheckout 选中
* */
const onChangeCheckout = (list: CheckboxValueType[]) => {
formRef.current?.setFieldsValue({
checkoutAll: list.length === opsStatusList.length ? true : false
})
};

/**
* onTreeChange 结构树选中
* */
const onTreeChange = (newValue: number) => {
setTreeValue(newValue);

};

/**
* onSubmit 提交
* */
const onSubmit = () => {
formRef.current.validateFields(['tasks', 'taskOperatingSavepointSelect']).then((values: any) => {
const {tasks, ...rest} = values
onOpsStatusCallBack({
...rest,
operating: opsStatus,
tasks: tasks.map((item: any) => {
return {
id: item,
name: opsStatusList.find((items: any) => items.id === item).name
}
})
})
})
}

/**
* onSubmitTree 树型选择提交
* */
const onSubmitTree = async () => {
try {
const {datas} = await queryOnClickOperatingTask({
operating: opsStatus,
catalogueId: treeValue
})
setOpsStatusList(datas)
} catch (e) {
console.log(e)
}
}

// options = {opsStatusList}
// value = {checkedList}
// onChange = {onChange}
return (
<Modal width={800} okText={'提交'} onCancel={() => {
onOpsStatusCallBack()
}} onOk={() => {
onSubmit()
}} title={OpsStatusLabel[opsStatus]} visible={opsStatusVisible}>
<Form ref={formRef}>
<Card>
<Row>
<Col span={8}>
<TreeSelect
showSearch
allowClear
treeDataSimpleMode
style={{width: '100%'}}
dropdownStyle={{maxHeight: 400, overflow: 'auto'}}
fieldNames={{label: 'name', value: 'id'}}
treeNodeFilterProp={'name'}
placeholder="请选择"
onChange={onTreeChange}
value={treeValue}
treeData={opsStatusListTree}
/>
</Col>
<Col push={2}>
<Button type={'primary'} onClick={() => {
onSubmitTree()
}}>查询</Button>
</Col>
</Row>
<Divider/>
<Row>
<Col>
<Form.Item name={'checkoutAll'} label={'全选'}>
<Checkbox onChange={onCheckAllChange}/>
</Form.Item>
</Col>
<Col push={15}>
{
opsStatus === '1' &&
<Form.Item name={'taskOperatingSavepointSelect'} label={' '} colon={false}
rules={[{message: '请输入', required: true}]}>
<Select style={{width: '150px'}}>
<Option value={'0'}>默认保存点</Option>
<Option value={'1'}>最新保存点</Option>
</Select>
</Form.Item>}
</Col>
</Row>
<Divider/>
<Form.Item name={'tasks'}>
<CheckboxGroup onChange={onChangeCheckout}>
<Row>
{
opsStatusList.map((item: any) => {
return <Col key={item.id} span={8}>
<Checkbox value={item.id}>{item.name}</Checkbox>
</Col>
})
}
</Row>
</CheckboxGroup>
</Form.Item>

</Card>
</Form>
</Modal>
)
}

export default OpsStatusModal
Loading