Commit b4c0d538 authored by 皮倩雯's avatar 皮倩雯

fix: '定时任务'

parent c5f89b6a
Pipeline #76008 passed with stages
/* eslint-disable default-case */
import React, { useEffect, useState } from 'react';
import SiteModal from '@/components/Modal/SiteModa';
import { AddIISAgentConfig } from '@/services/scheduledTasks/api';
import {
Input,
Card,
InputNumber,
Form,
Radio,
DatePicker,
Switch,
Select,
message,
notification,
} from 'antd';
import { EditOutlined, InfoCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import HourOfDaySelect from './HourOfDaySelect';
import DayOfWeekSelect from './DayOfWeekSelect';
import styles from './AddModal.less';
const { Item } = Form;
const { TextArea } = Input;
let unitType = { Hour: '小时', Minute: '分钟', Second: '秒' };
const hours = {
'1': '星期一',
'2': '星期二',
'3': '星期三',
'4': '星期四',
'5': '星期五',
'6': '星期六',
'7': '星期天',
};
const AddModal = props => {
const { submitCallback, visible, onCancel, type, record } = props;
const [isReentrant, setIsReentrant] = useState(false);
const [postCheck, setPostCheck] = useState(false);
const [reenCheck, setReenCheck] = useState(false);
const [logCheck, setLogCheck] = useState(false);
const [isEndTimeShow, setIsEndTimeShow] = useState(false);
const [isLoopShow, setIsLoopShow] = useState(false);
const [isDayLoopShow, setIsDayLoopShow] = useState(false);
const [isWeekLoopShow, setIsWeekLoopShow] = useState(false);
const [waitCheck, setWaitCheck] = useState(false);
const [isUse, setIsUse] = useState(true);
const [interval, setInterval] = useState(1);
const [loop_unit, setLoop_unit] = useState('Hour');
const [exeType, setExeType] = useState(true);
const [isType, setIsType] = useState('重复执行');
const [isTypeValue, setIsTypeValue] = useState('ByLoop');
const [time_out, setTime_out] = useState(30);
const [weekData, setWeekData] = useState([]);
const [exeTime, setExeTime] = useState(moment().format('YYYY-MM-DD 00:00:00'));
const [selectValues, setSelectValues] = useState([]);
const [form] = Form.useForm();
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
useEffect(() => {
if (visible) {
if (type === 'edit') {
let startTime =
record.LoopMode === 'ByOnce'
? moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00').add(
1,
'days',
)
: moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00');
form.setFieldsValue({
name: record.Name,
is_enable: record.Enabled,
url_type: record.Absolute ? true : false,
url_path: record.Url,
request_header: record.CustomHeader,
plan_type: record.LoopMode,
start_time: record.StartFrom ? moment(record.StartFrom, dateFormat) : startTime,
end_time: record.EndAt ? moment(record.EndAt, dateFormat) : null,
loop_mode: record.LoopMode,
interval: record.Interval,
loop_unit: record.LoopUnit,
hour_of_day: record.HourOfDay && record.HourOfDay.split(','),
day_of_week: record.DayOfWeek,
time_out: (record.Timeout !== -1 && record.Timeout / 1000) || 30,
post_state: record.UsePostState,
reentrant: record.AllowReentrant,
enable_log: record.AllowLog,
});
if (record.UsePostState) {
setIsReentrant(true);
}
let startTimeValue =
record.LoopMode === 'ByOnce'
? moment()
.add(1, 'days')
.format('YYYY-MM-DD 00:00:00')
: moment().format('YYYY-MM-DD 00:00:00');
setExeTime(record.StartFrom ? record.StartFrom : startTimeValue);
setIsUse(record.Enabled);
changeLoopMode(record.LoopMode);
setReenCheck(record.AllowReentrant);
setPostCheck(record.UsePostState);
setLogCheck(record.AllowLog);
setInterval(record.Interval);
setLoop_unit(record.LoopUnit);
setWaitCheck(record.UseTimeout || false);
setTime_out((record.Timeout !== -1 && record.Timeout / 1000) || 30);
if (record.Timeout !== -1) {
setWaitCheck(true);
}
if (record.LoopMode === 'ByOnce') {
setIsType('执行一次');
form.setFieldsValue({
type: '执行一次',
});
setExeType(false);
} else {
setIsType('重复执行');
form.setFieldsValue({
type: '重复执行',
});
if (record.LoopMode === 'ByDay') {
setSelectValues(record.HourOfDay.split(','));
} else if (record.LoopMode === 'ByWeek') {
setWeekData(record.DayOfWeek.split(','));
}
setExeType(true);
}
} else {
form.setFieldsValue({
type: '重复执行',
url_type: false,
loop_mode: 'ByLoop',
start_time: moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00'),
});
setExeTime(moment().format('YYYY-MM-DD 00:00:00'));
setIsType('重复执行');
changeLoopMode('ByLoop');
setIsUse(true);
setInterval(1);
setLoop_unit('Hour');
}
} else {
form.resetFields();
setSelectValues([]);
setWeekData([]);
setLogCheck(false);
setIsReentrant(false);
setReenCheck(false);
setPostCheck(false);
setWaitCheck(false);
setExeType(true);
}
}, [visible]);
const handleOk = async () => {
form.validateFields().then(validate => {
let fv = form.getFieldValue();
if (
(fv.loop_mode === 'ByDay' && !selectValues.length) ||
(fv.loop_mode === 'ByWeek' && !weekData.length)
) {
message.warning('请选择计划执行日');
return false;
}
let data = {
Url: fv.url_path,
CustomHeader: fv.request_header || '',
StartFrom: fv.start_time && fv.start_time.format(dateFormat),
EndAt: fv.end_time && fv.end_time.format(dateFormat),
LoopMode: isType === '重复执行' ? fv.loop_mode : 'ByOnce',
LoopUnit: loop_unit,
MonthOfYear: null,
WeekOfMonth: null,
DayOfWeek: fv.day_of_week ? fv.day_of_week.toString() : '',
DayOfMonth: null,
HourOfDay: fv.hour_of_day && fv.hour_of_day.toString(),
Interval: interval.toString(),
UsePostState: fv.post_state,
AllowReentrant: fv.reentrant,
AllowLog: fv.enable_log,
Enabled: isUse,
Timeout: time_out ? parseInt(time_out) * 1000 : 30000,
Absolute: fv.url_type,
SiteInfo: null,
Name: fv.name,
Tolerate: null,
UseTimeout: waitCheck,
};
time_out ? (data.MillisecondsTimeout = parseInt(time_out)) : -1;
if (!waitCheck) {
data.Timeout = -1;
data.MillisecondsTimeout = -1;
}
AddIISAgentConfig(data).then(res => {
if (res.code === 0) {
onCancel();
submitCallback(fv.type);
notification.success({
message: '提示',
duration: 3,
description: '新增成功',
});
} else {
notification.error({
message: '提示',
duration: 3,
description: res.msg,
});
}
});
});
};
const onPostChange = value => {
setIsReentrant(value);
setReenCheck(false);
setPostCheck(value);
form.setFieldsValue({
post_state: value,
reentrant: false,
});
};
const onReenChange = value => {
setReenCheck(value);
form.setFieldsValue({
reentrant: value,
});
};
const onLogChange = value => {
setLogCheck(value);
form.setFieldsValue({
enable_log: value,
});
};
const changeLoopMode = value => {
setIsTypeValue(value);
switch (value) {
case 'ByOnce':
setIsEndTimeShow(false);
setIsLoopShow(true);
setIsWeekLoopShow(false);
setIsDayLoopShow(false);
break;
case 'ByLoop':
setIsEndTimeShow(true);
setIsLoopShow(true);
setIsWeekLoopShow(false);
setIsDayLoopShow(false);
break;
case 'ByDay':
setIsEndTimeShow(true);
setIsLoopShow(false);
setIsWeekLoopShow(false);
setIsDayLoopShow(true);
break;
case 'ByWeek':
setIsEndTimeShow(true);
setIsLoopShow(false);
setIsWeekLoopShow(true);
setIsDayLoopShow(false);
break;
}
};
const onLoopModeChange = e => {
changeLoopMode(e.target.value);
setSelectValues([]);
setWeekData([]);
form.setFieldsValue({
hour_of_day: '',
day_of_week: '',
});
};
const onChange = val => {
setIsUse(val);
};
const handleExe = e => {
let obj = form.getFieldValue();
let data = e.target.value;
setIsType(data);
if (data === '执行一次') {
changeLoopMode('ByOnce');
setLoop_unit('Second');
form.setFieldsValue({
loop_mode: 'ByOnce',
hour_of_day: '',
day_of_week: '',
end_time: obj.start_time,
});
if (!record) {
form.setFieldsValue({
start_time: moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00').add(
1,
'days',
),
end_time: moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00').add(
1,
'days',
),
});
setExeTime(
moment()
.add(1, 'days')
.format('YYYY-MM-DD 00:00:00'),
);
}
setExeType(false);
} else {
changeLoopMode('ByLoop');
setExeType(true);
form.setFieldsValue({
loop_mode: 'ByLoop',
end_time: '',
});
if (!record) {
form.setFieldsValue({
start_time: moment(new Date(new Date().toLocaleDateString()), 'YYYY-MM-DD 00:00:00'),
hour_of_day: '',
day_of_week: '',
});
setExeTime(moment().format('YYYY-MM-DD 00:00:00'));
}
}
};
const onWait = e => {
setWaitCheck(e);
};
const changeUnit = e => {
setLoop_unit(e);
};
const changeInterval = e => {
setInterval(e);
};
const InputTimeOut = e => {
setTime_out(e);
};
const changeStartTime = e => {
const time = moment(e).format('YYYY-MM-DD HH:mm:ss');
setExeTime(time);
let obj = form.getFieldValue();
if (obj.loop_mode === 'ByOnce') setLoop_unit('Second');
};
const changeDay = data => {
if (data) setSelectValues(data);
};
const changeWeek = data => {
if (data) setWeekData(data);
};
return (
<div className={styles.agent_container}>
<SiteModal
{...props}
title={`${type === 'add' ? '新增' : '编辑'}定时任务`}
bodyStyle={{ width: '100%', minHeight: '100px' }}
style={{ top: 100, borderRadius: '20px' }}
width="800px"
destroyOnClose
cancelText="取消"
okText="确认"
forceRender
visible={visible}
onOk={() => handleOk()}
onCancel={() => onCancel()}
>
<div className={styles.IISAgent_container}>
<Form form={form} labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}>
<Item label="计划名称" name="name" rules={[{ required: true }]}>
<Input placeholder="请输入计划名称" disabled={type === 'edit' ? true : false} />
</Item>
<Item label="URL路径">
<Item label="" name="url_type" style={{ marginBottom: '0.2rem' }}>
<Radio.Group>
<Radio value={false}>相对路径(便于配置迁移)</Radio>
<Radio value={true}>绝对路径(用于外链)</Radio>
</Radio.Group>
</Item>
<Item label="" name="url_path" style={{ marginBottom: '0' }}>
<TextArea rows={3} placeholder="请输入URL名称" />
</Item>
</Item>
<Item label="请求头" name="request_header">
<Input placeholder="请求头,选填" />
</Item>
<Item label="计划类型" name="type">
<Radio.Group onChange={handleExe}>
<Radio.Button value="重复执行">重复执行</Radio.Button>
<Radio.Button value="执行一次">执行一次</Radio.Button>
</Radio.Group>
</Item>
{exeType && (
<Item label="执行方式" name="loop_mode">
<Radio.Group onChange={onLoopModeChange}>
<Radio value="ByLoop">循环</Radio>
<Radio value="ByDay">每天</Radio>
<Radio value="ByWeek">每周</Radio>
</Radio.Group>
</Item>
)}
<Item label="开始时间" wrapperCol={{ span: 28 }} style={{ marginBottom: '0' }}>
<div style={{ display: 'flex' }}>
<Item label="" name="start_time" style={{ marginRight: '1rem' }}>
<DatePicker showTime onChange={changeStartTime} />
</Item>
{isEndTimeShow && (
<Item label="结束时间" name="end_time">
<DatePicker showTime />
</Item>
)}
</div>
</Item>
{isLoopShow && isType === '重复执行' && (
<Card style={{ width: 600, margin: '0 0 1rem 3.6rem', height: '8rem' }}>
<div className={styles.loopShow}>
<span></span>
<InputNumber
min={0}
value={interval}
style={{ margin: '0 0.5rem' }}
onChange={changeInterval}
placeholder="请输入循环周期"
/>
<Select
value={loop_unit}
onChange={changeUnit}
style={{ width: '8rem', margin: '0 0.5rem' }}
>
<Select.Option value="Hour">小时</Select.Option>
<Select.Option value="Minute">分钟</Select.Option>
<Select.Option value="Second"></Select.Option>
</Select>
<span> 执行一次</span>
</div>
</Card>
)}
{isDayLoopShow && (
<Item label="日循环" name="hour_of_day">
<HourOfDaySelect changeDay={changeDay} />
</Item>
)}
{isWeekLoopShow && (
<Item label="周循环" name="day_of_week">
<DayOfWeekSelect changeWeek={changeWeek} />
</Item>
)}
{isTypeValue === 'ByDay'
? !selectValues.length && (
<span style={{ color: '#f00' }} className={styles.exeTime}>
<InfoCircleOutlined style={{ marginRight: '0.2rem' }} />
必须选择计划执行时刻
</span>
)
: ''}
{isTypeValue === 'ByWeek'
? !weekData.length && (
<span style={{ color: '#f00' }} className={styles.exeTime}>
<InfoCircleOutlined style={{ marginRight: '0.2rem' }} />
必须选择计划执行时刻
</span>
)
: ''}
<Item label="说明">
<div style={{ color: '#909EB6FF', fontSize: '12px' }}>
{isType === '执行一次' && <span>{exeTime}执行一次</span>}
{isType === '重复执行' && isTypeValue === 'ByDay' && (
<span style={{ color: selectValues.length ? '#909EB6FF' : '#f00' }}>
{exeTime}开始{selectValues.length ? ',在每天' : ''}
{selectValues.length
? selectValues.map((item, index) => {
return item.length > 1
? `${item}:00${index == selectValues.length - 1 ? '' : ','}`
: `0${item}:00${index == selectValues.length - 1 ? '' : ','}`;
})
: ''}
{selectValues.length ? '执行' : ''}
</span>
)}
{isType === '重复执行' && isTypeValue === 'ByWeek' && (
<span style={{ color: weekData.length ? '#909EB6FF' : '#f00' }}>
{exeTime}开始{weekData.length ? ',在每周' : ''}
{weekData.length
? weekData.map((item, index) => {
return `${hours[item]}${index == weekData.length - 1 ? '' : ','}`;
})
: ''}
{weekData.length && selectValues.length
? selectValues.map((item, index) => {
return item.length > 1
? `${item}:00${index == selectValues.length - 1 ? '' : ','}`
: `0${item}:00${index == selectValues.length - 1 ? '' : ','}`;
})
: ''}{' '}
{weekData.length ? '执行' : ''}
</span>
)}
{isType === '重复执行' && isTypeValue === 'ByLoop' && (
<span style={{ color: '#909EB6FF' }}>
{exeTime}开始,每{interval}
{unitType[loop_unit]}执行一次。
</span>
)}
</div>
</Item>
<Item label="其他设置" wrapperCol={{ span: 28 }} style={{ marginBottom: '0' }}>
{' '}
<div style={{ display: 'flex' }}>
<div style={{ display: 'flex' }}>
<Item name="wait" style={{ marginRight: '0.5rem' }}>
<Switch
checkedChildren="开启"
unCheckedChildren="关闭"
onChange={onWait}
checked={waitCheck}
/>
</Item>
<div style={{ paddingTop: '0.3rem' }}>请求等待时间(单位:秒)</div>
</div>
{waitCheck && (
<Item name="time_out">
<div>
<InputNumber value={time_out} onChange={InputTimeOut} />
</div>
</Item>
)}
</div>
</Item>
<Item label=" " wrapperCol={{ span: 28 }} colon={false} style={{ marginBottom: '0' }}>
{' '}
<div style={{ display: 'flex' }}>
<Item name="post_state" style={{ marginRight: '0.5rem' }}>
<Switch
checkedChildren="开启"
unCheckedChildren="关闭"
onChange={onPostChange}
checked={postCheck}
/>
</Item>
<div style={{ paddingTop: '0.3rem' }}>
使用POST维持状态(上一次返回结果传入下一次请求)
</div>
</div>
</Item>
<Item label=" " wrapperCol={{ span: 28 }} colon={false} style={{ marginBottom: '0' }}>
<div style={{ display: 'flex' }}>
<Item style={{ marginRight: '0.5rem' }} name="reentrant">
<Switch
checkedChildren="开启"
unCheckedChildren="关闭"
onChange={onReenChange}
disabled={isReentrant}
checked={reenCheck}
/>
</Item>
<div style={{ paddingTop: '0.3rem' }}>
允许重入(上一次未执行完,也会执行下一次请求)
</div>
</div>
</Item>
<Item label=" " wrapperCol={{ span: 28 }} colon={false} style={{ marginBottom: '0' }}>
<div style={{ display: 'flex' }}>
<Item name="enable_log" style={{ marginRight: '0.5rem' }}>
<Switch
checkedChildren="开启"
unCheckedChildren="关闭"
onChange={onLogChange}
checked={logCheck}
/>
</Item>
<div style={{ paddingTop: '0.3rem' }}>记录日志(小于每分钟一次的请求不会记录)</div>
</div>
</Item>
<Item label="禁用计划" style={{ color: '#f00' }} name="is_enable">
<Switch
checkedChildren="开启"
unCheckedChildren="关闭"
checked={isUse}
onChange={onChange}
/>
</Item>
</Form>
</div>
</SiteModal>
</div>
);
};
export default AddModal;
.agent_container {
display: flex;
flex-direction: row;
width: 80%;
.select_btn {
display: inline-block;
cursor: pointer;
text-align: center;
padding: 0 0.8rem;
color: rgba(22,133,255,1);
}
}
.exeTime{
display: flex;
align-items: center;
margin:0.2rem 0 0 7.6rem
}
.IISAgent_container {
overflow-y: scroll;
height: 500px;
}
.loopShow{
display: flex;
align-items: center;
margin-left: 3.6rem;
}
/* eslint-disable default-case */
/* eslint-disable no-unused-expressions */
import React, { useEffect, useState } from 'react';
import { Radio, Checkbox, Row, Col } from 'antd';
const DayOfWeekSelect = props => {
const { changeWeek } = props;
const [selectValues, setSelectValues] = useState([]);
const { onChange, value } = props;
const hours = [
{ name: '星期一', value: '1' },
{ name: '星期二', value: '2' },
{ name: '星期三', value: '3' },
{ name: '星期四', value: '4' },
{ name: '星期五', value: '5' },
{ name: '星期六', value: '6' },
{ name: '星期天', value: '7' },
];
const onTypeChange = e => {
let values = [];
switch (e.target.value) {
case 0:
values = ['1', '2', '3', '4', '5', '6', '7'];
break;
case 1:
const arr = ['1', '2', '3', '4', '5', '6', '7'];
let newArr = [];
selectValues &&
arr.map(item => {
if (!selectValues.includes(item)) {
newArr.push(item);
}
});
values = newArr;
break;
case 2:
values = ['1', '2', '3', '4', '5'];
break;
case 3:
values = ['6', '7'];
break;
}
changeWeek(values);
setSelectValues(values);
onChange && onChange(values);
};
const onCheckChange = val => {
setSelectValues(val);
onChange && onChange(val);
changeWeek(val);
};
useEffect(() => {
setSelectValues(value);
}, [props]);
return (
<div>
<Radio.Group onChange={onTypeChange} style={{ margin: '0.25rem 0' }}>
<Radio style={{ width: '85px' }} value={0}>
全选
</Radio>
<Radio style={{ width: '85px' }} value={1}>
反选
</Radio>
<Radio style={{ width: '88px' }} value={2}>
工作日
</Radio>
<Radio style={{ width: '88px' }} value={3}>
周末
</Radio>
</Radio.Group>
<Checkbox.Group value={selectValues} onChange={onCheckChange}>
<Row>
{hours.map((item, idx) => {
return (
<Col span={4} key={idx}>
<Checkbox value={item.value}>{item.name}</Checkbox>
</Col>
);
})}
</Row>
</Checkbox.Group>
</div>
);
};
export default DayOfWeekSelect;
/* eslint-disable no-case-declarations */
/* eslint-disable no-unused-expressions */
/* eslint-disable default-case */
import React, { useEffect, useState } from 'react';
import { Radio, Checkbox, Row, Col } from 'antd';
import styles from './HourOfDaySelect.less';
const HourOfDaySelect = props => {
const { changeDay } = props;
const [selectValues, setSelectValues] = useState([]);
const { onChange, value } = props;
const hours = [
{ name: '0:00', value: '0' },
{ name: '1:00', value: '1' },
{ name: '2:00', value: '2' },
{ name: '3:00', value: '3' },
{ name: '4:00', value: '4' },
{ name: '5:00', value: '5' },
{ name: '6:00', value: '6' },
{ name: '7:00', value: '7' },
{ name: '8:00', value: '8' },
{ name: '9:00', value: '9' },
{ name: '10:00', value: '10' },
{ name: '11:00', value: '11' },
{ name: '12:00', value: '12' },
{ name: '13:00', value: '13' },
{ name: '14:00', value: '14' },
{ name: '15:00', value: '15' },
{ name: '16:00', value: '16' },
{ name: '17:00', value: '17' },
{ name: '18:00', value: '18' },
{ name: '19:00', value: '19' },
{ name: '20:00', value: '20' },
{ name: '21:00', value: '21' },
{ name: '22:00', value: '22' },
{ name: '23:00', value: '23' },
];
const onTypeChange = e => {
let values = [];
switch (e.target.value) {
case 0:
values = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23',
];
break;
case 1:
const arr = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23',
];
let newArr = [];
selectValues &&
arr.map(item => {
if (!selectValues.includes(item)) {
newArr.push(item);
}
});
values = newArr;
break;
case 2:
values = ['6', '8'];
break;
case 3:
values = ['0', '8', '16'];
break;
case 4:
values = ['0', '6', '12', '18'];
break;
}
onChange(values);
setSelectValues(values);
changeDay(values);
};
useEffect(() => {
setSelectValues(value);
}, [props]);
const onCheckChange = val => {
setSelectValues(val);
onChange(val);
changeDay(val);
};
return (
<div className={styles.hourOfDay_container}>
<Radio.Group onChange={onTypeChange} style={{ marginBottom: '0.5rem' }}>
<Radio style={{ width: '85px' }} value={0}>
全选
</Radio>
<Radio style={{ width: '85px' }} value={1}>
反选
</Radio>
<Radio style={{ width: '88px' }} value={2}>
一天两次
</Radio>
<Radio style={{ width: '88px' }} value={3}>
一天三次
</Radio>
<Radio style={{ width: '88px' }} value={4}>
一天四次
</Radio>
</Radio.Group>
<Checkbox.Group value={selectValues} onChange={onCheckChange}>
<Row>
{hours.map((item, idx) => {
return (
<Col span={4} key={idx}>
<Checkbox value={item.value}>{item.name}</Checkbox>
</Col>
);
})}
</Row>
</Checkbox.Group>
</div>
);
};
export default HourOfDaySelect;
.hourOfDay_container{
display: flex;
flex-direction: column;
margin-top: 0.3rem;
}
import React, { useState, useEffect, useRef } from 'react';
import { Checkbox } from 'antd';
import styles from './PushTest.less';
const CheckboxGroup = Checkbox.Group;
const CardCheck = props => {
// 自定义获取改变后的值hooks
const usePrevious = value => {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
const { cardMsg, callback, checkList } = props;
const [checkedList, setCheckedList] = useState([]); // 选中列表
const [indeterminate, setIndeterminate] = useState(false);
const [checkAll, setCheckAll] = useState(false);
const [plainOptions, setPlainOptions] = useState([]);
const prevAmount = usePrevious({ checkedList });
useEffect(() => {
const msg = JSON.parse(JSON.stringify(cardMsg));
setPlainOptions(msg.plainOptions);
setCheckedList(msg.checkedList);
setIndeterminate(msg.indeterminate);
setCheckAll(msg.checkAll);
}, [cardMsg]);
// 获取勾选新增得数据
const addData = (arr1, arr2) => arr2.filter(val => arr1.indexOf(val) === -1);
// 获取勾选删除得数据
const delData = (arr1, arr2) => arr1.filter(val => arr2.indexOf(val) === -1);
// 单选监听
const onChange = list => {
let newCheckList = [...checkList];
let arr;
if (checkedList.length > list.length) {
// 取消勾选
arr = delData(checkedList, list);
arr.forEach(item => {
newCheckList.splice(newCheckList.findIndex(ele => ele.value === item), 1);
});
} else {
// 勾选元素
arr = addData(checkedList, list);
arr.forEach(item => {
let checkName = plainOptions.find(ele => ele.value === item);
newCheckList.push(checkName);
});
}
callback(newCheckList);
setCheckedList(list);
setIndeterminate(!!list.length && list.length < plainOptions.length);
setCheckAll(list.length === plainOptions.length);
};
// 全选监听
const onCheckAllChange = e => {
let newCheckList = [...checkList];
let arr;
if (e.target.checked) {
// 全选
arr = addData(checkedList, plainOptions.map(item => item.value));
arr.forEach(item => {
let checkName = plainOptions.find(ele => ele.value === item);
newCheckList.push(checkName);
});
} else {
arr = delData(checkedList, []);
arr.forEach(item => {
newCheckList.splice(newCheckList.findIndex(ele => ele.value === item), 1);
});
}
callback(newCheckList);
setCheckedList(e.target.checked ? plainOptions.map(item => item.value) : []);
setIndeterminate(false);
setCheckAll(e.target.checked);
};
return (
<div className={styles.checkContent}>
<div className={styles.topCheckbox}>
<Checkbox
indeterminate={indeterminate}
onChange={e => onCheckAllChange(e)}
checked={checkAll}
>
{cardMsg.groupName}
</Checkbox>
</div>
<div className={styles.bottomCheckbox}>
<CheckboxGroup
value={checkedList}
onChange={list => onChange(list)}
style={{ display: 'flex', flexWrap: 'wrap' }}
>
{plainOptions.map(item => (
<Checkbox key={item.value} value={item.value}>
{item.label}
</Checkbox>
))}
</CheckboxGroup>
</div>
</div>
);
};
export default CardCheck;
import React, { useState, useEffect, useCallback } from 'react';
import { Modal, Input, Button, message, Spin, Pagination, Table } from 'antd';
import { GetGroupUserTree, TestPush } from '@/services/messagemanage/messagemanage';
import styles from './PushTest.less';
import CardCheck from './CardCheck';
const PushTest = props => {
const { confirmModal, onCancel, visible, pushTestMsg } = props;
const [allList, setAllist] = useState([]); // 用于展示得数据
const [checkList, setCheckList] = useState([]); // 选中得数据集合
const [loading, setLoading] = useState(false);
const [total, setTotal] = useState();
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [searchName, setSearchName] = useState();
useEffect(() => {
if (visible) {
setCurrentPage(1);
getData(searchName, 1, pageSize);
} else {
setCheckList([]);
setAllist([]);
setSearchName('');
}
}, [visible]);
// 选中后得回调函数
const checkCallBack = useCallback(newCheckList => {
if (newCheckList) {
setCheckList(newCheckList);
}
});
// 监听分页
const paginationChange = (page, pageSizes) => {
setCurrentPage(page);
setPageSize(pageSizes);
getData(searchName, page, pageSizes);
};
// 提交勾选的测试人员
const onFinish = () => {
TestPush({
theme: '定时推送',
msgType: pushTestMsg.Name,
tousers: checkList.map(item => item.value),
pushPath: pushTestMsg.Url ? pushTestMsg.Url : '',
msgTypeId: pushTestMsg.ID.toString(),
})
.then(res => {
if (res.code === 0) {
confirmModal();
message.success('测试推送成功');
} else {
message.error(res.msg);
}
})
.catch(() => {
message.error('网络异常,请稍后再试');
});
};
// 搜索
const onSearch = () => {
setCurrentPage(1);
getData(searchName, 1, pageSize);
};
// 重置
const onReset = () => {
setCurrentPage(1);
getData('', 1, pageSize);
setSearchName('');
};
// 搜索框监听
const searchChange = e => {
setSearchName(e.target.value);
};
// 获取数据
const getData = (username, page, pageSizes) => {
setLoading(true);
GetGroupUserTree({
key: username,
pageSize: pageSizes,
PageIndex: page,
})
.then(res => {
setLoading(false);
if (res.code === 0) {
setTotal(res.data.count);
// 数据处理成checkbox组件需要得形式
let list = res.data.data.map(item => {
let indeterminate = false;
let checkedList = [];
let checkAll = false;
let options = item.users.map(val => {
checkList.forEach(ele => {
if (val.userId === ele.value) {
checkedList.push(ele.value);
}
});
return {
label: val.userName,
value: val.userId,
};
});
if (checkedList.length === options.length && checkedList.length > 0) {
checkAll = true;
}
if (checkedList.length < options.length && checkedList.length > 0) {
indeterminate = true;
}
return {
groupName: item.groupName,
groupId: item.groupId,
indeterminate,
checkAll,
checkedList,
plainOptions: options,
};
});
setAllist(list);
} else {
message.error(res.msg);
}
})
.catch(() => {
setLoading(false);
message.error('网络异常,请稍后再试');
});
};
// 拖拽后的回调函数
const dragCallBack = val => {
if (val) {
setCheckList(val);
}
};
const columns = [
{
title: '已选推送人',
dataIndex: 'label',
key: 'label',
width: 300,
},
];
return (
<>
<Modal
title="选择推送人"
visible={visible}
onOk={onFinish}
width="900px"
onCancel={onCancel}
maskClosable={false}
destroyOnClose
centered
>
<div className={styles.pushTestContent}>
<div className={styles.leftContent}>
{/* 头部搜索框 */}
<div className={styles.searchHeader}>
<Input.Search
value={searchName}
placeholder="请输入部门或用户"
onChange={searchChange}
onSearch={onSearch}
enterButton
style={{ width: '300px', marginRight: '15px' }}
/>
<Button type="primary" htmlType="submit" onClick={onReset}>
重置
</Button>
</div>
{/* 复选框模块 */}
<div className={styles.checkContainer}>
<Spin spinning={loading}>
{allList.map((item, index) => (
<div className={styles.checkBoxContent} key={item.groupId}>
<CardCheck
cardMsg={item}
cardIndex={index}
callback={(val, newCheckList) => checkCallBack(val, newCheckList)}
checkList={checkList}
/>
</div>
))}
</Spin>
</div>
</div>
<div className={styles.tableRight}>
<Table
bordered
style={{ width: '350px', overflowX: 'hidden' }}
rowKey={record => record.value}
columns={columns}
dataSource={checkList}
pagination={false}
size="small"
scroll={{ y: 530 }}
ItemTypes="pushTest"
/>
</div>
</div>
<div>
{/* 分页 */}
<Pagination
total={total}
showTotal={(totals, range) => `共 ${totals} 条`}
defaultPageSize={pageSize}
defaultCurrent={1}
current={currentPage}
onChange={paginationChange}
style={{ width: '100%' }}
size="small"
showQuickJumper
showSizeChanger
/>
</div>
</Modal>
</>
);
};
export default PushTest;
.pushTestContent {
display: flex;
.searchHeader {
display: flex;
}
.checkContainer {
height: 500px;
width: 500px;
overflow-y: scroll;
margin: 20px 0;
padding-right: 5px;
.checkContent {
display: flex;
width: 100%;
flex-direction: column;
border: 1px solid #c2cdfd;
border-radius: 5px;
margin-top: 20px;
min-height: 50px;
padding: 0 10px 10px 20px;
.ant-checkbox-wrapper {
background-color: #fff;
}
.topCheckbox {
height: 20px;
margin: -10px 0 0 0px;
line-height: 20px;
}
.topCheckbox > label :hover {
font-weight: 600;
}
.bottomCheckbox {
margin-top: 10px;
.ant-checkbox-wrapper {
min-width: 150px;
margin-left: 0;
}
// .ant-checkbox-group-item {
// min-width: 150px !important;
// }
// .ant-checkbox-wrapper {
// min-width: 150px !important;
// }
}
.checkdiv {
display: flex;
flex-wrap: wrap;
}
}
}
.tableRight {
margin-left: 10px;
}
}
/* eslint-disable no-else-return */
/* eslint-disable no-unneeded-ternary */
import React, { useState, useEffect, useRef } from 'react';
import {
Input,
Table,
Button,
notification,
message,
Tooltip,
Tag,
Modal,
Popconfirm,
Space,
Switch,
Select,
} from 'antd';
import {
SearchOutlined,
FundViewOutlined,
EditTwoTone,
DeleteOutlined,
PlusOutlined,
} from '@ant-design/icons';
import 'moment/dist/locale/zh-cn';
import styles from './index.less';
import {
GetIISAgentConfig,
DeleteIISAgentConfig,
AddIISAgentConfig,
} from '@/services/scheduledTasks/api';
import AddModal from './components/AddModal';
import PushTest from './components/PushTest/PushTest';
const { Option } = Select;
const ScheduledTasks = () => {
const [loading, setLoading] = useState(false); // 源数据
const [requestUrl, setRequestUrl] = useState(''); // 接口名称筛选
const [showSearchStyle, setShowSearchStyle] = useState(false); // 是否显示模糊查询样式
const [keepTableList, setKeepTableList] = useState([]);
const [addVisible, setAddVisible] = useState(false);
const [type, setType] = useState('');
const [recordItem, setRecordItem] = useState();
const [pushTestVisible, setPushTestVisible] = useState(false);
const typeValue = useRef('重复执行');
const [columnsData, setColumnsData] = useState([]);
const columns = [
{
title: '计划名称',
dataIndex: 'Name',
key: 'Name',
width: 300,
fixed: 'left',
onCell: () => ({
style: {
maxWidth: 300,
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
cursor: 'pointer',
},
}),
render: text => <Tooltip title={text}>{searchStyle(text)}</Tooltip>,
},
{
title: '计划类型',
dataIndex: 'LoopMode',
key: 'LoopMode',
align: 'center',
width: 200,
render: text => {
if (text === 'ByOnce') {
return <span>执行一次</span>;
} else {
return <span>重复执行</span>;
}
},
},
{
title: '执行方式',
dataIndex: 'LoopMode',
key: 'LoopMode',
align: 'center',
width: 150,
render: text => {
if (text === 'ByLoop') {
return <Tag color="purple">循环</Tag>;
} else if (text === 'ByDay') {
return <Tag color="cyan">每天</Tag>;
} else if (text === 'ByWeek') {
return <Tag color="volcano">每周</Tag>;
}
},
},
{
title: '计划开始时间',
dataIndex: 'StartFrom',
key: 'StartFrom',
align: 'center',
width: 300,
},
{
title: '计划结束时间',
dataIndex: 'EndAt',
key: 'EndAt',
align: 'center',
width: 300,
},
{
title: '是否启用',
dataIndex: 'Enabled',
key: 'Enabled',
align: 'center',
width: 150,
render: (text, record) => {
if (text === true) {
return <Tag color="green"></Tag>;
} else if (text === false) {
return <Tag color="blue"></Tag>;
}
// return (
// <Switch
// checkedChildren="开启"
// unCheckedChildren="关闭"
// onChange={e => changeSwitch(e, record)}
// checked={text}
// />
// );
},
},
{
title: '操作',
width: 150,
align: 'center',
ellipsis: true,
render: (text, record) => (
<Space>
{/* <Tooltip title="测试">
<FundViewOutlined
style={{ fontSize: '16px', color: '#1890FF' }}
onClick={() => {
TestDesc(record);
}}
/>
</Tooltip> */}
<Tooltip title="编辑">
<EditTwoTone
style={{ fontSize: '16px', color: '#e86060' }}
onClick={() => {
editData(record);
}}
/>
</Tooltip>
<div onClick={e => e.stopPropagation()}>
<Popconfirm
title="是否删除方案?"
okText="确认"
cancelText="取消"
onConfirm={() => {
deleteData(record);
}}
>
<DeleteOutlined style={{ fontSize: '16px', color: '#e86060' }} />
</Popconfirm>
</div>
</Space>
),
},
];
useEffect(() => {
getTableList();
setColumnsData(columns);
}, []);
const getTableList = (search, planType) => {
let newSearch = search ? search : requestUrl;
let newType = planType ? planType : typeValue.current;
setLoading(true);
GetIISAgentConfig({ agentName: newSearch }).then(res => {
setLoading(false);
if (res.code === 0) {
let newData = [];
if (newType === '重复执行') {
newData = res.data.filter(i => i.LoopMode !== 'ByOnce');
} else {
newData = res.data.filter(i => i.LoopMode === 'ByOnce');
}
setKeepTableList(newData);
} else {
setKeepTableList([]);
notification.error({
message: '提示',
duration: 3,
description: res.msg,
});
}
});
};
const changeSwitch = (e, record) => {
// AddIISAgentConfig({ ...record, Enabled: e }).then(res => {
// if (res.code === 0) {
// getTableList();
// message.success(e ? `开启成功!` : `关闭成功!`);
// } else {
// message.error(res.msg);
// }
// });
};
const TestDesc = val => {
setRecordItem(val);
setPushTestVisible(true);
};
const editData = val => {
setType('edit');
setRecordItem(val);
setAddVisible(true);
};
const deleteData = val => {
DeleteIISAgentConfig({ agentName: val.Name }).then(res => {
if (res.code === 0) {
notification.success({
message: '提示',
duration: 3,
description: '删除成功',
});
getTableList();
} else {
notification.error({
message: '提示',
duration: 3,
description: res.msg,
});
}
});
};
// 模糊查询匹配的样式
const searchStyle = val => {
let n;
if (showSearchStyle) {
n = val.replace(new RegExp(requestUrl, 'g'), `<span style='color:red'>${requestUrl}</span>`);
} else {
n = val;
}
return <div dangerouslySetInnerHTML={{ __html: n }} />;
};
const handleAdd = () => {
setType('add');
setAddVisible(true);
};
const onOk = val => {
changeTable(val);
typeValue.current = val;
getTableList('', val);
};
const changeTable = e => {
if (e === '执行一次') {
let newColumns = columns;
let data = newColumns.filter(i => i.title !== '执行方式');
setColumnsData(data);
} else {
setColumnsData(columns);
}
};
return (
<div className={styles.scheduledTasks}>
<div className={styles.head}>
<div className={styles.headLeft}>
<span style={{ marginLeft: '5px' }}>计划类型:</span>
<Select
placeholder="请选择计划类型"
style={{ width: '155px' }}
value={typeValue.current}
onChange={e => {
changeTable(e);
typeValue.current = e;
getTableList('', e);
}}
>
<Option value="重复执行">重复执行</Option>
<Option value="执行一次">执行一次</Option>
</Select>
<span style={{ marginLeft: '15px' }}>计划名称:</span>
<Input.Search
style={{ width: '250px' }}
placeholder="请输入计划名称"
onChange={e => {
setRequestUrl(e.target.value);
}}
onSearch={e => {
getTableList(e);
setShowSearchStyle(true);
}}
value={requestUrl}
/>
</div>
<div className={styles.headRight}>
<Button
icon={<PlusOutlined className={styles.icon} />}
type="primary"
onClick={handleAdd}
style={{
marginLeft: '25px',
verticalAlign: 'middle',
marginTop: '-3px',
}}
>
新增
</Button>
</div>
</div>
<div className={styles.table}>
<Table
size="small"
bordered
columns={columnsData}
dataSource={keepTableList}
onRow={record => ({
onDoubleClick: event => {
event.stopPropagation();
editData(record);
}, // 双击
})}
scroll={{ y: 'calc(100vh - 225px)' }}
loading={loading}
/>
</div>
<AddModal
visible={addVisible}
onCancel={() => setAddVisible(false)}
submitCallback={onOk}
type={type}
record={recordItem}
/>
<PushTest
visible={pushTestVisible}
onCancel={() => setPushTestVisible(false)}
pushTestMsg={recordItem}
/>
</div>
);
};
export default ScheduledTasks;
.scheduledTasks {
width: 100%;
height: 100%;
.head {
padding: 10px;
background: white;
margin-bottom: 2px;
width: 100%;
height: 52px;
display: flex;
justify-content: space-between;
align-items: center;
.headLeft{
display: flex;
align-items: center;
}
}
.table {
height: calc(100% - 53px);
width: 100%;
background-color: white;
padding: 10px;
overflow: hidden;
margin-bottom: 3px;
.ant-table-container {
height: calc(100vh - 185px);
}
}
.icon {
margin-top: -5px;
vertical-align: text-bottom;
}
}
......@@ -41,6 +41,7 @@ import {
PlusOutlined,
SyncOutlined,
ClusterOutlined,
MessageOutlined,
} from '@ant-design/icons';
import PageContainer from '@/components/BasePageContainer';
import voca from 'voca';
......@@ -68,6 +69,7 @@ import {
DragGroup,
GetAllSite,
SetGroupManager,
ChangeSMSState,
} from '@/services/userManage/api';
import { AddUserAuthSetting, GetUserAuthSet } from '@/services/database/api';
import TreeComponents from '@/components/ExpendableTree';
......@@ -316,6 +318,44 @@ const UserManage = () => {
/>
</Popconfirm>
</Tooltip>
<Tooltip title={record.isSendSMS === 0 ? '不接收短信' : '接收短信'}>
<Popconfirm
placement="bottomRight"
title={
record.isSendSMS === 0 ? (
<p>
确定设置用户
<span className={styles.redText}>{voca.stripTags(record.loginName)}</span>
可以接收短信吗?
</p>
) : (
<p>
确定设置用户
<span className={styles.redText}>{voca.stripTags(record.loginName)}</span>
不可接收短信吗?
</p>
)
}
okText="确认"
cancelText="取消"
onConfirm={() => {
ChangeSMSState({ userId: record.userId }).then(res => {
if (res.code === 0) {
currentSelectOrg === '-1' ? submitSearchUser() : onSelect([currentSelectOrg]);
} else {
notification.error({
message: '设置失败',
description: res.msg,
});
}
});
}}
>
<MessageOutlined
style={{ fontSize: '16px', color: record.isSendSMS === 0 ? '#e86060' : '#1890FF' }}
/>
</Popconfirm>
</Tooltip>
</Space>
),
},
......
......@@ -131,6 +131,7 @@ const BaseFrameContainer = asyncComponent(() =>
const IntegratedLogin = asyncComponent(() =>
import('@/pages/platformCenter/integratedLogin/integrate'),
);
const ScheduledTasks = asyncComponent(() => import('@/pages/platformCenter/scheduledTasks/index'));
// 业务中心
const TableManager = asyncComponent(() => import('@/pages/bsmanager/base/tablemanager'));
// const FiledConfig = asyncComponent(() =>
......@@ -433,6 +434,11 @@ export default {
name: '消息中心',
component: MessageManager,
},
{
path: '/platform/scheduledTasks',
name: '定时任务',
component: ScheduledTasks,
},
// {
// path: '/platform/notificationNew',
// name: '消息中心(新)',
......
import { get, PUBLISH_SERVICE, post } from '../index';
export const AddIISAgentConfig = data =>
post(`${PUBLISH_SERVICE}/MessageConfig/AddIISAgentConfig`, data); // 添加助理服务器配置
export const GetIISAgentConfig = param =>
get(`${PUBLISH_SERVICE}/MessageConfig/GetIISAgentConfig`, param); // 获取助理服务器配置
export const DeleteIISAgentConfig = param =>
get(`${PUBLISH_SERVICE}/MessageConfig/DeleteIISAgentConfig`, param); // 删除助理服务器配置
......@@ -187,6 +187,8 @@ export const DragGroup = params => post(`${PUBLISH_SERVICE}/UserCenter/DragGroup
export const GetAllSite = params => get(`${PUBLISH_SERVICE}/UserCenter/GetAllSite`, params);
// 设置为主管
export const SetGroupManager = params => get(`${PUBLISH_SERVICE}/UserCenter/SetGroupManager`, params);
// 设置接收短信
export const ChangeSMSState = params => get(`${PUBLISH_SERVICE}/UserCenter/ChangeSMSState`, params);
// export const DeleteOUNew = params =>
// get(`${PUBLISH_SERVICE}/UserCenter/DeleteOU`, params)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment