import React, { useEffect, useState } from 'react'; import { Card, Button, Table, Space, Modal, Popconfirm, notification, Spin, Pagination, Checkbox, } from 'antd'; import copy from 'copy-to-clipboard'; import PageContainer from '@/components/BasePageContainer'; import { CheckSquareFilled, ConsoleSqlOutlined } from '@ant-design/icons'; import styles from './ManagementDataBase.less'; import { tableCheck, tableCheckNew, newUpdateDateBase, updateDateBase, databaseStandardGetLog, databaseStandardGetLogNew, } from '@/services/database/api'; const ManagementDataBase = () => { const [autoCheckList, setAutoCheckList] = useState([]); // 自动列表 const [autoCheck, setAutoCheck] = useState([]); const [checkList, setCheckList] = useState([]); // 手动列表 const [logList, setLogList] = useState([]); // 日志列表 const [checkFlag, setCheckFlag] = useState(1); const [upFlag, setUpFlag] = useState(1); // const [checkLoading, setCheckLoading] = useState(false); // 按钮loading const [logLoading, setLogLoading] = useState(false); const [modalVisible, setModalVisible] = useState(false); // 弹窗 const [content, setContent] = useState(null); const [modalTitle, setModalTitle] = useState('详细信息'); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [checkSql, setCheckSql] = useState(''); const [sqlVisible, setSqlVisible] = useState(false); const [repairTypeList, setRepairTypeList] = useState([]); const [list, setlist] = useState(['表', '字段', '主外键', '主键', '索引', '复合索引']); const [selectedRowKeys, setSelectedRowKeys] = useState([]); // 保存已选自动升级表键值 const [keepCheckList, setKeepChecklist] = useState([]); // 保存已选自动升级表值 const [keepData, setKeepData] = useState([]); // 保存分类数组 const [allchecked, setAllChecked] = useState(true); const [indeterminateAll, setIndeterminateAll] = useState(false); const [typeFilters, setTypeFilters] = useState([]); // type列筛选 const [filteredValue, setFilteredValue] = useState([]); // 检查数据库表 useEffect(() => { setCheckLoading(true); // tableCheck({ // _version: 9999, // _dc: new Date().getTime(), // }) // .then(res => { // setCheckLoading(false); // console.log(res); // if (res.sucess) { // const { list, messageList } = res; // // 自动检测列表 // let arr = list.map((item, index) => { // item.key = index; // return item; // }); // // 手动检查列表 // let arr2 = messageList.map((item, index) => { // item.key = index; // return item; // }); // setAutoCheckList(arr); // setCheckList(arr2); // } // }) // .catch(err => { // setCheckLoading(false); // console.error(err); // }); tableCheckNew() .then(resnew => { setCheckLoading(false); if (resnew.code == 0) { let res = resnew.data; const { Autolist, ManualList } = res; // 自动检测列表 let arr = Autolist.map((item, index) => { item.key = index; return item; }); // 手动检查列表 let arr2 = ManualList.map((item, index) => { item.key = index; return item; }); let data = []; list.map(i => { if (res.RepairTypeList.indexOf(i) != -1) { data.push(i); } }); console.log(arr); // 所有数据 let qq = arr.map(item => item.Type); qq = qq.filter((value, index) => qq.indexOf(value) === index); console.log(qq); console.log(qq.map(item => ({ text: item, value: item }))); setTypeFilters(qq.map(item => ({ text: item, value: item }))); let datalist = []; if (arr.length > 0) { arr.map(i => { datalist.push(i.key); }); } console.log(datalist); // 所有数据的key setKeepData(data); console.log(data); // 分类数组 let aa = []; if (data.length > 0) { data.map(i => { let vv = []; let ff = []; // key arr.map(j => { if (j.Type == i) { vv.push(j); ff.push(j.key); } }); let a = {}; a.name = i; a.checked = true; a.indeterminate = false; a.value = vv; a.key = ff; aa.push(a); }); } console.log(aa); setRepairTypeList(aa); setAutoCheck(arr); setAutoCheckList(arr); setCheckList(arr2); setAllChecked(true); setIndeterminateAll(false); } }) .catch(err => { setCheckLoading(false); console.error(err); }); }, [checkFlag]); // 获取数据库升级记录 useEffect(() => { setLogLoading(true); // databaseStandardGetLog({ // _version: 9999, // _dc: new Date().getTime(), // }) // .then(res => { // setLogLoading(false); // if (res) { // let arr = []; // res.map((item, index) => { // item.key = index; // arr.push(item); // }); // setLogList(res); // } // }) // .catch(err => { // setLogLoading(false); // console.error(err); // }); databaseStandardGetLogNew() .then(resnew => { setLogLoading(false); if (resnew.code == 0) { let res = resnew.data.list; let arr = []; res.map((item, index) => { item.key = index; arr.push(item); }); setLogList(res); } }) .catch(err => { setLogLoading(false); console.error(err); }); }, [upFlag]); // 检查功能 const handleCheck = () => { setCheckFlag(checkFlag + 1); setFilteredValue([]); }; // 升级功能 const handleUpdate = () => { console.log(keepCheckList); console.log(selectedRowKeys); if (repairTypeList.length > 0) { if (keepCheckList.length > 0) { setCheckLoading(true); newUpdateDateBase(keepCheckList) .then(res => { setCheckLoading(false); setCheckFlag(checkFlag + 1); setUpFlag(upFlag + 1); if (res.code === 0) { setKeepChecklist([]); setSelectedRowKeys([]); setFilteredValue([]); notification.success({ message: '通知', duration: 3, description: '修复成功', }); } else { notification.error({ message: '通知', duration: 15, description: res.msg, }); } }) .catch(err => { setCheckLoading(false); console.error(err); }); } else { notification.error({ message: '提示', duration: 3, description: '请勾选升级列表', }); } } else { setCheckLoading(true); updateDateBase() .then(res => { setCheckLoading(false); setCheckFlag(checkFlag + 1); setUpFlag(upFlag + 1); if (res.code === 0) { setFilteredValue([]); notification.success({ message: '通知', duration: 3, description: '修复成功', }); } else { notification.error({ message: '通知', duration: 15, description: res.msg, }); } }) .catch(err => { setCheckLoading(false); console.error(err); }); } }; const handleErrLog = (text, val) => { setModalTitle(val); let arr = []; arr.push(text.split(/(\r\n)|(\n)/).map((item, index) => <p key={index}>{item}</p>)); setModalVisible(true); // setContent(text); setContent(arr); }; const handleLog = (text, val) => { setModalTitle(val); let arr = []; arr.push( text .split(/(\r\n)|(\n)/) .map((item, index) => <p key={index} dangerouslySetInnerHTML={{ __html: item }} />), ); setModalVisible(true); // setContent(text); setContent(arr); }; // 复制SQL const copySql = text => { if (copy(text)) { notification.success({ message: '提示', duration: 3, description: '复制成功', }); } else { notification.error({ message: '提示', duration: 3, description: '复制失败', }); } }; const autoCheckColumns = [ { title: '表名称', dataIndex: 'TableName', key: 'TableName', width: 200, ellipsis: true, }, { title: '类型', dataIndex: 'Type', key: 'Type', width: 180, ellipsis: true, filters: typeFilters, onFilter: (value, record) => record.Type === value, filteredValue, }, { title: '差异比较', dataIndex: 'Message', key: 'message', }, ]; const checkColumns = [ { title: '表名称', dataIndex: 'TableName', key: 'TableName', width: 200, ellipsis: true, }, { title: '差异比较', dataIndex: 'Message', key: 'Message', width: 400, ellipsis: true, }, { title: 'SQL语句', dataIndex: 'DiffSql', key: 'DiffSql', render: (text, record) => ( <Button size="small" type="primary" onClick={() => { // copySql(text); check(record); setSqlVisible(true); }} > 查看SQL </Button> ), }, ]; const logColumns = [ { title: '登录名', dataIndex: 'UpdateBy', key: 'UpdateBy', width: 200, ellipsis: true, }, { title: '数据库名称', dataIndex: 'Name', key: 'Name', width: 200, ellipsis: true, }, { title: '解决方案', dataIndex: 'DbProductName', key: 'DbProductName', width: 200, ellipsis: true, }, // { // title: '数据库版本', // dataIndex: 'Version', // key: 'Version', // width: 200, // ellipsis: true, // }, { title: '升级时间', dataIndex: 'UpdateTime', key: 'UpdateTime', width: 200, ellipsis: true, }, // { // title: '版本日志', // dataIndex: 'Oklog', // key: 'Oklog', // render: text => ( // <Button // size="small" // disabled={!text} // onClick={() => { // handleLog(text, '版本日志'); // }} // > // 日志 // </Button> // ), // }, { title: '成功日志', dataIndex: 'Oklog', key: 'Oklog', ellipsis: true, render: text => ( <Button size="small" type="primary" onClick={() => { handleLog(text, '详细信息'); }} > 升级内容 </Button> ), }, { title: '错误日志', dataIndex: 'Errlog', key: 'Errlog', ellipsis: true, render: text => { if (text && text.length > 0) { return ( <Button size="small" type="primary" onClick={() => { handleLog(text, '详细信息'); }} style={{ backgroundColor: 'red' }} > 错误内容 </Button> ); } }, }, ]; const paginationChange = (page, pageSizes) => { console.log(page); console.log(pageSizes); setCurrentPage(page); setPageSize(pageSizes); }; const check = e => { setCheckSql(e); }; // 复选框 const rowSelection = { selectedRowKeys, // columnTitle: ' ', // hideDefaultSelections: true, onChange: (RowKeys, Rows) => { // 找到勾选/取消勾选项的Type let aa = []; // 取消 if (keepCheckList.length > Rows.length) { keepCheckList.map(i => { if (Rows.indexOf(i) == -1) { aa.push(i.Type); } }); } // 勾选 if (keepCheckList.length < Rows.length) { Rows.map(i => { if (keepCheckList.indexOf(i) == -1) { aa.push(i.Type); } }); } // 找到勾选/取消勾选项的下标 let index = []; repairTypeList.map((j, k) => { if (j.name == aa[0]) { index.push(k); } }); // 全部勾选数据按照type分类存储 let list11 = []; if (keepData.length > 0) { keepData.map(i => { let vv = []; Rows.map(j => { if (j.Type == i) { vv.push(j); } }); list11.push(vv); }); } // 控制分组全选 if ( list11[index[0]].length < repairTypeList[index[0]].value.length && list11[index[0]].length !== 0 ) { repairTypeList[index[0]].indeterminate = true; repairTypeList[index[0]].checked = false; } else if (list11[index[0]].length === 0) { repairTypeList[index[0]].indeterminate = false; repairTypeList[index[0]].checked = false; } else if (list11[index[0]].length === repairTypeList[index[0]].value.length) { repairTypeList[index[0]].indeterminate = false; repairTypeList[index[0]].checked = true; } // 控制全选 if (RowKeys.length < autoCheckList.length && RowKeys.length !== 0) { setAllChecked(false); setIndeterminateAll(true); } else if (RowKeys.length === 0) { setAllChecked(false); setIndeterminateAll(false); } else if (RowKeys.length === autoCheckList.length) { setAllChecked(true); setIndeterminateAll(false); } setSelectedRowKeys(RowKeys); setKeepChecklist(Rows); }, }; // 分类全选 const onChangeAll = (e, j) => { let data1 = [...repairTypeList]; data1[j].checked = e.target.checked; data1[j].indeterminate = false; setRepairTypeList(data1); if (e.target.checked) { let aa = [...keepCheckList]; let bb = [...selectedRowKeys]; let data = [...new Set(aa.concat(data1[j].value))]; let data2 = [...new Set(bb.concat(data1[j].key))]; // 控制全选 if (data.length < autoCheckList.length && data.length !== 0) { setAllChecked(false); setIndeterminateAll(true); } else if (data.length === 0) { setAllChecked(false); setIndeterminateAll(false); } else if (data.length === autoCheckList.length) { setAllChecked(true); setIndeterminateAll(false); } setKeepChecklist(data); setSelectedRowKeys(data2); } else { let aa = []; // 全部已选数据 let bb = []; // 全部已选数据key keepCheckList.map(i => { if (data1[j].value.indexOf(i) == -1) { aa.push(i); bb.push(i.key); } }); // 控制全选 if (aa.length < autoCheckList.length && aa.length !== 0) { setAllChecked(false); setIndeterminateAll(true); } else if (aa.length === 0) { setAllChecked(false); setIndeterminateAll(false); } else if (aa.length === autoCheckList.length) { setAllChecked(true); setIndeterminateAll(false); } setKeepChecklist(aa); setSelectedRowKeys(bb); } }; // 全选 const onChange1 = e => { setAllChecked(e.target.checked); setIndeterminateAll(false); if (e.target.checked) { let aa = [...repairTypeList]; aa.map(i => { i.checked = true; i.indeterminate = false; }); setKeepChecklist(autoCheckList); let bb = []; autoCheckList.map(i => { bb.push(i.key); }); setSelectedRowKeys(bb); } else { let aa = [...repairTypeList]; aa.map(i => { i.checked = false; i.indeterminate = false; }); setKeepChecklist([]); setSelectedRowKeys([]); } }; const onChangeInput = filters => { console.log('filters', filters); setFilteredValue(filters.Type); }; return ( <> <PageContainer> <Card> <div className={styles.tableTitle}> <div style={{ display: 'inline-block' }}> <span style={{ marginRight: '100px' }}>升级详情</span> {/* {repairTypeList.length > 0 && ( <> <Checkbox checked={allchecked} onChange={onChange1} indeterminate={indeterminateAll} > 全选 </Checkbox> <div style={{ display: 'inline-block', marginLeft: '10px' }}> {repairTypeList.map((i, j) => ( <Checkbox checked={i.checked} onChange={e => onChangeAll(e, j)} indeterminate={i.indeterminate} > {i.name} </Checkbox> ))} </div> </> )} */} </div> <div style={{ display: 'inline-block' }}> <strong> (已选 <span style={{ color: 'rgb(24, 144, 255)' }}>{keepCheckList.length}</span>/共 {autoCheckList.length}条) </strong> </div> </div> <Spin tip="loading..." spinning={checkLoading}> <Table rowSelection={{ type: 'checkbox', ...rowSelection, }} className={styles.mgTop20} columns={autoCheckColumns} hideSelectAll dataSource={autoCheckList} bordered size="small" scroll={{ y: '390px', }} pagination={false} onChange={onChangeInput} /> <div className={styles.btnBox}> <Space> <Button type="primary" onClick={handleCheck}> 检查 </Button> <Popconfirm title={ <span> 已选 <span style={{ color: 'rgb(24, 144, 255)' }}>{keepCheckList.length}</span>/ {autoCheckList.length} 条数据,是否根据已选数据,升级当前连接数据库? </span> } okText="确认" cancelText="取消" onConfirm={() => { handleUpdate(); }} > <Button danger type="primary"> 升级 </Button> </Popconfirm> </Space> </div> </Spin> </Card> <Card className={styles.mgTop20}> <div className={styles.tableTitle}> 手动升级 (字段长度不统一,请手动修改差异,数据可能会截断,请谨慎操作) </div> <Table className={styles.mgTop20} columns={checkColumns} dataSource={checkList} bordered loading={checkLoading} size="small" /> </Card> <Card className={styles.mgTop20}> <div className={styles.tableTitle}>数据库版本记录</div> <Table className={styles.mgTop20} columns={logColumns} dataSource={logList} bordered loading={logLoading} size="small" /> </Card> </PageContainer> <Modal title={modalTitle} visible={modalVisible} keyboard={false} maskClosable centered onOk={() => setModalVisible(false)} onCancel={() => setModalVisible(false)} width="1000px" bodyStyle={{ minHeight: '100px', maxHeight: '600px', overflowY: 'scroll', }} style={{ top: '40px' }} footer={[ <Button type="primary" onClick={() => setModalVisible(false)} key="back"> 关闭窗口 </Button>, ]} > {content} </Modal> <Modal title={checkSql.TableName} visible={sqlVisible} maskClosable centered onOk={() => setSqlVisible(false)} onCancel={() => setSqlVisible(false)} width="500px" bodyStyle={{ minHeight: '100px', overflowY: 'scroll', }} footer={[ <Button type="primary" onClick={() => copySql(checkSql.DiffSql)}> 复制SQL </Button>, <Button type="primary" onClick={() => setSqlVisible(false)} key="back"> 关闭窗口 </Button>, ]} > {checkSql.DiffSql} </Modal> </> ); }; export default ManagementDataBase;