import React, { useCallback, useRef, useState, useEffect } from 'react';
import {
Button,
message,
Modal,
Table,
Tag,
Space,
Typography,
Tooltip,
Input,
Form,
notification,
} from 'antd';
import {
EditOutlined,
DeleteOutlined,
SyncOutlined,
ClockCircleOutlined,
CloseCircleOutlined,
CheckCircleOutlined,
StopOutlined,
} from '@ant-design/icons';
import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout';
import { request } from '@/utils/http';
import EnvModal from './modal';
import EditNameModal from './editNameModal';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import './index.less';
import { getTableScroll } from '@/utils/index';
import { doc } from 'prettier';
const { Text } = Typography;
const { Search, TextArea } = Input;
enum Status {
'已启用',
'已禁用',
}
enum StatusColor {
'success',
'error',
}
enum OperationName {
'启用',
'禁用',
}
enum OperationPath {
'enable',
'disable',
}
const type = 'DragableBodyRow';
const DragableBodyRow = ({
index,
moveRow,
className,
style,
...restProps
}: any) => {
const ref = useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
const { index: dragIndex } = (monitor.getItem() as any) || {};
if (dragIndex === index) {
return {};
}
return {
isOver: monitor.isOver(),
dropClassName:
dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
};
},
drop: (item: any) => {
moveRow(item.index, index);
},
});
const [, drag] = useDrag({
type,
item: { index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
drop(drag(ref));
return (
);
};
const Env = ({ headerStyle, isPhone, theme }: any) => {
const columns: any = [
{
title: '序号',
align: 'center' as const,
width: 60,
render: (text: string, record: any, index: number) => {
return {index + 1} ;
},
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
align: 'center' as const,
sorter: (a: any, b: any) => a.name.localeCompare(b.name),
},
{
title: '值',
dataIndex: 'value',
key: 'value',
align: 'center' as const,
width: '35%',
ellipsis: {
showTitle: false,
},
render: (text: string, record: any) => {
return (
{text}
);
},
},
{
title: '备注',
dataIndex: 'remarks',
key: 'remarks',
align: 'center' as const,
},
{
title: '更新时间',
dataIndex: 'timestamp',
key: 'timestamp',
align: 'center' as const,
width: 165,
ellipsis: {
showTitle: false,
},
sorter: {
compare: (a: any, b: any) => {
const updatedAtA = new Date(a.updatedAt || a.timestamp).getTime();
const updatedAtB = new Date(b.updatedAt || b.timestamp).getTime();
return updatedAtA - updatedAtB;
},
},
render: (text: string, record: any) => {
const language = navigator.language || navigator.languages[0];
const time = record.updatedAt || record.timestamp;
const date = new Date(time)
.toLocaleString(language, {
hour12: false,
})
.replace(' 24:', ' 00:');
return (
{date}
);
},
},
{
title: '状态',
key: 'status',
dataIndex: 'status',
align: 'center' as const,
width: 70,
filters: [
{
text: '已启用',
value: 0,
},
{
text: '已禁用',
value: 1,
},
],
onFilter: (value: number, record: any) => record.status === value,
render: (text: string, record: any, index: number) => {
return (
{Status[record.status]}
);
},
},
{
title: '操作',
key: 'action',
width: 120,
align: 'center' as const,
render: (text: string, record: any, index: number) => {
const isPc = !isPhone;
return (
editEnv(record, index)}>
enabledOrDisabledEnv(record, index)}>
{record.status === Status.已禁用 ? (
) : (
)}
deleteEnv(record, index)}>
);
},
},
];
const [value, setValue] = useState([]);
const [loading, setLoading] = useState(true);
const [isModalVisible, setIsModalVisible] = useState(false);
const [isEditNameModalVisible, setIsEditNameModalVisible] = useState(false);
const [editedEnv, setEditedEnv] = useState();
const [selectedRowIds, setSelectedRowIds] = useState([]);
const [searchText, setSearchText] = useState('');
const [tableScrollHeight, setTableScrollHeight] = useState();
const getEnvs = () => {
setLoading(true);
request
.get(`${config.apiPrefix}envs?searchValue=${searchText}`)
.then((data: any) => {
setValue(data.data);
})
.finally(() => setLoading(false));
};
const enabledOrDisabledEnv = (record: any, index: number) => {
Modal.confirm({
title: `确认${record.status === Status.已禁用 ? '启用' : '禁用'}`,
content: (
<>
确认{record.status === Status.已禁用 ? '启用' : '禁用'}
Env{' '}
{record.value}
{' '}
吗
>
),
onOk() {
request
.put(
`${config.apiPrefix}envs/${
record.status === Status.已禁用 ? 'enable' : 'disable'
}`,
{
data: [record.id],
},
)
.then((data: any) => {
if (data.code === 200) {
message.success(
`${record.status === Status.已禁用 ? '启用' : '禁用'}成功`,
);
const newStatus =
record.status === Status.已禁用 ? Status.已启用 : Status.已禁用;
const result = [...value];
result.splice(index, 1, {
...record,
status: newStatus,
});
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const addEnv = () => {
setEditedEnv(null as any);
setIsModalVisible(true);
};
const editEnv = (record: any, index: number) => {
setEditedEnv(record);
setIsModalVisible(true);
};
const deleteEnv = (record: any, index: number) => {
Modal.confirm({
title: '确认删除',
content: (
<>
确认删除变量{' '}
{record.name}: {record.value}
{' '}
吗
>
),
onOk() {
request
.delete(`${config.apiPrefix}envs`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
message.success('删除成功');
const result = [...value];
result.splice(index, 1);
setValue(result);
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const handleCancel = (env?: any[]) => {
setIsModalVisible(false);
env && handleEnv(env);
};
const handleEditNameCancel = (env?: any[]) => {
setIsEditNameModalVisible(false);
getEnvs();
};
const handleEnv = (env: any) => {
const result = [...value];
const index = value.findIndex((x) => x.id === env.id);
if (index === -1) {
env = Array.isArray(env) ? env : [env];
result.push(...env);
} else {
result.splice(index, 1, {
...env,
});
}
setValue(result);
};
const components = {
body: {
row: DragableBodyRow,
},
};
const moveRow = useCallback(
(dragIndex, hoverIndex) => {
if (dragIndex === hoverIndex) {
return;
}
const dragRow = value[dragIndex];
request
.put(`${config.apiPrefix}envs/${dragRow.id}/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex },
})
.then((data: any) => {
if (data.code === 200) {
const newData = [...value];
newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, { ...dragRow, ...data.data });
setValue([...newData]);
} else {
message.error(data);
}
});
},
[value],
);
const onSelectChange = (selectedIds: any[]) => {
setSelectedRowIds(selectedIds);
setTimeout(() => {
if (selectedRowIds.length === 0 || selectedIds.length === 0) {
setTableScrollHeight(getTableScroll({ extraHeight: 87 }));
}
});
};
const rowSelection = {
selectedRowIds,
onChange: onSelectChange,
};
const delEnvs = () => {
Modal.confirm({
title: '确认删除',
content: <>确认删除选中的变量吗>,
onOk() {
request
.delete(`${config.apiPrefix}envs`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
message.success('批量删除成功');
setSelectedRowIds([]);
getEnvs();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const operateEnvs = (operationStatus: number) => {
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>确认{OperationName[operationStatus]}选中的变量吗>,
onOk() {
request
.put(`${config.apiPrefix}envs/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
getEnvs();
} else {
message.error(data);
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const [importForm] = Form.useForm();
const operateImport = () => {
const importList: Array = [
// {
// index: 1,
// name: '',
// icon: '',
// color: ''
// }
];
let importRes: any;
const insertOneEnv = async (values: any) => {
const { value, split, name, remarks } = values;
const method = 'post';
let payload;
if (split === '1') {
const symbol = value.includes('&') ? '&' : '\n';
payload = value.split(symbol).map((x: any) => {
return {
name: name,
value: x,
remarks: remarks,
};
});
} else {
payload = [{ value, name, remarks }];
}
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
data: payload,
});
return { code, data };
};
const submitImport = async (value: string) => {
let now_at: any = '';
try {
setLoading(true);
const dataList = JSON.parse(value); // 是一个数组
for (const [index, item] of dataList.entries()) {
importList.push({
index: index,
name: item.name,
icon: ,
color: 'default',
text: '等待中',
});
}
for (const [index, item] of dataList.entries()) {
Object.assign(importList[index], {
icon: ,
color: 'processing',
text: '进行中',
});
now_at = importList[index];
const { code = 0 } = await insertOneEnv(item);
if (code === 200) {
Object.assign(importList[index], {
icon: ,
color: 'success',
text: '成功',
});
} else {
Object.assign(importList[index], {
icon: ,
color: 'error',
text: '失败',
});
}
}
importRes = importList.map((one) => {
return (
第${one.index + 1}个变量 - ${one.name}{' '}
更新成功
);
});
const count_success = importList.filter(
(one) => one.color === 'success',
).length;
const count_failed = importList.filter(
(one) => one.color === 'error',
).length;
notification.success({
message: '导入完成',
description: `成功导入${count_success}个,失败${count_failed}个`,
});
return true;
} catch (e) {
if (e.message.includes('JSON')) {
message.error('数据格式有问题,请检查并更正json格式');
} else {
message.error(
`导入第 ${now_at.index + 1} 个数据 ${
now_at.name
} 失败,请检查是否存在相同变量`,
);
console.log(e);
}
} finally {
setLoading(false);
}
return false;
};
Modal.confirm({
title: `环境变量配置数据-导入-请手动粘贴`,
okText: '导入',
content: (
),
async onOk() {
const values = await importForm.validateFields();
const { envs }: { envs: string } = values;
const isOk = await submitImport(envs);
if (isOk) {
setTimeout(() => {
location.reload();
}, 1000);
return Promise.resolve();
}
return Promise.reject('');
},
onCancel() {
importForm.resetFields();
},
});
};
const operateExport = () => {
const result = [...value];
const selectItems = result
.filter((one) => selectedRowIds.includes(one.id))
.map((one) => {
return {
name: one.name,
value: one.value,
split: one.split,
remarks: one.remarks,
};
});
const resJson = JSON.stringify(selectItems, function (key: any, val: any) {
console.log(val);
if (val) return val;
});
Modal.confirm({
title: `环境变量配置数据-导出-请手动复制`,
content: (
),
onOk() {
console.log('Ok');
},
onCancel() {
console.log('Cancel');
},
});
};
const modifyName = () => {
setIsEditNameModalVisible(true);
};
const onSearch = (value: string) => {
setSearchText(value.trim());
};
useEffect(() => {
getEnvs();
}, [searchText]);
useEffect(() => {
setTimeout(() => {
setTableScrollHeight(getTableScroll({ extraHeight: 87 }));
});
}, []);
return (
,
,
]}
header={{
style: headerStyle,
}}
>
{selectedRowIds.length > 0 && (
已选择
{selectedRowIds?.length}项
)}
{
return {
index,
moveRow,
} as any;
}}
/>
);
};
export default Env;